about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-02-12 00:22:29 -0500
committerRich Felker <dalias@aerifal.cx>2011-02-12 00:22:29 -0500
commit0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 (patch)
tree6eaef0d8a720fa3da580de87b647fff796fe80b3 /src
downloadmusl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.gz
musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.xz
musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.zip
initial check-in, version 0.5.0 v0.5.0
Diffstat (limited to 'src')
-rw-r--r--src/conf/fpathconf.c35
-rw-r--r--src/conf/pathconf.c6
-rw-r--r--src/conf/sysconf.c222
-rw-r--r--src/ctype/__ctype_get_mb_cur_max.c6
-rw-r--r--src/ctype/isalnum.c6
-rw-r--r--src/ctype/isalpha.c7
-rw-r--r--src/ctype/isascii.c6
-rw-r--r--src/ctype/isblank.c6
-rw-r--r--src/ctype/iscntrl.c6
-rw-r--r--src/ctype/isdigit.c7
-rw-r--r--src/ctype/isgraph.c4
-rw-r--r--src/ctype/islower.c7
-rw-r--r--src/ctype/isprint.c4
-rw-r--r--src/ctype/ispunct.c6
-rw-r--r--src/ctype/isspace.c6
-rw-r--r--src/ctype/isupper.c7
-rw-r--r--src/ctype/iswalnum.c9
-rw-r--r--src/ctype/iswalpha.c6
-rw-r--r--src/ctype/iswblank.c8
-rw-r--r--src/ctype/iswcntrl.c10
-rw-r--r--src/ctype/iswctype.c63
-rw-r--r--src/ctype/iswdigit.c9
-rw-r--r--src/ctype/iswgraph.c7
-rw-r--r--src/ctype/iswlower.c6
-rw-r--r--src/ctype/iswprint.c10
-rw-r--r--src/ctype/iswpunct.c138
-rw-r--r--src/ctype/iswspace.c15
-rw-r--r--src/ctype/iswupper.c6
-rw-r--r--src/ctype/iswxdigit.c7
-rw-r--r--src/ctype/isxdigit.c6
-rw-r--r--src/ctype/toascii.c7
-rw-r--r--src/ctype/tolower.c7
-rw-r--r--src/ctype/toupper.c7
-rw-r--r--src/ctype/towctrans.c246
-rw-r--r--src/ctype/wcswidth.c8
-rw-r--r--src/ctype/wctrans.c16
-rw-r--r--src/ctype/wcwidth.c185
-rw-r--r--src/dirent/__dirent.h9
-rw-r--r--src/dirent/__getdents.c12
-rw-r--r--src/dirent/alphasort.c10
-rw-r--r--src/dirent/closedir.c11
-rw-r--r--src/dirent/dirfd.c7
-rw-r--r--src/dirent/fdopendir.c26
-rw-r--r--src/dirent/opendir.c25
-rw-r--r--src/dirent/readdir.c32
-rw-r--r--src/dirent/readdir_r.c30
-rw-r--r--src/dirent/rewinddir.c13
-rw-r--r--src/dirent/scandir.c50
-rw-r--r--src/dirent/seekdir.c12
-rw-r--r--src/dirent/telldir.c7
-rw-r--r--src/env/__environ.c7
-rw-r--r--src/env/__libc_start_main.c26
-rw-r--r--src/env/clearenv.c9
-rw-r--r--src/env/getenv.c14
-rw-r--r--src/env/putenv.c59
-rw-r--r--src/env/setenv.c31
-rw-r--r--src/env/unsetenv.c32
-rw-r--r--src/errno/__errno_location.c11
-rw-r--r--src/errno/__strerror.h101
-rw-r--r--src/errno/strerror.c22
-rw-r--r--src/exit/_Exit.c9
-rw-r--r--src/exit/abort.c8
-rw-r--r--src/exit/assert.c9
-rw-r--r--src/exit/atexit.c57
-rw-r--r--src/exit/exit.c28
-rw-r--r--src/fcntl/creat.c9
-rw-r--r--src/fcntl/fcntl.c22
-rw-r--r--src/fcntl/open.c21
-rw-r--r--src/fcntl/openat.c21
-rw-r--r--src/internal/atomic.h110
-rw-r--r--src/internal/clone.h22
-rw-r--r--src/internal/futex.h16
-rw-r--r--src/internal/libc.c3
-rw-r--r--src/internal/libc.h43
-rw-r--r--src/internal/locale_impl.h5
-rw-r--r--src/internal/pthread_impl.h68
-rw-r--r--src/internal/stdio_impl.h100
-rw-r--r--src/internal/syscall.c11
-rw-r--r--src/internal/syscall.h469
-rw-r--r--src/internal/util.h5
-rw-r--r--src/ipc/ftok.c10
-rw-r--r--src/ipc/ipc.h13
-rw-r--r--src/ipc/semctl.c18
-rw-r--r--src/ipc/semget.c12
-rw-r--r--src/ipc/semop.c12
-rw-r--r--src/ipc/shmat.c17
-rw-r--r--src/ipc/shmctl.c12
-rw-r--r--src/ipc/shmdt.c12
-rw-r--r--src/ipc/shmget.c12
-rw-r--r--src/linux/brk.c6
-rw-r--r--src/linux/chroot.c8
-rw-r--r--src/linux/daemon.c31
-rw-r--r--src/linux/epoll_create.c7
-rw-r--r--src/linux/epoll_create1.c7
-rw-r--r--src/linux/epoll_ctl.c7
-rw-r--r--src/linux/epoll_pwait.c7
-rw-r--r--src/linux/epoll_wait.c7
-rw-r--r--src/linux/getdtablesize.c9
-rw-r--r--src/linux/gethostid.c4
-rw-r--r--src/linux/getopt_long.c52
-rw-r--r--src/linux/getpagesize.c7
-rw-r--r--src/linux/getpass.c39
-rw-r--r--src/linux/initgroups.c15
-rw-r--r--src/linux/klogctl.c7
-rw-r--r--src/linux/mntent.c57
-rw-r--r--src/linux/mount.c8
-rw-r--r--src/linux/prctl.c13
-rw-r--r--src/linux/reboot.c8
-rw-r--r--src/linux/sbrk.c7
-rw-r--r--src/linux/sendfile.c10
-rw-r--r--src/linux/setgroups.c9
-rw-r--r--src/linux/sethostname.c8
-rw-r--r--src/linux/settimeofday.c7
-rw-r--r--src/linux/signalfd.c7
-rw-r--r--src/linux/stime.c7
-rw-r--r--src/linux/swapoff.c8
-rw-r--r--src/linux/swapon.c8
-rw-r--r--src/linux/sysinfo.c9
-rw-r--r--src/linux/umount.c8
-rw-r--r--src/linux/umount2.c8
-rw-r--r--src/linux/utimes.c13
-rw-r--r--src/linux/wait3.c11
-rw-r--r--src/linux/wait4.c19
-rw-r--r--src/locale/catclose.c6
-rw-r--r--src/locale/catgets.c6
-rw-r--r--src/locale/catopen.c6
-rw-r--r--src/locale/duplocale.c11
-rw-r--r--src/locale/freelocale.c7
-rw-r--r--src/locale/iconv.c568
-rw-r--r--src/locale/intl.c67
-rw-r--r--src/locale/isalnum_l.c6
-rw-r--r--src/locale/isalpha_l.c6
-rw-r--r--src/locale/isblank_l.c6
-rw-r--r--src/locale/iscntrl_l.c6
-rw-r--r--src/locale/isdigit_l.c6
-rw-r--r--src/locale/isgraph_l.c6
-rw-r--r--src/locale/islower_l.c6
-rw-r--r--src/locale/isprint_l.c6
-rw-r--r--src/locale/ispunct_l.c6
-rw-r--r--src/locale/isspace_l.c6
-rw-r--r--src/locale/isupper_l.c6
-rw-r--r--src/locale/isxdigit_l.c6
-rw-r--r--src/locale/langinfo.c58
-rw-r--r--src/locale/localeconv.c22
-rw-r--r--src/locale/newlocale.c11
-rw-r--r--src/locale/nl_langinfo.c13
-rw-r--r--src/locale/setlocale.c9
-rw-r--r--src/locale/strcoll.c6
-rw-r--r--src/locale/strxfrm.c9
-rw-r--r--src/locale/tmp390
-rw-r--r--src/locale/tolower_l.c6
-rw-r--r--src/locale/toupper_l.c6
-rw-r--r--src/locale/wcscoll.c7
-rw-r--r--src/locale/wcsxfrm.c12
-rw-r--r--src/malloc/DESIGN22
-rw-r--r--src/malloc/__brk.c7
-rw-r--r--src/malloc/__simple_malloc.c44
-rw-r--r--src/malloc/calloc.c23
-rw-r--r--src/malloc/malloc.c515
-rw-r--r--src/malloc/memalign.c13
-rw-r--r--src/malloc/posix_memalign.c47
-rw-r--r--src/math/__fpclassify.c14
-rw-r--r--src/math/__fpclassifyf.c14
-rw-r--r--src/math/__fpclassifyl.c16
-rw-r--r--src/math/e_acos.c99
-rw-r--r--src/math/e_acosf.c77
-rw-r--r--src/math/e_acosh.c59
-rw-r--r--src/math/e_acoshf.c45
-rw-r--r--src/math/e_asin.c109
-rw-r--r--src/math/e_asinf.c80
-rw-r--r--src/math/e_atan2.c120
-rw-r--r--src/math/e_atan2f.c93
-rw-r--r--src/math/e_atanh.c59
-rw-r--r--src/math/e_atanhf.c42
-rw-r--r--src/math/e_cosh.c82
-rw-r--r--src/math/e_coshf.c59
-rw-r--r--src/math/e_exp.c155
-rw-r--r--src/math/e_expf.c91
-rw-r--r--src/math/e_fmod.c129
-rw-r--r--src/math/e_fmodf.c101
-rw-r--r--src/math/e_hypot.c121
-rw-r--r--src/math/e_hypotf.c79
-rw-r--r--src/math/e_log.c131
-rw-r--r--src/math/e_log10.c83
-rw-r--r--src/math/e_log10f.c51
-rw-r--r--src/math/e_logf.c81
-rw-r--r--src/math/e_pow.c300
-rw-r--r--src/math/e_powf.c243
-rw-r--r--src/math/e_rem_pio2.c163
-rw-r--r--src/math/e_rem_pio2f.c175
-rw-r--r--src/math/e_remainder.c69
-rw-r--r--src/math/e_remainderf.c61
-rw-r--r--src/math/e_scalb.c35
-rw-r--r--src/math/e_scalbf.c31
-rw-r--r--src/math/e_sinh.c75
-rw-r--r--src/math/e_sinhf.c56
-rw-r--r--src/math/e_sqrt.c442
-rw-r--r--src/math/e_sqrtf.c85
-rw-r--r--src/math/i386/e_exp.s36
-rw-r--r--src/math/i386/e_expf.s1
-rw-r--r--src/math/i386/e_log.s6
-rw-r--r--src/math/i386/e_log10.s6
-rw-r--r--src/math/i386/e_log10f.s6
-rw-r--r--src/math/i386/e_logf.s6
-rw-r--r--src/math/i386/e_remainder.s16
-rw-r--r--src/math/i386/e_remainderf.s0
-rw-r--r--src/math/i386/e_sqrt.s4
-rw-r--r--src/math/i386/e_sqrtf.s4
-rw-r--r--src/math/i386/s_ceil.s0
-rw-r--r--src/math/i386/s_ceilf.s0
-rw-r--r--src/math/i386/s_fabs.s5
-rw-r--r--src/math/i386/s_fabsf.s5
-rw-r--r--src/math/i386/s_floor.s0
-rw-r--r--src/math/i386/s_floorf.s0
-rw-r--r--src/math/i386/s_ldexp.s0
-rw-r--r--src/math/i386/s_ldexpf.s0
-rw-r--r--src/math/i386/s_rint.s5
-rw-r--r--src/math/i386/s_rintf.s5
-rw-r--r--src/math/i386/s_scalbln.s11
-rw-r--r--src/math/i386/s_scalblnf.s11
-rw-r--r--src/math/i386/s_trunc.s36
-rw-r--r--src/math/i386/s_truncf.s0
-rw-r--r--src/math/k_cos.c85
-rw-r--r--src/math/k_cosf.c52
-rw-r--r--src/math/k_rem_pio2.c300
-rw-r--r--src/math/k_rem_pio2f.c192
-rw-r--r--src/math/k_sin.c68
-rw-r--r--src/math/k_sinf.c42
-rw-r--r--src/math/k_tan.c149
-rw-r--r--src/math/k_tanf.c105
-rw-r--r--src/math/math_private.h143
-rw-r--r--src/math/s_asinh.c53
-rw-r--r--src/math/s_asinhf.c45
-rw-r--r--src/math/s_atan.c115
-rw-r--r--src/math/s_atanf.c95
-rw-r--r--src/math/s_cbrt.c77
-rw-r--r--src/math/s_cbrtf.c67
-rw-r--r--src/math/s_ceil.c68
-rw-r--r--src/math/s_ceilf.c49
-rw-r--r--src/math/s_copysign.c30
-rw-r--r--src/math/s_copysignf.c33
-rw-r--r--src/math/s_cos.c74
-rw-r--r--src/math/s_cosf.c47
-rw-r--r--src/math/s_erf.c298
-rw-r--r--src/math/s_erff.c207
-rw-r--r--src/math/s_expm1.c217
-rw-r--r--src/math/s_expm1f.c122
-rw-r--r--src/math/s_fabs.c27
-rw-r--r--src/math/s_fabsf.c30
-rw-r--r--src/math/s_floor.c69
-rw-r--r--src/math/s_floorf.c58
-rw-r--r--src/math/s_ilogb.c45
-rw-r--r--src/math/s_ilogbf.c37
-rw-r--r--src/math/s_ldexp.c6
-rw-r--r--src/math/s_ldexpf.c6
-rw-r--r--src/math/s_llrint.c8
-rw-r--r--src/math/s_log1p.c157
-rw-r--r--src/math/s_log1pf.c96
-rw-r--r--src/math/s_logb.c34
-rw-r--r--src/math/s_logbf.c31
-rw-r--r--src/math/s_lrint.c8
-rw-r--r--src/math/s_lrintf.c8
-rw-r--r--src/math/s_modf.c71
-rw-r--r--src/math/s_modff.c52
-rw-r--r--src/math/s_nextafter.c72
-rw-r--r--src/math/s_nextafterf.c63
-rw-r--r--src/math/s_remquo.c149
-rw-r--r--src/math/s_remquof.c118
-rw-r--r--src/math/s_rint.c80
-rw-r--r--src/math/s_rintf.c45
-rw-r--r--src/math/s_round.c48
-rw-r--r--src/math/s_roundf.c48
-rw-r--r--src/math/s_scalbln.c61
-rw-r--r--src/math/s_scalblnf.c57
-rw-r--r--src/math/s_sin.c74
-rw-r--r--src/math/s_sinf.c45
-rw-r--r--src/math/s_tan.c68
-rw-r--r--src/math/s_tanf.c40
-rw-r--r--src/math/s_tanh.c74
-rw-r--r--src/math/s_tanhf.c52
-rw-r--r--src/math/s_trunc.c58
-rw-r--r--src/math/s_truncf.c50
-rw-r--r--src/misc/basename.c12
-rw-r--r--src/misc/bswap_32.c7
-rw-r--r--src/misc/bswap_64.c9
-rw-r--r--src/misc/crypt.c2578
-rw-r--r--src/misc/cuserid.c13
-rw-r--r--src/misc/dirname.c15
-rw-r--r--src/misc/ffs.c9
-rw-r--r--src/misc/ftw.c9
-rw-r--r--src/misc/getdomainname.c9
-rw-r--r--src/misc/getgrouplist.c11
-rw-r--r--src/misc/getopt.c63
-rw-r--r--src/misc/getpriority.c9
-rw-r--r--src/misc/getrlimit.c15
-rw-r--r--src/misc/getrusage.c20
-rw-r--r--src/misc/getsubopt.c23
-rw-r--r--src/misc/ioctl.c13
-rw-r--r--src/misc/lockf.c33
-rw-r--r--src/misc/nftw.c121
-rw-r--r--src/misc/openpty.c33
-rw-r--r--src/misc/pty.c35
-rw-r--r--src/misc/realpath.c6
-rw-r--r--src/misc/sched_yield.c10
-rw-r--r--src/misc/setpriority.c7
-rw-r--r--src/misc/setrlimit.c11
-rw-r--r--src/misc/syslog.c115
-rw-r--r--src/misc/uname.c8
-rw-r--r--src/mman/madvise.c10
-rw-r--r--src/mman/mlock.c7
-rw-r--r--src/mman/mlockall.c7
-rw-r--r--src/mman/mmap.c18
-rw-r--r--src/mman/mprotect.c7
-rw-r--r--src/mman/mremap.c19
-rw-r--r--src/mman/msync.c8
-rw-r--r--src/mman/munlock.c7
-rw-r--r--src/mman/munlockall.c7
-rw-r--r--src/mman/munmap.c11
-rw-r--r--src/mman/posix_madvise.c6
-rw-r--r--src/multibyte/btowc.c7
-rw-r--r--src/multibyte/decode.c47
-rw-r--r--src/multibyte/internal.c60
-rw-r--r--src/multibyte/internal.h61
-rw-r--r--src/multibyte/mblen.c17
-rw-r--r--src/multibyte/mbrlen.c18
-rw-r--r--src/multibyte/mbrtowc.c58
-rw-r--r--src/multibyte/mbsinit.c17
-rw-r--r--src/multibyte/mbsnrtowcs.c61
-rw-r--r--src/multibyte/mbsrtowcs.c121
-rw-r--r--src/multibyte/mbstowcs.c18
-rw-r--r--src/multibyte/mbtowc.c19
-rw-r--r--src/multibyte/wcrtomb.c38
-rw-r--r--src/multibyte/wcsnrtombs.c51
-rw-r--r--src/multibyte/wcsrtombs.c58
-rw-r--r--src/multibyte/wcstombs.c17
-rw-r--r--src/multibyte/wctob.c8
-rw-r--r--src/multibyte/wctomb.c18
-rw-r--r--src/network/__dns.c267
-rw-r--r--src/network/__dns.h14
-rw-r--r--src/network/__ipparse.c40
-rw-r--r--src/network/accept.c14
-rw-r--r--src/network/bind.c9
-rw-r--r--src/network/connect.c14
-rw-r--r--src/network/dn_expand.c28
-rw-r--r--src/network/ent.c26
-rw-r--r--src/network/freeaddrinfo.c7
-rw-r--r--src/network/gai_strerror.c21
-rw-r--r--src/network/getaddrinfo.c224
-rw-r--r--src/network/gethostbyaddr.c15
-rw-r--r--src/network/gethostbyaddr_r.c71
-rw-r--r--src/network/gethostbyname.c63
-rw-r--r--src/network/gethostbyname2.c16
-rw-r--r--src/network/gethostbyname2_r.c99
-rw-r--r--src/network/gethostbyname_r.c11
-rw-r--r--src/network/getnameinfo.c54
-rw-r--r--src/network/getpeername.c9
-rw-r--r--src/network/getservbyname.c12
-rw-r--r--src/network/getservbyname_r.c41
-rw-r--r--src/network/getservbyport.c12
-rw-r--r--src/network/getservbyport_r.c43
-rw-r--r--src/network/getsockname.c9
-rw-r--r--src/network/getsockopt.c13
-rw-r--r--src/network/h_errno.c1
-rw-r--r--src/network/hstrerror.c16
-rw-r--r--src/network/htonl.c10
-rw-r--r--src/network/htons.c10
-rw-r--r--src/network/in6addr_any.c3
-rw-r--r--src/network/in6addr_loopback.c3
-rw-r--r--src/network/inet_addr.c11
-rw-r--r--src/network/inet_aton.c7
-rw-r--r--src/network/inet_ntoa.c10
-rw-r--r--src/network/inet_ntop.c48
-rw-r--r--src/network/inet_pton.c31
-rw-r--r--src/network/listen.c9
-rw-r--r--src/network/ntohl.c10
-rw-r--r--src/network/ntohs.c10
-rw-r--r--src/network/proto.c58
-rw-r--r--src/network/recv.c14
-rw-r--r--src/network/recvfrom.c17
-rw-r--r--src/network/recvmsg.c14
-rw-r--r--src/network/res_init.c4
-rw-r--r--src/network/res_query.c20
-rw-r--r--src/network/send.c14
-rw-r--r--src/network/sendmsg.c14
-rw-r--r--src/network/sendto.c17
-rw-r--r--src/network/serv.c16
-rw-r--r--src/network/setsockopt.c9
-rw-r--r--src/network/shutdown.c9
-rw-r--r--src/network/sockatmark.c11
-rw-r--r--src/network/socket.c9
-rw-r--r--src/network/socketcall.h24
-rw-r--r--src/network/socketpair.c9
-rw-r--r--src/passwd/getgr_r.c53
-rw-r--r--src/passwd/getgrent.c39
-rw-r--r--src/passwd/getgrent_a.c46
-rw-r--r--src/passwd/getpw_r.c46
-rw-r--r--src/passwd/getpwent.c39
-rw-r--r--src/passwd/getpwent_a.c37
-rw-r--r--src/passwd/getspent.c14
-rw-r--r--src/passwd/getspnam.c17
-rw-r--r--src/passwd/getspnam_r.c89
-rw-r--r--src/passwd/lckpwdf.c11
-rw-r--r--src/passwd/pwf.h13
-rw-r--r--src/prng/__rand48_step.c14
-rw-r--r--src/prng/__seed48.c1
-rw-r--r--src/prng/drand48.c19
-rw-r--r--src/prng/lcong48.c9
-rw-r--r--src/prng/lrand48.c15
-rw-r--r--src/prng/mrand48.c15
-rw-r--r--src/prng/rand.c13
-rw-r--r--src/prng/rand_r.c6
-rw-r--r--src/prng/random.c8
-rw-r--r--src/prng/seed48.c12
-rw-r--r--src/prng/srand48.c6
-rw-r--r--src/prng/srandom.c8
-rw-r--r--src/process/execl.c20
-rw-r--r--src/process/execle.c22
-rw-r--r--src/process/execlp.c20
-rw-r--r--src/process/execv.c8
-rw-r--r--src/process/execve.c8
-rw-r--r--src/process/execvp.c34
-rw-r--r--src/process/fork.c9
-rw-r--r--src/process/system.c45
-rw-r--r--src/process/vfork.c8
-rw-r--r--src/process/wait.c6
-rw-r--r--src/process/waitid.c7
-rw-r--r--src/process/waitpid.c7
-rw-r--r--src/regex/fnmatch.c150
-rw-r--r--src/regex/glob.c238
-rw-r--r--src/regex/regcomp.c3362
-rw-r--r--src/regex/regerror.c75
-rw-r--r--src/regex/regexec.c1107
-rw-r--r--src/regex/tre-mem.c163
-rw-r--r--src/regex/tre.h269
-rw-r--r--src/select/poll.c12
-rw-r--r--src/select/pselect.c15
-rw-r--r--src/select/select.c12
-rw-r--r--src/setjmp/i386/longjmp.s22
-rw-r--r--src/setjmp/i386/setjmp.s23
-rw-r--r--src/setjmp/longjmp.c0
-rw-r--r--src/setjmp/setjmp.c0
-rw-r--r--src/signal/bsd_signal.c6
-rw-r--r--src/signal/getitimer.c12
-rw-r--r--src/signal/i386/sigsetjmp.s13
-rw-r--r--src/signal/kill.c7
-rw-r--r--src/signal/killpg.c11
-rw-r--r--src/signal/raise.c7
-rw-r--r--src/signal/setitimer.c15
-rw-r--r--src/signal/sigaction.c48
-rw-r--r--src/signal/sigaddset.c13
-rw-r--r--src/signal/sigaltstack.c8
-rw-r--r--src/signal/sigdelset.c13
-rw-r--r--src/signal/sigemptyset.c8
-rw-r--r--src/signal/sigfillset.c8
-rw-r--r--src/signal/sighold.c11
-rw-r--r--src/signal/sigignore.c12
-rw-r--r--src/signal/siginterrupt.c13
-rw-r--r--src/signal/sigismember.c12
-rw-r--r--src/signal/siglongjmp.c12
-rw-r--r--src/signal/signal.c13
-rw-r--r--src/signal/sigpause.c11
-rw-r--r--src/signal/sigpending.c7
-rw-r--r--src/signal/sigprocmask.c23
-rw-r--r--src/signal/sigqueue.c14
-rw-r--r--src/signal/sigrelse.c11
-rw-r--r--src/signal/sigrtmax.c4
-rw-r--r--src/signal/sigrtmin.c4
-rw-r--r--src/signal/sigset.c28
-rw-r--r--src/signal/sigsetjmp.c17
-rw-r--r--src/signal/sigsuspend.c7
-rw-r--r--src/signal/sigtimedwait.c12
-rw-r--r--src/signal/sigwait.c11
-rw-r--r--src/signal/sigwaitinfo.c7
-rw-r--r--src/stat/chmod.c7
-rw-r--r--src/stat/fchmod.c7
-rw-r--r--src/stat/fchmodat.c7
-rw-r--r--src/stat/fstat.c10
-rw-r--r--src/stat/fstatat.c10
-rw-r--r--src/stat/fstatvfs.c13
-rw-r--r--src/stat/lstat.c10
-rw-r--r--src/stat/mkdir.c7
-rw-r--r--src/stat/mkdirat.c7
-rw-r--r--src/stat/mkfifo.c6
-rw-r--r--src/stat/mkfifoat.c6
-rw-r--r--src/stat/mknod.c10
-rw-r--r--src/stat/mknodat.c7
-rw-r--r--src/stat/stat.c10
-rw-r--r--src/stat/statvfs.c13
-rw-r--r--src/stat/umask.c7
-rw-r--r--src/stdio/__fclose_ca.c6
-rw-r--r--src/stdio/__fdopen.c52
-rw-r--r--src/stdio/__fopen_rb_ca.c18
-rw-r--r--src/stdio/__fpending.c6
-rw-r--r--src/stdio/__ofl.c3
-rw-r--r--src/stdio/__overflow.c52
-rw-r--r--src/stdio/__scanf.c487
-rw-r--r--src/stdio/__scanf.h16
-rw-r--r--src/stdio/__stdio_close.c6
-rw-r--r--src/stdio/__stdio_read.c6
-rw-r--r--src/stdio/__stdio_seek.c15
-rw-r--r--src/stdio/__stdio_write.c9
-rw-r--r--src/stdio/__uflow.c7
-rw-r--r--src/stdio/__underflow.c38
-rw-r--r--src/stdio/asprintf.c14
-rw-r--r--src/stdio/clearerr.c10
-rw-r--r--src/stdio/dprintf.c12
-rw-r--r--src/stdio/fclose.c21
-rw-r--r--src/stdio/feof.c10
-rw-r--r--src/stdio/ferror.c10
-rw-r--r--src/stdio/fflush.c50
-rw-r--r--src/stdio/fgetc.c10
-rw-r--r--src/stdio/fgetpos.c11
-rw-r--r--src/stdio/fgets.c34
-rw-r--r--src/stdio/fgetwc.c51
-rw-r--r--src/stdio/fgetws.c27
-rw-r--r--src/stdio/fileno.c8
-rw-r--r--src/stdio/fmemopen.c16
-rw-r--r--src/stdio/fopen.c34
-rw-r--r--src/stdio/fprintf.c12
-rw-r--r--src/stdio/fputc.c10
-rw-r--r--src/stdio/fputs.c10
-rw-r--r--src/stdio/fputwc.c33
-rw-r--r--src/stdio/fputws.c23
-rw-r--r--src/stdio/fread.c49
-rw-r--r--src/stdio/freopen.c47
-rw-r--r--src/stdio/fscanf.c12
-rw-r--r--src/stdio/fseek.c38
-rw-r--r--src/stdio/fsetpos.c8
-rw-r--r--src/stdio/ftell.c35
-rw-r--r--src/stdio/fwide.c10
-rw-r--r--src/stdio/fwrite.c51
-rw-r--r--src/stdio/fwscanf.c13
-rw-r--r--src/stdio/getc.c6
-rw-r--r--src/stdio/getc_unlocked.c8
-rw-r--r--src/stdio/getchar.c6
-rw-r--r--src/stdio/getchar_unlocked.c6
-rw-r--r--src/stdio/getdelim.c59
-rw-r--r--src/stdio/getline.c6
-rw-r--r--src/stdio/gets.c8
-rw-r--r--src/stdio/getw.c7
-rw-r--r--src/stdio/getwc.c6
-rw-r--r--src/stdio/getwchar.c8
-rw-r--r--src/stdio/pclose.c10
-rw-r--r--src/stdio/perror.c27
-rw-r--r--src/stdio/popen.c43
-rw-r--r--src/stdio/printf.c12
-rw-r--r--src/stdio/putc.c8
-rw-r--r--src/stdio/putc_unlocked.c8
-rw-r--r--src/stdio/putchar.c6
-rw-r--r--src/stdio/putchar_unlocked.c7
-rw-r--r--src/stdio/puts.c6
-rw-r--r--src/stdio/putw.c6
-rw-r--r--src/stdio/putwc.c6
-rw-r--r--src/stdio/putwchar.c8
-rw-r--r--src/stdio/remove.c7
-rw-r--r--src/stdio/rename.c7
-rw-r--r--src/stdio/rewind.c6
-rw-r--r--src/stdio/scanf.c12
-rw-r--r--src/stdio/setbuf.c6
-rw-r--r--src/stdio/setvbuf.c22
-rw-r--r--src/stdio/snprintf.c13
-rw-r--r--src/stdio/sprintf.c12
-rw-r--r--src/stdio/sscanf.c12
-rw-r--r--src/stdio/stderr.c13
-rw-r--r--src/stdio/stdin.c13
-rw-r--r--src/stdio/stdout.c17
-rw-r--r--src/stdio/swscanf.c13
-rw-r--r--src/stdio/tempnam.c42
-rw-r--r--src/stdio/tmpfile.c23
-rw-r--r--src/stdio/tmpnam.c38
-rw-r--r--src/stdio/ungetc.c33
-rw-r--r--src/stdio/ungetwc.c45
-rw-r--r--src/stdio/vasprintf.c27
-rw-r--r--src/stdio/vdprintf.c14
-rw-r--r--src/stdio/vfprintf.c640
-rw-r--r--src/stdio/vfscanf.c43
-rw-r--r--src/stdio/vfwscanf.c28
-rw-r--r--src/stdio/vprintf.c6
-rw-r--r--src/stdio/vscanf.c7
-rw-r--r--src/stdio/vsnprintf.c33
-rw-r--r--src/stdio/vsprintf.c7
-rw-r--r--src/stdio/vsscanf.c21
-rw-r--r--src/stdio/vswscanf.c19
-rw-r--r--src/stdio/vwscanf.c8
-rw-r--r--src/stdio/wscanf.c13
-rw-r--r--src/stdlib/abs.c4
-rw-r--r--src/stdlib/atof.c6
-rw-r--r--src/stdlib/atoi.c15
-rw-r--r--src/stdlib/atol.c16
-rw-r--r--src/stdlib/atoll.c16
-rw-r--r--src/stdlib/bsearch.c20
-rw-r--r--src/stdlib/div.c6
-rw-r--r--src/stdlib/frexp.c23
-rw-r--r--src/stdlib/frexpf.c23
-rw-r--r--src/stdlib/frexpl.c25
-rw-r--r--src/stdlib/imaxabs.c6
-rw-r--r--src/stdlib/imaxdiv.c6
-rw-r--r--src/stdlib/labs.c4
-rw-r--r--src/stdlib/ldiv.c6
-rw-r--r--src/stdlib/llabs.c4
-rw-r--r--src/stdlib/lldiv.c6
-rw-r--r--src/stdlib/qsort.c50
-rw-r--r--src/stdlib/strtod.c6
-rw-r--r--src/stdlib/strtof.c6
-rw-r--r--src/stdlib/strtoimax.c25
-rw-r--r--src/stdlib/strtol.c17
-rw-r--r--src/stdlib/strtold.c93
-rw-r--r--src/stdlib/strtoll.c17
-rw-r--r--src/stdlib/strtoul.c14
-rw-r--r--src/stdlib/strtoull.c14
-rw-r--r--src/stdlib/strtoumax.c123
-rw-r--r--src/stdlib/wcstoimax.c24
-rw-r--r--src/stdlib/wcstol.c18
-rw-r--r--src/stdlib/wcstoll.c18
-rw-r--r--src/stdlib/wcstoul.c15
-rw-r--r--src/stdlib/wcstoull.c15
-rw-r--r--src/stdlib/wcstoumax.c47
-rw-r--r--src/string/bcmp.c7
-rw-r--r--src/string/bcopy.c7
-rw-r--r--src/string/bzero.c7
-rw-r--r--src/string/index.c7
-rw-r--r--src/string/memchr.c24
-rw-r--r--src/string/memcmp.c8
-rw-r--r--src/string/memcpy.c29
-rw-r--r--src/string/memmove.c14
-rw-r--r--src/string/mempcpy.c7
-rw-r--r--src/string/memset.c21
-rw-r--r--src/string/rindex.c7
-rw-r--r--src/string/stpcpy.c29
-rw-r--r--src/string/stpncpy.c32
-rw-r--r--src/string/strcasecmp.c9
-rw-r--r--src/string/strcasestr.c7
-rw-r--r--src/string/strcat.c7
-rw-r--r--src/string/strchr.c23
-rw-r--r--src/string/strchrnul.c7
-rw-r--r--src/string/strcmp.c7
-rw-r--r--src/string/strcpy.c16
-rw-r--r--src/string/strcspn.c20
-rw-r--r--src/string/strdup.c13
-rw-r--r--src/string/strerror_r.c11
-rw-r--r--src/string/strlcat.c8
-rw-r--r--src/string/strlcpy.c32
-rw-r--r--src/string/strlen.c21
-rw-r--r--src/string/strncasecmp.c10
-rw-r--r--src/string/strncat.c10
-rw-r--r--src/string/strncmp.c9
-rw-r--r--src/string/strncpy.c9
-rw-r--r--src/string/strndup.c12
-rw-r--r--src/string/strnlen.c7
-rw-r--r--src/string/strpbrk.c7
-rw-r--r--src/string/strrchr.c9
-rw-r--r--src/string/strsep.c12
-rw-r--r--src/string/strsignal.c98
-rw-r--r--src/string/strspn.c22
-rw-r--r--src/string/strstr.c166
-rw-r--r--src/string/strtok.c13
-rw-r--r--src/string/strtok_r.c12
-rw-r--r--src/string/swab.c13
-rw-r--r--src/string/wcscat.c7
-rw-r--r--src/string/wcschr.c8
-rw-r--r--src/string/wcscmp.c7
-rw-r--r--src/string/wcscpy.c8
-rw-r--r--src/string/wcscspn.c10
-rw-r--r--src/string/wcslen.c8
-rw-r--r--src/string/wcsncat.c10
-rw-r--r--src/string/wcsncmp.c7
-rw-r--r--src/string/wcsncpy.c9
-rw-r--r--src/string/wcspbrk.c7
-rw-r--r--src/string/wcsrchr.c8
-rw-r--r--src/string/wcsspn.c8
-rw-r--r--src/string/wcsstr.c117
-rw-r--r--src/string/wcswcs.c6
-rw-r--r--src/string/wmemchr.c8
-rw-r--r--src/string/wmemcmp.c8
-rw-r--r--src/string/wmemcpy.c9
-rw-r--r--src/string/wmemmove.c11
-rw-r--r--src/string/wmemset.c9
-rw-r--r--src/stub/utmpx.c30
-rw-r--r--src/temp/mkdtemp.c21
-rw-r--r--src/temp/mkstemp.c26
-rw-r--r--src/temp/mktemp.c29
-rw-r--r--src/termios/cfgetospeed.c12
-rw-r--r--src/termios/cfsetospeed.c22
-rw-r--r--src/termios/tcdrain.c7
-rw-r--r--src/termios/tcflow.c7
-rw-r--r--src/termios/tcflush.c7
-rw-r--r--src/termios/tcgetattr.c10
-rw-r--r--src/termios/tcgetsid.c10
-rw-r--r--src/termios/tcsendbreak.c8
-rw-r--r--src/termios/tcsetattr.c13
-rw-r--r--src/thread/__futex.c8
-rw-r--r--src/thread/__lock.c12
-rw-r--r--src/thread/__set_thread_area.c9
-rw-r--r--src/thread/__timedwait.c21
-rw-r--r--src/thread/__unmapself.c0
-rw-r--r--src/thread/__wait.c16
-rw-r--r--src/thread/__wake.c9
-rw-r--r--src/thread/cancellation.c22
-rw-r--r--src/thread/clone.c26
-rw-r--r--src/thread/i386/__unmapself.s22
-rw-r--r--src/thread/i386/clone.s35
-rw-r--r--src/thread/pthread_attr_destroy.c6
-rw-r--r--src/thread/pthread_attr_getdetachstate.c7
-rw-r--r--src/thread/pthread_attr_getguardsize.c7
-rw-r--r--src/thread/pthread_attr_getscope.c6
-rw-r--r--src/thread/pthread_attr_getstacksize.c7
-rw-r--r--src/thread/pthread_attr_init.c7
-rw-r--r--src/thread/pthread_attr_setdetachstate.c7
-rw-r--r--src/thread/pthread_attr_setguardsize.c8
-rw-r--r--src/thread/pthread_attr_setscope.c6
-rw-r--r--src/thread/pthread_attr_setstacksize.c8
-rw-r--r--src/thread/pthread_barrier_destroy.c6
-rw-r--r--src/thread/pthread_barrier_init.c8
-rw-r--r--src/thread/pthread_barrier_wait.c31
-rw-r--r--src/thread/pthread_cancel.c7
-rw-r--r--src/thread/pthread_cond_broadcast.c8
-rw-r--r--src/thread/pthread_cond_destroy.c6
-rw-r--r--src/thread/pthread_cond_init.c7
-rw-r--r--src/thread/pthread_cond_signal.c8
-rw-r--r--src/thread/pthread_cond_timedwait.c26
-rw-r--r--src/thread/pthread_cond_wait.c6
-rw-r--r--src/thread/pthread_create.c189
-rw-r--r--src/thread/pthread_detach.c11
-rw-r--r--src/thread/pthread_equal.c6
-rw-r--r--src/thread/pthread_exit.c25
-rw-r--r--src/thread/pthread_getspecific.c8
-rw-r--r--src/thread/pthread_join.c12
-rw-r--r--src/thread/pthread_key_create.c25
-rw-r--r--src/thread/pthread_key_delete.c7
-rw-r--r--src/thread/pthread_kill.c7
-rw-r--r--src/thread/pthread_mutex_destroy.c6
-rw-r--r--src/thread/pthread_mutex_init.c9
-rw-r--r--src/thread/pthread_mutex_lock.c9
-rw-r--r--src/thread/pthread_mutex_timedlock.c15
-rw-r--r--src/thread/pthread_mutex_trylock.c28
-rw-r--r--src/thread/pthread_mutex_unlock.c19
-rw-r--r--src/thread/pthread_mutexattr_destroy.c6
-rw-r--r--src/thread/pthread_mutexattr_gettype.c7
-rw-r--r--src/thread/pthread_mutexattr_init.c7
-rw-r--r--src/thread/pthread_mutexattr_settype.c8
-rw-r--r--src/thread/pthread_once.c38
-rw-r--r--src/thread/pthread_rwlock_destroy.c6
-rw-r--r--src/thread/pthread_rwlock_init.c9
-rw-r--r--src/thread/pthread_rwlock_rdlock.c8
-rw-r--r--src/thread/pthread_rwlock_timedrdlock.c15
-rw-r--r--src/thread/pthread_rwlock_timedwrlock.c17
-rw-r--r--src/thread/pthread_rwlock_tryrdlock.c13
-rw-r--r--src/thread/pthread_rwlock_trywrlock.c13
-rw-r--r--src/thread/pthread_rwlock_unlock.c17
-rw-r--r--src/thread/pthread_rwlock_wrlock.c13
-rw-r--r--src/thread/pthread_self.c39
-rw-r--r--src/thread/pthread_setcancelstate.c10
-rw-r--r--src/thread/pthread_setcanceltype.c10
-rw-r--r--src/thread/pthread_setspecific.c18
-rw-r--r--src/thread/pthread_spin_destroy.c6
-rw-r--r--src/thread/pthread_spin_init.c6
-rw-r--r--src/thread/pthread_spin_lock.c7
-rw-r--r--src/thread/pthread_spin_trylock.c6
-rw-r--r--src/thread/pthread_spin_unlock.c6
-rw-r--r--src/thread/pthread_testcancel.c7
-rw-r--r--src/time/__asctime.c27
-rw-r--r--src/time/__time.h9
-rw-r--r--src/time/__time_to_tm.c81
-rw-r--r--src/time/__tm_to_time.c33
-rw-r--r--src/time/asctime.c9
-rw-r--r--src/time/asctime_r.c8
-rw-r--r--src/time/clock.c9
-rw-r--r--src/time/clock_gettime.c7
-rw-r--r--src/time/ctime.c6
-rw-r--r--src/time/ctime_r.c8
-rw-r--r--src/time/difftime.c6
-rw-r--r--src/time/gettimeofday.c9
-rw-r--r--src/time/gmtime.c11
-rw-r--r--src/time/gmtime_r.c10
-rw-r--r--src/time/localtime.c12
-rw-r--r--src/time/localtime_r.c11
-rw-r--r--src/time/mktime.c24
-rw-r--r--src/time/nanosleep.c13
-rw-r--r--src/time/strftime.c172
-rw-r--r--src/time/strptime.c178
-rw-r--r--src/time/time.c12
-rw-r--r--src/time/times.c7
-rw-r--r--src/time/timezone.s27
-rw-r--r--src/time/tzset.c173
-rw-r--r--src/time/utime.c12
-rw-r--r--src/unistd/_exit.c7
-rw-r--r--src/unistd/access.c7
-rw-r--r--src/unistd/alarm.c7
-rw-r--r--src/unistd/chdir.c7
-rw-r--r--src/unistd/chown.c7
-rw-r--r--src/unistd/close.c11
-rw-r--r--src/unistd/confstr.c17
-rw-r--r--src/unistd/ctermid.c23
-rw-r--r--src/unistd/dup.c7
-rw-r--r--src/unistd/dup2.c7
-rw-r--r--src/unistd/faccessat.c7
-rw-r--r--src/unistd/fchdir.c7
-rw-r--r--src/unistd/fchown.c7
-rw-r--r--src/unistd/fchownat.c7
-rw-r--r--src/unistd/fdatasync.c7
-rw-r--r--src/unistd/fsync.c8
-rw-r--r--src/unistd/ftruncate.c15
-rw-r--r--src/unistd/getcwd.c8
-rw-r--r--src/unistd/getegid.c7
-rw-r--r--src/unistd/geteuid.c7
-rw-r--r--src/unistd/getgid.c7
-rw-r--r--src/unistd/getgroups.c8
-rw-r--r--src/unistd/gethostname.c14
-rw-r--r--src/unistd/getlogin.c7
-rw-r--r--src/unistd/getlogin_r.c13
-rw-r--r--src/unistd/getpgid.c7
-rw-r--r--src/unistd/getpgrp.c7
-rw-r--r--src/unistd/getpid.c7
-rw-r--r--src/unistd/getppid.c7
-rw-r--r--src/unistd/getsid.c7
-rw-r--r--src/unistd/getuid.c7
-rw-r--r--src/unistd/isatty.c8
-rw-r--r--src/unistd/lchown.c7
-rw-r--r--src/unistd/link.c7
-rw-r--r--src/unistd/linkat.c7
-rw-r--r--src/unistd/lseek.c16
-rw-r--r--src/unistd/nice.c7
-rw-r--r--src/unistd/pause.c12
-rw-r--r--src/unistd/pipe.c7
-rw-r--r--src/unistd/pread.c14
-rw-r--r--src/unistd/pwrite.c14
-rw-r--r--src/unistd/read.c12
-rw-r--r--src/unistd/readlink.c7
-rw-r--r--src/unistd/readlinkat.c7
-rw-r--r--src/unistd/readv.c12
-rw-r--r--src/unistd/renameat.c7
-rw-r--r--src/unistd/rmdir.c7
-rw-r--r--src/unistd/setegid.c6
-rw-r--r--src/unistd/seteuid.c6
-rw-r--r--src/unistd/setgid.c9
-rw-r--r--src/unistd/setpgid.c7
-rw-r--r--src/unistd/setpgrp.c6
-rw-r--r--src/unistd/setregid.c9
-rw-r--r--src/unistd/setreuid.c9
-rw-r--r--src/unistd/setsid.c7
-rw-r--r--src/unistd/setuid.c9
-rw-r--r--src/unistd/sleep.c10
-rw-r--r--src/unistd/symlink.c7
-rw-r--r--src/unistd/symlinkat.c7
-rw-r--r--src/unistd/sync.c7
-rw-r--r--src/unistd/tcgetpgrp.c11
-rw-r--r--src/unistd/tcsetpgrp.c9
-rw-r--r--src/unistd/truncate.c15
-rw-r--r--src/unistd/ttyname.c14
-rw-r--r--src/unistd/ttyname_r.c19
-rw-r--r--src/unistd/ualarm.c8
-rw-r--r--src/unistd/unlink.c7
-rw-r--r--src/unistd/unlinkat.c7
-rw-r--r--src/unistd/usleep.c11
-rw-r--r--src/unistd/write.c12
-rw-r--r--src/unistd/writev.c12
856 files changed, 33417 insertions, 0 deletions
diff --git a/src/conf/fpathconf.c b/src/conf/fpathconf.c
new file mode 100644
index 00000000..af7e4d3b
--- /dev/null
+++ b/src/conf/fpathconf.c
@@ -0,0 +1,35 @@
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+long fpathconf(int fd, int name)
+{
+	static const short values[] = {
+		[_PC_LINK_MAX] = _POSIX_LINK_MAX,
+		[_PC_MAX_CANON] = _POSIX_MAX_CANON,
+		[_PC_MAX_INPUT] = _POSIX_MAX_INPUT,
+		[_PC_NAME_MAX] = NAME_MAX,
+		[_PC_PATH_MAX] = PATH_MAX,
+		[_PC_PIPE_BUF] = PIPE_BUF,
+		[_PC_CHOWN_RESTRICTED] = 1,
+		[_PC_NO_TRUNC] = 1,
+		[_PC_VDISABLE] = 0,
+		[_PC_SYNC_IO] = 0,
+		[_PC_ASYNC_IO] = 0,
+		[_PC_PRIO_IO] = 0,
+		[_PC_SOCK_MAXBUF] = -1,
+		[_PC_FILESIZEBITS] = sizeof(off_t),
+		[_PC_REC_INCR_XFER_SIZE] = PAGE_SIZE,
+		[_PC_REC_MAX_XFER_SIZE] = PAGE_SIZE,
+		[_PC_REC_MIN_XFER_SIZE] = PAGE_SIZE,
+		[_PC_REC_XFER_ALIGN] = PAGE_SIZE,
+		[_PC_ALLOC_SIZE_MIN] = PAGE_SIZE,
+		[_PC_SYMLINK_MAX] = SYMLINK_MAX,
+		[_PC_2_SYMLINKS] = 1
+	};
+	if (name > sizeof(values)/sizeof(values[0])) {
+		errno = EINVAL;
+		return -1;
+	}
+	return values[name];
+}
diff --git a/src/conf/pathconf.c b/src/conf/pathconf.c
new file mode 100644
index 00000000..01e19c59
--- /dev/null
+++ b/src/conf/pathconf.c
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+long pathconf(const char *path, int name)
+{
+	return fpathconf(-1, name);
+}
diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c
new file mode 100644
index 00000000..cdaeb2a6
--- /dev/null
+++ b/src/conf/sysconf.c
@@ -0,0 +1,222 @@
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#define VER (-2)
+#define OFLOW (-3)
+
+long sysconf(int name)
+{
+	static const short values[] = {
+		[_SC_ARG_MAX] = OFLOW,
+		[_SC_CHILD_MAX] = -1,
+		[_SC_CLK_TCK] = 100,
+		[_SC_NGROUPS_MAX] = 32,
+		[_SC_OPEN_MAX] = 1024,
+		[_SC_STREAM_MAX] = -1,
+		[_SC_TZNAME_MAX] = TZNAME_MAX,
+		[_SC_JOB_CONTROL] = 1,
+		[_SC_SAVED_IDS] = 1,
+		[_SC_REALTIME_SIGNALS] = 1,
+		[_SC_PRIORITY_SCHEDULING] = -1,
+		[_SC_TIMERS] = VER,
+		[_SC_ASYNCHRONOUS_IO] = VER,
+		[_SC_PRIORITIZED_IO] = -1,
+		[_SC_SYNCHRONIZED_IO] = -1,
+		[_SC_FSYNC] = -1,
+		[_SC_MAPPED_FILES] = VER,
+		[_SC_MEMLOCK] = VER,
+		[_SC_MEMLOCK_RANGE] = VER,
+		[_SC_MEMORY_PROTECTION] = VER,
+		[_SC_MESSAGE_PASSING] = -1,
+		[_SC_SEMAPHORES] = VER,
+		[_SC_SHARED_MEMORY_OBJECTS] = -1,
+		[_SC_AIO_LISTIO_MAX] = -1,
+		[_SC_AIO_MAX] = -1,
+		[_SC_AIO_PRIO_DELTA_MAX] = 0, /* ?? */
+		[_SC_DELAYTIMER_MAX] = _POSIX_DELAYTIMER_MAX,
+		[_SC_MQ_OPEN_MAX] = -1,
+		[_SC_MQ_PRIO_MAX] = _POSIX_MQ_PRIO_MAX,
+		[_SC_VERSION] = VER,
+		[_SC_PAGE_SIZE] = PAGE_SIZE,
+		[_SC_RTSIG_MAX] = 63, /* ?? */
+		[_SC_SEM_NSEMS_MAX] = _POSIX_SEM_NSEMS_MAX,
+		[_SC_SEM_VALUE_MAX] = _POSIX_SEM_VALUE_MAX,
+		[_SC_SIGQUEUE_MAX] = -1,
+		[_SC_TIMER_MAX] = -1,
+		[_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX,
+		[_SC_BC_DIM_MAX] = _POSIX2_BC_DIM_MAX,
+		[_SC_BC_SCALE_MAX] = _POSIX2_BC_SCALE_MAX,
+		[_SC_BC_STRING_MAX] = _POSIX2_BC_STRING_MAX,
+		[_SC_COLL_WEIGHTS_MAX] = COLL_WEIGHTS_MAX,
+		[_SC_EQUIV_CLASS_MAX] = -1, /* ?? */
+		[_SC_EXPR_NEST_MAX] = -1,
+		[_SC_LINE_MAX] = -1,
+		[_SC_RE_DUP_MAX] = RE_DUP_MAX,
+		[_SC_CHARCLASS_NAME_MAX] = -1, /* ?? */
+		[_SC_2_VERSION] = VER,
+		[_SC_2_C_BIND] = VER,
+		[_SC_2_C_DEV] = -1,
+		[_SC_2_FORT_DEV] = -1,
+		[_SC_2_FORT_RUN] = -1,
+		[_SC_2_SW_DEV] = -1,
+		[_SC_2_LOCALEDEF] = -1,
+		[_SC_PII] = -1, /* ????????? */
+		[_SC_PII_XTI] = -1,
+		[_SC_PII_SOCKET] = -1,
+		[_SC_PII_INTERNET] = -1,
+		[_SC_PII_OSI] = -1,
+		[_SC_POLL] = 1,
+		[_SC_SELECT] = 1,
+		[_SC_IOV_MAX] = IOV_MAX,
+		[_SC_PII_INTERNET_STREAM] = -1,
+		[_SC_PII_INTERNET_DGRAM] = -1,
+		[_SC_PII_OSI_COTS] = -1,
+		[_SC_PII_OSI_CLTS] = -1,
+		[_SC_PII_OSI_M] = -1,
+		[_SC_T_IOV_MAX] = -1,
+		[_SC_THREADS] = VER,
+		[_SC_THREAD_SAFE_FUNCTIONS] = VER,
+		[_SC_GETGR_R_SIZE_MAX] = -1,
+		[_SC_GETPW_R_SIZE_MAX] = -1,
+		[_SC_LOGIN_NAME_MAX] = 256,
+		[_SC_TTY_NAME_MAX] = TTY_NAME_MAX,
+		[_SC_THREAD_DESTRUCTOR_ITERATIONS] = _POSIX_THREAD_DESTRUCTOR_ITERATIONS,
+		[_SC_THREAD_KEYS_MAX] = -1,
+		[_SC_THREAD_STACK_MIN] = 2*PAGE_SIZE,
+		[_SC_THREAD_THREADS_MAX] = -1,
+		[_SC_THREAD_ATTR_STACKADDR] = -1,
+		[_SC_THREAD_ATTR_STACKSIZE] = VER,
+		[_SC_THREAD_PRIORITY_SCHEDULING] = -1,
+		[_SC_THREAD_PRIO_INHERIT] = -1,
+		[_SC_THREAD_PRIO_PROTECT] = -1,
+		[_SC_THREAD_PROCESS_SHARED] = VER,
+		[_SC_NPROCESSORS_CONF] = -1,
+		[_SC_NPROCESSORS_ONLN] = -1,
+		[_SC_PHYS_PAGES] = -1,
+		[_SC_AVPHYS_PAGES] = -1,
+		[_SC_ATEXIT_MAX] = -1,
+		[_SC_PASS_MAX] = -1,
+		[_SC_XOPEN_VERSION] = _XOPEN_VERSION,
+		[_SC_XOPEN_XCU_VERSION] = _XOPEN_VERSION,
+		[_SC_XOPEN_UNIX] = -1,
+		[_SC_XOPEN_CRYPT] = -1,
+		[_SC_XOPEN_ENH_I18N] = 1,
+		[_SC_XOPEN_SHM] = 1,
+		[_SC_2_CHAR_TERM] = -1,
+		[_SC_2_C_VERSION] = -1,
+		[_SC_2_UPE] = -1,
+		[_SC_XOPEN_XPG2] = -1,
+		[_SC_XOPEN_XPG3] = -1,
+		[_SC_XOPEN_XPG4] = -1,
+		[_SC_CHAR_BIT] = -1,
+		[_SC_CHAR_MAX] = -1,
+		[_SC_CHAR_MIN] = -1,
+		[_SC_INT_MAX] = -1,
+		[_SC_INT_MIN] = -1,
+		[_SC_LONG_BIT] = -1,
+		[_SC_WORD_BIT] = -1,
+		[_SC_MB_LEN_MAX] = -1,
+		[_SC_NZERO] = NZERO,
+		[_SC_SSIZE_MAX] = -1,
+		[_SC_SCHAR_MAX] = -1,
+		[_SC_SCHAR_MIN] = -1,
+		[_SC_SHRT_MAX] = -1,
+		[_SC_SHRT_MIN] = -1,
+		[_SC_UCHAR_MAX] = -1,
+		[_SC_UINT_MAX] = -1,
+		[_SC_ULONG_MAX] = -1,
+		[_SC_USHRT_MAX] = -1,
+		[_SC_NL_ARGMAX] = -1,
+		[_SC_NL_LANGMAX] = -1,
+		[_SC_NL_MSGMAX] = -1,
+		[_SC_NL_NMAX] = -1,
+		[_SC_NL_SETMAX] = -1,
+		[_SC_NL_TEXTMAX] = -1,
+		[_SC_XBS5_ILP32_OFF32] = -1,
+		[_SC_XBS5_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1,
+		[_SC_XBS5_LP64_OFF64] = 2*(sizeof(long)==8)-1,
+		[_SC_XBS5_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1,
+		[_SC_XOPEN_LEGACY] = -1,
+		[_SC_XOPEN_REALTIME] = -1,
+		[_SC_XOPEN_REALTIME_THREADS] = -1,
+		[_SC_ADVISORY_INFO] = -1,
+		[_SC_BARRIERS] = VER,
+		[_SC_BASE] = -1,
+		[_SC_C_LANG_SUPPORT] = -1,
+		[_SC_C_LANG_SUPPORT_R] = -1,
+		[_SC_CLOCK_SELECTION] = VER,
+		[_SC_CPUTIME] = VER,
+		[_SC_THREAD_CPUTIME] = -1,
+		[_SC_DEVICE_IO] = -1,
+		[_SC_DEVICE_SPECIFIC] = -1,
+		[_SC_DEVICE_SPECIFIC_R] = -1,
+		[_SC_FD_MGMT] = -1,
+		[_SC_FIFO] = -1,
+		[_SC_PIPE] = -1,
+		[_SC_FILE_ATTRIBUTES] = -1,
+		[_SC_FILE_LOCKING] = -1,
+		[_SC_FILE_SYSTEM] = -1,
+		[_SC_MONOTONIC_CLOCK] = VER,
+		[_SC_MULTI_PROCESS] = -1,
+		[_SC_SINGLE_PROCESS] = -1,
+		[_SC_NETWORKING] = -1,
+		[_SC_READER_WRITER_LOCKS] = VER,
+		[_SC_SPIN_LOCKS] = VER,
+		[_SC_REGEXP] = 1,
+		[_SC_REGEX_VERSION] = -1,
+		[_SC_SHELL] = 1,
+		[_SC_SIGNALS] = -1,
+		[_SC_SPAWN] = -1,
+		[_SC_SPORADIC_SERVER] = -1,
+		[_SC_THREAD_SPORADIC_SERVER] = -1,
+		[_SC_SYSTEM_DATABASE] = -1,
+		[_SC_SYSTEM_DATABASE_R] = -1,
+		[_SC_TIMEOUTS] = VER,
+		[_SC_TYPED_MEMORY_OBJECTS] = -1,
+		[_SC_USER_GROUPS] = -1,
+		[_SC_USER_GROUPS_R] = -1,
+		[_SC_2_PBS] = -1,
+		[_SC_2_PBS_ACCOUNTING] = -1,
+		[_SC_2_PBS_LOCATE] = -1,
+		[_SC_2_PBS_MESSAGE] = -1,
+		[_SC_2_PBS_TRACK] = -1,
+		[_SC_SYMLOOP_MAX] = SYMLOOP_MAX,
+		[_SC_STREAMS] = 0,
+		[_SC_2_PBS_CHECKPOINT] = -1,
+		[_SC_V6_ILP32_OFF32] = -1,
+		[_SC_V6_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1,
+		[_SC_V6_LP64_OFF64] = 2*(sizeof(long)==8)-1,
+		[_SC_V6_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1,
+		[_SC_HOST_NAME_MAX] = HOST_NAME_MAX,
+		[_SC_TRACE] = -1,
+		[_SC_TRACE_EVENT_FILTER] = -1,
+		[_SC_TRACE_INHERIT] = -1,
+		[_SC_TRACE_LOG] = -1,
+
+		[_SC_IPV6] = VER,
+		[_SC_RAW_SOCKETS] = VER,
+		[_SC_V7_ILP32_OFF32] = -1,
+		[_SC_V7_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1,
+		[_SC_V7_LP64_OFF64] = 2*(sizeof(long)==8)-1,
+		[_SC_V7_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1,
+		[_SC_SS_REPL_MAX] = -1,
+		[_SC_TRACE_EVENT_NAME_MAX] = -1,
+		[_SC_TRACE_NAME_MAX] = -1,
+		[_SC_TRACE_SYS_MAX] = -1,
+		[_SC_TRACE_USER_EVENT_MAX] = -1,
+		[_SC_XOPEN_STREAMS] = 0,
+		[_SC_THREAD_ROBUST_PRIO_INHERIT] = -1,
+		[_SC_THREAD_ROBUST_PRIO_PROTECT] = -1,
+	};
+	if (name > sizeof(values)/sizeof(values[0])) {
+		errno = EINVAL;
+		return -1;
+	} else if (values[name] == VER) {
+		return _POSIX_VERSION;
+	} else if (values[name] == OFLOW) {
+		return ARG_MAX;
+	} else {
+		return values[name];
+	}
+}
diff --git a/src/ctype/__ctype_get_mb_cur_max.c b/src/ctype/__ctype_get_mb_cur_max.c
new file mode 100644
index 00000000..42e4ee71
--- /dev/null
+++ b/src/ctype/__ctype_get_mb_cur_max.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+size_t __ctype_get_mb_cur_max()
+{
+	return 4;
+}
diff --git a/src/ctype/isalnum.c b/src/ctype/isalnum.c
new file mode 100644
index 00000000..e3d2cf0b
--- /dev/null
+++ b/src/ctype/isalnum.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isalnum(int c)
+{
+	return isalpha(c) || isdigit(c);
+}
diff --git a/src/ctype/isalpha.c b/src/ctype/isalpha.c
new file mode 100644
index 00000000..53e115c2
--- /dev/null
+++ b/src/ctype/isalpha.c
@@ -0,0 +1,7 @@
+#include <ctype.h>
+#undef isalpha
+
+int isalpha(int c)
+{
+	return ((unsigned)c|32)-'a' < 26;
+}
diff --git a/src/ctype/isascii.c b/src/ctype/isascii.c
new file mode 100644
index 00000000..3af0a10d
--- /dev/null
+++ b/src/ctype/isascii.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isascii(int c)
+{
+	return !(c&~0x7f);
+}
diff --git a/src/ctype/isblank.c b/src/ctype/isblank.c
new file mode 100644
index 00000000..957400b2
--- /dev/null
+++ b/src/ctype/isblank.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isblank(int c)
+{
+	return (c == ' ' || c == '\t');
+}
diff --git a/src/ctype/iscntrl.c b/src/ctype/iscntrl.c
new file mode 100644
index 00000000..92ed7f0e
--- /dev/null
+++ b/src/ctype/iscntrl.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int iscntrl(int c)
+{
+	return (unsigned)c < 0x20 || c == 0x7f;
+}
diff --git a/src/ctype/isdigit.c b/src/ctype/isdigit.c
new file mode 100644
index 00000000..0bc82a6d
--- /dev/null
+++ b/src/ctype/isdigit.c
@@ -0,0 +1,7 @@
+#include <ctype.h>
+#undef isdigit
+
+int isdigit(int c)
+{
+	return (unsigned)c-'0' < 10;
+}
diff --git a/src/ctype/isgraph.c b/src/ctype/isgraph.c
new file mode 100644
index 00000000..98979d1e
--- /dev/null
+++ b/src/ctype/isgraph.c
@@ -0,0 +1,4 @@
+int isgraph(int c)
+{
+	return (unsigned)c-0x21 < 0x5e;
+}
diff --git a/src/ctype/islower.c b/src/ctype/islower.c
new file mode 100644
index 00000000..d72fb212
--- /dev/null
+++ b/src/ctype/islower.c
@@ -0,0 +1,7 @@
+#include <ctype.h>
+#undef islower
+
+int islower(int c)
+{
+	return (unsigned)c-'a' < 26;
+}
diff --git a/src/ctype/isprint.c b/src/ctype/isprint.c
new file mode 100644
index 00000000..504e66ed
--- /dev/null
+++ b/src/ctype/isprint.c
@@ -0,0 +1,4 @@
+int isprint(int c)
+{
+	return (unsigned)c-0x20 < 0x5f;
+}
diff --git a/src/ctype/ispunct.c b/src/ctype/ispunct.c
new file mode 100644
index 00000000..fc455352
--- /dev/null
+++ b/src/ctype/ispunct.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int ispunct(int c)
+{
+	return isgraph(c) && !isalnum(c);
+}
diff --git a/src/ctype/isspace.c b/src/ctype/isspace.c
new file mode 100644
index 00000000..8e535aa1
--- /dev/null
+++ b/src/ctype/isspace.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isspace(int c)
+{
+	return c == ' ' || (unsigned)c-'\t' < 5;
+}
diff --git a/src/ctype/isupper.c b/src/ctype/isupper.c
new file mode 100644
index 00000000..f09d88c5
--- /dev/null
+++ b/src/ctype/isupper.c
@@ -0,0 +1,7 @@
+#include <ctype.h>
+#undef isupper
+
+int isupper(int c)
+{
+	return (unsigned)c-'A' < 26;
+}
diff --git a/src/ctype/iswalnum.c b/src/ctype/iswalnum.c
new file mode 100644
index 00000000..d3b56674
--- /dev/null
+++ b/src/ctype/iswalnum.c
@@ -0,0 +1,9 @@
+#include <wchar.h>
+#include <wctype.h>
+
+#undef iswalnum
+
+int iswalnum(wint_t wc)
+{
+	return (unsigned)wc-'0' < 10 || iswalpha(wc);
+}
diff --git a/src/ctype/iswalpha.c b/src/ctype/iswalpha.c
new file mode 100644
index 00000000..0f031eac
--- /dev/null
+++ b/src/ctype/iswalpha.c
@@ -0,0 +1,6 @@
+#include <wctype.h>
+
+int iswalpha(wint_t wc)
+{
+	return (32U|wc)-'a'<26;
+}
diff --git a/src/ctype/iswblank.c b/src/ctype/iswblank.c
new file mode 100644
index 00000000..bc6196f2
--- /dev/null
+++ b/src/ctype/iswblank.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+#include <wctype.h>
+#include <ctype.h>
+
+int iswblank(wint_t wc)
+{
+	return isblank(wc);
+}
diff --git a/src/ctype/iswcntrl.c b/src/ctype/iswcntrl.c
new file mode 100644
index 00000000..93942b08
--- /dev/null
+++ b/src/ctype/iswcntrl.c
@@ -0,0 +1,10 @@
+#include <wchar.h>
+#include <wctype.h>
+
+int iswcntrl(wint_t wc)
+{
+	return (unsigned)wc < 32
+	    || (unsigned)(wc-0x7f) < 33
+	    || (unsigned)(wc-0x2028) < 2
+	    || (unsigned)(wc-0xfff9) < 3;
+}
diff --git a/src/ctype/iswctype.c b/src/ctype/iswctype.c
new file mode 100644
index 00000000..d917975b
--- /dev/null
+++ b/src/ctype/iswctype.c
@@ -0,0 +1,63 @@
+#include <wchar.h>
+#include <wctype.h>
+#include <string.h>
+
+#define WCTYPE_ALNUM  1
+#define WCTYPE_ALPHA  2
+#define WCTYPE_BLANK  3
+#define WCTYPE_CNTRL  4
+#define WCTYPE_DIGIT  5
+#define WCTYPE_GRAPH  6
+#define WCTYPE_LOWER  7
+#define WCTYPE_PRINT  8
+#define WCTYPE_PUNCT  9
+#define WCTYPE_SPACE  10
+#define WCTYPE_UPPER  11
+#define WCTYPE_XDIGIT 12
+
+int iswctype(wint_t wc, wctype_t type)
+{
+	switch (type) {
+	case WCTYPE_ALNUM:
+		return iswalnum(wc);
+	case WCTYPE_ALPHA:
+		return iswalpha(wc);
+	case WCTYPE_BLANK:
+		return iswblank(wc);
+	case WCTYPE_CNTRL:
+		return iswcntrl(wc);
+	case WCTYPE_DIGIT:
+		return iswdigit(wc);
+	case WCTYPE_GRAPH:
+		return iswgraph(wc);
+	case WCTYPE_LOWER:
+		return iswlower(wc);
+	case WCTYPE_PRINT:
+		return iswprint(wc);
+	case WCTYPE_PUNCT:
+		return iswpunct(wc);
+	case WCTYPE_SPACE:
+		return iswspace(wc);
+	case WCTYPE_UPPER:
+		return iswupper(wc);
+	case WCTYPE_XDIGIT:
+		return iswxdigit(wc);
+	}
+	return 0;
+}
+
+wctype_t wctype(const char *s)
+{
+	int i;
+	const char *p;
+	/* order must match! */
+	static const char names[] =
+		"alnum\0" "alpha\0" "blank\0"
+		"cntrl\0" "digit\0" "graph\0"
+		"lower\0" "print\0" "punct\0"
+		"space\0" "upper\0" "xdigit";
+	for (i=1, p=names; *p; i++, p+=6)
+		if (*s == *p && !strcmp(s, p))
+			return i;
+	return 0;
+}
diff --git a/src/ctype/iswdigit.c b/src/ctype/iswdigit.c
new file mode 100644
index 00000000..0487145f
--- /dev/null
+++ b/src/ctype/iswdigit.c
@@ -0,0 +1,9 @@
+#include <wchar.h>
+#include <wctype.h>
+
+#undef iswdigit
+
+int iswdigit(wint_t wc)
+{
+	return (unsigned)wc-'0' < 10;
+}
diff --git a/src/ctype/iswgraph.c b/src/ctype/iswgraph.c
new file mode 100644
index 00000000..fdc97853
--- /dev/null
+++ b/src/ctype/iswgraph.c
@@ -0,0 +1,7 @@
+#include <wctype.h>
+
+int iswgraph(wint_t wc)
+{
+	/* ISO C defines this function as: */
+	return !iswspace(wc) && iswprint(wc);
+}
diff --git a/src/ctype/iswlower.c b/src/ctype/iswlower.c
new file mode 100644
index 00000000..0a568e77
--- /dev/null
+++ b/src/ctype/iswlower.c
@@ -0,0 +1,6 @@
+#include <wctype.h>
+
+int iswlower(wint_t wc)
+{
+	return towupper(wc) != wc;
+}
diff --git a/src/ctype/iswprint.c b/src/ctype/iswprint.c
new file mode 100644
index 00000000..7717671a
--- /dev/null
+++ b/src/ctype/iswprint.c
@@ -0,0 +1,10 @@
+#include <wctype.h>
+
+int iswprint(wint_t wc)
+{
+	unsigned c = wc;
+	/* assume any non-control, non-illegal codepoint is printable */
+	if (c>0x10ffff || c-0xd800<0x800 || (c&0xfffe)==0xfffe || iswcntrl(c))
+		return 0;
+	return 1;
+}
diff --git a/src/ctype/iswpunct.c b/src/ctype/iswpunct.c
new file mode 100644
index 00000000..1414c30c
--- /dev/null
+++ b/src/ctype/iswpunct.c
@@ -0,0 +1,138 @@
+#include <wctype.h>
+#include <inttypes.h>
+
+/* The below data is derived from classes (P.|Sm) plus Pattern_Syntax */
+
+#define R(a,b) { (b), (b)-(a) }
+
+static const struct range {
+	uint32_t base:20;
+	uint32_t len:12;
+} ranges[] = {
+R(0x21, 0x2f),
+R(0x3a, 0x40),
+R(0x5b, 0x60),
+R(0x7b, 0x7e),
+R(0xa1, 0xa7),
+R(0xa9, 0xa9),
+R(0xab, 0xac),
+R(0xae, 0xae),
+R(0xb0, 0xb1),
+R(0xb6, 0xb7),
+R(0xbb, 0xbb),
+R(0xbf, 0xbf),
+R(0xd7, 0xd7),
+R(0xf7, 0xf7),
+R(0x37e, 0x37e),
+R(0x387, 0x387),
+R(0x3f6, 0x3f6),
+R(0x55a, 0x55f),
+R(0x589, 0x58a),
+R(0x5be, 0x5be),
+R(0x5c0, 0x5c0),
+R(0x5c3, 0x5c3),
+R(0x5c6, 0x5c6),
+R(0x5f3, 0x5f4),
+R(0x606, 0x60a),
+R(0x60c, 0x60d),
+R(0x61b, 0x61b),
+R(0x61e, 0x61f),
+R(0x66a, 0x66d),
+R(0x6d4, 0x6d4),
+R(0x700, 0x70d),
+R(0x7f7, 0x7f9),
+R(0x964, 0x965),
+R(0x970, 0x970),
+R(0xdf4, 0xdf4),
+R(0xe4f, 0xe4f),
+R(0xe5a, 0xe5b),
+R(0xf04, 0xf12),
+R(0xf3a, 0xf3d),
+R(0xf85, 0xf85),
+R(0xfd0, 0xfd4),
+R(0x104a, 0x104f),
+R(0x10fb, 0x10fb),
+R(0x1361, 0x1368),
+R(0x166d, 0x166e),
+R(0x1680, 0x1680),
+R(0x169b, 0x169c),
+R(0x16eb, 0x16ed),
+R(0x1735, 0x1736),
+R(0x17d4, 0x17d6),
+R(0x17d8, 0x17da),
+R(0x1800, 0x180a),
+R(0x180e, 0x180e),
+R(0x1944, 0x1945),
+R(0x19de, 0x19df),
+R(0x1a1e, 0x1a1f),
+R(0x1b5a, 0x1b60),
+R(0x1c3b, 0x1c3f),
+R(0x1c7e, 0x1c7f),
+R(0x2010, 0x2027),
+R(0x2030, 0x205e),
+R(0x207a, 0x207e),
+R(0x208a, 0x208e),
+R(0x2140, 0x2144),
+R(0x214b, 0x214b),
+R(0x2190, 0x245f),
+R(0x2500, 0x2775),
+R(0x2794, 0x2bff),
+R(0x2cf9, 0x2cfc),
+R(0x2cfe, 0x2cff),
+R(0x2e00, 0x2e7f),
+R(0x3001, 0x3003),
+R(0x3008, 0x3020),
+R(0x3030, 0x3030),
+R(0x303d, 0x303d),
+R(0x30a0, 0x30a0),
+R(0x30fb, 0x30fb),
+R(0xa60d, 0xa60f),
+R(0xa874, 0xa877),
+R(0xa8ce, 0xa8cf),
+R(0xa92e, 0xa92f),
+R(0xa95f, 0xa95f),
+R(0xfb29, 0xfb29),
+R(0xfd3e, 0xfd3f),
+R(0xfe10, 0xfe19),
+R(0xfe30, 0xfe52),
+R(0xfe54, 0xfe66),
+R(0xfe68, 0xfe68),
+R(0xfe6a, 0xfe6b),
+R(0xff01, 0xff03),
+R(0xff05, 0xff0f),
+R(0xff1a, 0xff20),
+R(0xff3b, 0xff3d),
+R(0xff3f, 0xff3f),
+R(0xff5b, 0xff65),
+R(0xffe2, 0xffe2),
+R(0xffe9, 0xffec),
+R(0x10100, 0x10101),
+R(0x1039f, 0x1039f),
+R(0x103d0, 0x103d0),
+R(0x1091f, 0x1091f),
+R(0x1093f, 0x1093f),
+R(0x10a50, 0x10a58),
+R(0x12470, 0x12473),
+R(0x1d6c1, 0x1d6c1),
+R(0x1d6db, 0x1d6db),
+R(0x1d6fb, 0x1d6fb),
+R(0x1d715, 0x1d715),
+R(0x1d735, 0x1d735),
+R(0x1d74f, 0x1d74f),
+R(0x1d76f, 0x1d76f),
+R(0x1d789, 0x1d789),
+R(0x1d7a9, 0x1d7a9),
+R(0x1d7c3, 0x1d7c3),
+};
+
+int iswpunct(wint_t wc)
+{
+	unsigned c = wc;
+	int a = 0;
+	int n = sizeof ranges / sizeof ranges[0];
+	do {
+		n >>= 1;
+		a += n+1 & (signed)(ranges[a+n].base-c)>>31;
+	} while (n);
+	return ranges[a].base-c <= ranges[a].len;
+}
diff --git a/src/ctype/iswspace.c b/src/ctype/iswspace.c
new file mode 100644
index 00000000..68a17437
--- /dev/null
+++ b/src/ctype/iswspace.c
@@ -0,0 +1,15 @@
+#include <wchar.h>
+#include <wctype.h>
+#include <ctype.h>
+
+int iswspace(wint_t wc)
+{
+	static const wchar_t spaces[] = {
+		' ', '\t', '\n', '\r', 11, 12,  0x0085,
+		0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005,
+		0x2006, 0x2008, 0x2009, 0x200a, 0x200b,
+		0x2028, 0x2029, 0x2050, 0x3000, 0
+	};
+	if (wcschr(spaces, wc)) return 1;
+	return 0;
+}
diff --git a/src/ctype/iswupper.c b/src/ctype/iswupper.c
new file mode 100644
index 00000000..eae59a75
--- /dev/null
+++ b/src/ctype/iswupper.c
@@ -0,0 +1,6 @@
+#include <wctype.h>
+
+int iswupper(wint_t wc)
+{
+	return towlower(wc) != wc;
+}
diff --git a/src/ctype/iswxdigit.c b/src/ctype/iswxdigit.c
new file mode 100644
index 00000000..229a469f
--- /dev/null
+++ b/src/ctype/iswxdigit.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+#include <wctype.h>
+
+int iswxdigit(wint_t wc)
+{
+	return (unsigned)(wc-'0') < 10 || (unsigned)((wc|32)-'a') < 6;
+}
diff --git a/src/ctype/isxdigit.c b/src/ctype/isxdigit.c
new file mode 100644
index 00000000..ae68a3dc
--- /dev/null
+++ b/src/ctype/isxdigit.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isxdigit(int c)
+{
+	return isdigit(c) || ((unsigned)c|32)-'a' < 6;
+}
diff --git a/src/ctype/toascii.c b/src/ctype/toascii.c
new file mode 100644
index 00000000..f0e48e8e
--- /dev/null
+++ b/src/ctype/toascii.c
@@ -0,0 +1,7 @@
+#include <ctype.h>
+
+/* nonsense function that should NEVER be used! */
+int toascii(int c)
+{
+	return c & 0x7f;
+}
diff --git a/src/ctype/tolower.c b/src/ctype/tolower.c
new file mode 100644
index 00000000..b56f3c50
--- /dev/null
+++ b/src/ctype/tolower.c
@@ -0,0 +1,7 @@
+#include <ctype.h>
+
+int tolower(int c)
+{
+	if (isupper(c)) return c | 32;
+	return c;
+}
diff --git a/src/ctype/toupper.c b/src/ctype/toupper.c
new file mode 100644
index 00000000..1799f030
--- /dev/null
+++ b/src/ctype/toupper.c
@@ -0,0 +1,7 @@
+#include <ctype.h>
+
+int toupper(int c)
+{
+	if (islower(c)) return c & 0x5f;
+	return c;
+}
diff --git a/src/ctype/towctrans.c b/src/ctype/towctrans.c
new file mode 100644
index 00000000..0b1eed04
--- /dev/null
+++ b/src/ctype/towctrans.c
@@ -0,0 +1,246 @@
+#include <wchar.h>
+#include <wctype.h>
+#include <stdio.h>
+
+#define CASEMAP(u1,u2,l) { (u1), (l)-(u1), (u2)-(u1)+1 }
+#define CASELACE(u1,u2) CASEMAP((u1),(u2),(u1)+1)
+
+static const struct {
+	unsigned short upper;
+	signed char lower;
+	unsigned char len;
+} casemaps[] = {
+	CASEMAP('A','Z','a'),
+	CASEMAP(0xc0,0xde,0xe0),
+
+	CASELACE(0x0100,0x012e),
+	CASELACE(0x0132,0x0136),
+	CASELACE(0x0139,0x0147),
+	CASELACE(0x014a,0x0176),
+	CASELACE(0x0179,0x017d),
+
+	CASELACE(0x370,0x372),
+	CASEMAP(0x391,0x3a1,0x3b1),
+	CASEMAP(0x3a3,0x3ab,0x3c3),
+	CASEMAP(0x400,0x40f,0x450),
+	CASEMAP(0x410,0x42f,0x430),
+
+	CASELACE(0x460,0x480),
+	CASELACE(0x48a,0x4be),
+	CASELACE(0x4c1,0x4cd),
+	CASELACE(0x4d0,0x50e),
+
+	CASEMAP(0x531,0x556,0x561),
+
+	CASELACE(0x01a0,0x01a4),
+	CASELACE(0x01b3,0x01b5),
+	CASELACE(0x01cd,0x01db),
+	CASELACE(0x01de,0x01ee),
+	CASELACE(0x01f8,0x021e),
+	CASELACE(0x0222,0x0232),
+	CASELACE(0x03d8,0x03ee),
+
+	CASELACE(0x1e00,0x1e94),
+	CASELACE(0x1ea0,0x1efe),
+
+	CASEMAP(0x1f08,0x1f0f,0x1f00),
+	CASEMAP(0x1f18,0x1f1d,0x1f10),
+	CASEMAP(0x1f28,0x1f2f,0x1f20),
+	CASEMAP(0x1f38,0x1f3f,0x1f30),
+	CASEMAP(0x1f48,0x1f4d,0x1f40),
+
+	CASEMAP(0x1f68,0x1f6f,0x1f60),
+	CASEMAP(0x1f88,0x1f8f,0x1f80),
+	CASEMAP(0x1f98,0x1f9f,0x1f90),
+	CASEMAP(0x1fa8,0x1faf,0x1fa0),
+	CASEMAP(0x1fb8,0x1fb9,0x1fb0),
+	CASEMAP(0x1fba,0x1fbb,0x1f70),
+	CASEMAP(0x1fc8,0x1fcb,0x1f72),
+	CASEMAP(0x1fd8,0x1fd9,0x1fd0),
+	CASEMAP(0x1fda,0x1fdb,0x1f76),
+	CASEMAP(0x1fe8,0x1fe9,0x1fe0),
+	CASEMAP(0x1fea,0x1feb,0x1f7a),
+	CASEMAP(0x1ff8,0x1ff9,0x1f78),
+	CASEMAP(0x1ffa,0x1ffb,0x1f7c),
+
+	CASELACE(0x246,0x24e),
+	CASELACE(0x510,0x512),
+	CASEMAP(0x2160,0x216f,0x2170),
+	CASEMAP(0x2c00,0x2c2e,0x2c30),
+	CASELACE(0x2c67,0x2c6b),
+	CASELACE(0x2c80,0x2ce2),
+
+	CASELACE(0xa722,0xa72e),
+	CASELACE(0xa732,0xa76e),
+	CASELACE(0xa779,0xa77b),
+	CASELACE(0xa77e,0xa786),
+
+	CASEMAP(0xff21,0xff3a,0xff41),
+	{ 0,0,0 }
+};
+
+static const unsigned short pairs[][2] = {
+	{ 'I',    0x0131 },
+	{ 'S',    0x017f },
+	{ 0x0130, 'i'    },
+	{ 0x0178, 0x00ff },
+	{ 0x0181, 0x0253 },
+	{ 0x0182, 0x0183 },
+	{ 0x0184, 0x0185 },
+	{ 0x0186, 0x0254 },
+	{ 0x0187, 0x0188 },
+	{ 0x0189, 0x0256 },
+	{ 0x018a, 0x0257 },
+	{ 0x018b, 0x018c },
+	{ 0x018e, 0x01dd },
+	{ 0x018f, 0x0259 },
+	{ 0x0190, 0x025b },
+	{ 0x0191, 0x0192 },
+	{ 0x0193, 0x0260 },
+	{ 0x0194, 0x0263 },
+	{ 0x0196, 0x0269 },
+	{ 0x0197, 0x0268 },
+	{ 0x0198, 0x0199 },
+	{ 0x019c, 0x026f },
+	{ 0x019d, 0x0272 },
+	{ 0x019f, 0x0275 },
+	{ 0x01a6, 0x0280 },
+	{ 0x01a7, 0x01a8 },
+	{ 0x01a9, 0x0283 },
+	{ 0x01ac, 0x01ad },
+	{ 0x01ae, 0x0288 },
+	{ 0x01af, 0x01b0 },
+	{ 0x01b1, 0x028a },
+	{ 0x01b2, 0x028b },
+	{ 0x01b7, 0x0292 },
+	{ 0x01b8, 0x01b9 },
+	{ 0x01bc, 0x01bd },
+	{ 0x01c4, 0x01c6 },
+	{ 0x01c4, 0x01c5 },
+	{ 0x01c5, 0x01c6 },
+	{ 0x01c7, 0x01c9 },
+	{ 0x01c7, 0x01c8 },
+	{ 0x01c8, 0x01c9 },
+	{ 0x01ca, 0x01cc },
+	{ 0x01ca, 0x01cb },
+	{ 0x01cb, 0x01cc },
+	{ 0x01f1, 0x01f3 },
+	{ 0x01f1, 0x01f2 },
+	{ 0x01f2, 0x01f3 },
+	{ 0x01f4, 0x01f5 },
+	{ 0x01f6, 0x0195 },
+	{ 0x01f7, 0x01bf },
+	{ 0x0220, 0x019e },
+	{ 0x0386, 0x03ac },
+	{ 0x0388, 0x03ad },
+	{ 0x0389, 0x03ae },
+	{ 0x038a, 0x03af },
+	{ 0x038c, 0x03cc },
+	{ 0x038e, 0x03cd },
+	{ 0x038f, 0x03ce },
+	{ 0x0399, 0x0345 },
+	{ 0x0399, 0x1fbe },
+	{ 0x03a3, 0x03c2 },
+	{ 0x03f7, 0x03f8 },
+	{ 0x03fa, 0x03fb },
+	{ 0x1e60, 0x1e9b },
+
+	{ 0x1f59, 0x1f51 },
+	{ 0x1f5b, 0x1f53 },
+	{ 0x1f5d, 0x1f55 },
+	{ 0x1f5f, 0x1f57 },
+	{ 0x1fbc, 0x1fb3 },
+	{ 0x1fcc, 0x1fc3 },
+	{ 0x1fec, 0x1fe5 },
+	{ 0x1ffc, 0x1ff3 },
+
+	{ 0x23a, 0x2c65 },
+	{ 0x23b, 0x23c },
+	{ 0x23d, 0x19a },
+	{ 0x23e, 0x2c66 },
+	{ 0x241, 0x242 },
+	{ 0x243, 0x180 },
+	{ 0x244, 0x289 },
+	{ 0x245, 0x28c },
+	{ 0x3f4, 0x3b8 },
+	{ 0x3f9, 0x3f2 },
+	{ 0x3fd, 0x37b },
+	{ 0x3fe, 0x37c },
+	{ 0x3ff, 0x37d },
+	{ 0x4c0, 0x4cf },
+
+	{ 0x2126, 0x3c9 },
+	{ 0x212a, 'k' },
+	{ 0x212b, 0xe5 },
+	{ 0x2132, 0x214e },
+	{ 0x2183, 0x2184 },
+	{ 0x2c60, 0x2c61 },
+	{ 0x2c62, 0x26b },
+	{ 0x2c63, 0x1d7d },
+	{ 0x2c64, 0x27d },
+	{ 0x2c6d, 0x251 },
+	{ 0x2c6e, 0x271 },
+	{ 0x2c6f, 0x250 },
+	{ 0x2c72, 0x2c73 },
+	{ 0x2c75, 0x2c76 },
+
+	{ 0xa77d, 0x1d79 },
+
+	/* bogus greek 'symbol' letters */
+	{ 0x376, 0x377 },
+	{ 0x39c, 0xb5 },
+	{ 0x392, 0x3d0 },
+	{ 0x398, 0x3d1 },
+	{ 0x3a6, 0x3d5 },
+	{ 0x3a0, 0x3d6 },
+	{ 0x39a, 0x3f0 },
+	{ 0x3a1, 0x3f1 },
+	{ 0x395, 0x3f5 },
+	{ 0x3cf, 0x3d7 },
+
+	{ 0,0 }
+};
+
+
+static wchar_t __towcase(wchar_t wc, int lower)
+{
+	int i;
+	int lmul = 2*lower-1;
+	int lmask = lower-1;
+	if ((unsigned)wc - 0x10400 < 0x50)
+		return wc + lmul*0x28;
+	/* no letters with case in these large ranges */
+	if (!iswalpha(wc)
+	 || (unsigned)wc - 0x0600 <= 0x0fff-0x0600
+	 || (unsigned)wc - 0x2e00 <= 0xa6ff-0x2e00
+	 || (unsigned)wc - 0xa800 <= 0xfeff-0xa800)
+		return wc;
+	/* special case because the diff between upper/lower is too big */
+	if ((unsigned)wc - 0x10a0 < 0x26 || (unsigned)wc - 0x2d00 < 0x26)
+		return wc + lmul*(0x2d00-0x10a0);
+	for (i=0; casemaps[i].len; i++) {
+		int base = casemaps[i].upper + (lmask & casemaps[i].lower);
+		if ((unsigned)wc-base < casemaps[i].len) {
+			if (casemaps[i].lower == 1)
+				return wc + lower - ((wc-casemaps[i].upper)&1);
+			return wc + lmul*casemaps[i].lower;
+		}
+	}
+	for (i=0; pairs[i][1-lower]; i++) {
+		if (pairs[i][1-lower] == wc)
+			return pairs[i][lower];
+	}
+	if ((unsigned)wc - 0x10428 + (lower<<5) + (lower<<3) < 0x28)
+		return wc - 0x28 + (lower<<10) + (lower<<6);
+	return wc;
+}
+
+wint_t towupper(wint_t wc)
+{
+	return __towcase(wc, 0);
+}
+
+wint_t towlower(wint_t wc)
+{
+	return __towcase(wc, 1);
+}
diff --git a/src/ctype/wcswidth.c b/src/ctype/wcswidth.c
new file mode 100644
index 00000000..5c8a5a4d
--- /dev/null
+++ b/src/ctype/wcswidth.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+int wcswidth(const wchar_t *wcs, size_t n)
+{
+	int l=0, k=0;
+	for (; n-- && *wcs && (k = wcwidth(*wcs)) >= 0; l+=k, wcs++);
+	return (k < 0) ? k : l;
+}
diff --git a/src/ctype/wctrans.c b/src/ctype/wctrans.c
new file mode 100644
index 00000000..03e9fd6a
--- /dev/null
+++ b/src/ctype/wctrans.c
@@ -0,0 +1,16 @@
+#include <wctype.h>
+#include <string.h>
+
+wctrans_t wctrans(const char *class)
+{
+	if (!strcmp(class, "toupper")) return 1;
+	if (!strcmp(class, "tolower")) return 2;
+	return 0;
+}
+
+wint_t towctrans(wint_t wc, wctrans_t trans)
+{
+	if (trans == 1) return towupper(wc);
+	if (trans == 2) return towlower(wc);
+	return wc;
+}
diff --git a/src/ctype/wcwidth.c b/src/ctype/wcwidth.c
new file mode 100644
index 00000000..ebc560a5
--- /dev/null
+++ b/src/ctype/wcwidth.c
@@ -0,0 +1,185 @@
+#include <inttypes.h>
+#include <wchar.h>
+
+#define R(a,b,w) { (b), (w)/2, (b)-(a) }
+
+static const struct range {
+	uint32_t base:20;
+	uint32_t width:1;
+	uint32_t len:11;
+} ranges[] = {
+	R(0x0300, 0x036F, 0),
+	R(0x0483, 0x0486, 0),
+	R(0x0488, 0x0489, 0),
+	R(0x0591, 0x05BD, 0),
+	R(0x05BF, 0x05BF, 0),
+	R(0x05C1, 0x05C2, 0),
+	R(0x05C4, 0x05C5, 0),
+	R(0x05C7, 0x05C7, 0),
+	R(0x0600, 0x0603, 0),
+	R(0x0610, 0x0615, 0),
+	R(0x064B, 0x065E, 0),
+	R(0x0670, 0x0670, 0),
+	R(0x06D6, 0x06E4, 0),
+	R(0x06E7, 0x06E8, 0),
+	R(0x06EA, 0x06ED, 0),
+	R(0x070F, 0x070F, 0),
+	R(0x0711, 0x0711, 0),
+	R(0x0730, 0x074A, 0),
+	R(0x07A6, 0x07B0, 0),
+	R(0x07EB, 0x07F3, 0),
+	R(0x0901, 0x0902, 0),
+	R(0x093C, 0x093C, 0),
+	R(0x0941, 0x0948, 0),
+	R(0x094D, 0x094D, 0),
+	R(0x0951, 0x0954, 0),
+	R(0x0962, 0x0963, 0),
+	R(0x0981, 0x0981, 0),
+	R(0x09BC, 0x09BC, 0),
+	R(0x09C1, 0x09C4, 0),
+	R(0x09CD, 0x09CD, 0),
+	R(0x09E2, 0x09E3, 0),
+	R(0x0A01, 0x0A02, 0),
+	R(0x0A3C, 0x0A3C, 0),
+	R(0x0A41, 0x0A42, 0),
+	R(0x0A47, 0x0A48, 0),
+	R(0x0A4B, 0x0A4D, 0),
+	R(0x0A70, 0x0A71, 0),
+	R(0x0A81, 0x0A82, 0),
+	R(0x0ABC, 0x0ABC, 0),
+	R(0x0AC1, 0x0AC5, 0),
+	R(0x0AC7, 0x0AC8, 0),
+	R(0x0ACD, 0x0ACD, 0),
+	R(0x0AE2, 0x0AE3, 0),
+	R(0x0B01, 0x0B01, 0),
+	R(0x0B3C, 0x0B3C, 0),
+	R(0x0B3F, 0x0B3F, 0),
+	R(0x0B41, 0x0B43, 0),
+	R(0x0B4D, 0x0B4D, 0),
+	R(0x0B56, 0x0B56, 0),
+	R(0x0B82, 0x0B82, 0),
+	R(0x0BC0, 0x0BC0, 0),
+	R(0x0BCD, 0x0BCD, 0),
+	R(0x0C3E, 0x0C40, 0),
+	R(0x0C46, 0x0C48, 0),
+	R(0x0C4A, 0x0C4D, 0),
+	R(0x0C55, 0x0C56, 0),
+	R(0x0CBC, 0x0CBC, 0),
+	R(0x0CBF, 0x0CBF, 0),
+	R(0x0CC6, 0x0CC6, 0),
+	R(0x0CCC, 0x0CCD, 0),
+	R(0x0CE2, 0x0CE3, 0),
+	R(0x0D41, 0x0D43, 0),
+	R(0x0D4D, 0x0D4D, 0),
+	R(0x0DCA, 0x0DCA, 0),
+	R(0x0DD2, 0x0DD4, 0),
+	R(0x0DD6, 0x0DD6, 0),
+	R(0x0E31, 0x0E31, 0),
+	R(0x0E34, 0x0E3A, 0),
+	R(0x0E47, 0x0E4E, 0),
+	R(0x0EB1, 0x0EB1, 0),
+	R(0x0EB4, 0x0EB9, 0),
+	R(0x0EBB, 0x0EBC, 0),
+	R(0x0EC8, 0x0ECD, 0),
+	R(0x0F18, 0x0F19, 0),
+	R(0x0F35, 0x0F35, 0),
+	R(0x0F37, 0x0F37, 0),
+	R(0x0F39, 0x0F39, 0),
+	R(0x0F71, 0x0F7E, 0),
+	R(0x0F80, 0x0F84, 0),
+	R(0x0F86, 0x0F87, 0),
+	R(0x0F90, 0x0F97, 0),
+	R(0x0F99, 0x0FBC, 0),
+	R(0x0FC6, 0x0FC6, 0),
+	R(0x102D, 0x1030, 0),
+	R(0x1032, 0x1032, 0),
+	R(0x1036, 0x1037, 0),
+	R(0x1039, 0x1039, 0),
+	R(0x1058, 0x1059, 0),
+	R(0x1100, 0x115F, 2),
+	R(0x1160, 0x11FF, 0),
+	R(0x135F, 0x135F, 0),
+	R(0x1712, 0x1714, 0),
+	R(0x1732, 0x1734, 0),
+	R(0x1752, 0x1753, 0),
+	R(0x1772, 0x1773, 0),
+	R(0x17B4, 0x17B5, 0),
+	R(0x17B7, 0x17BD, 0),
+	R(0x17C6, 0x17C6, 0),
+	R(0x17C9, 0x17D3, 0),
+	R(0x17DD, 0x17DD, 0),
+	R(0x180B, 0x180D, 0),
+	R(0x18A9, 0x18A9, 0),
+	R(0x1920, 0x1922, 0),
+	R(0x1927, 0x1928, 0),
+	R(0x1932, 0x1932, 0),
+	R(0x1939, 0x193B, 0),
+	R(0x1A17, 0x1A18, 0),
+	R(0x1B00, 0x1B03, 0),
+	R(0x1B34, 0x1B34, 0),
+	R(0x1B36, 0x1B3A, 0),
+	R(0x1B3C, 0x1B3C, 0),
+	R(0x1B42, 0x1B42, 0),
+	R(0x1B6B, 0x1B73, 0),
+	R(0x1DC0, 0x1DCA, 0),
+	R(0x1DFE, 0x1DFF, 0),
+	R(0x200B, 0x200F, 0),
+	R(0x202A, 0x202E, 0),
+	R(0x2060, 0x2063, 0),
+	R(0x206A, 0x206F, 0),
+	R(0x20D0, 0x20EF, 0),
+	R(0x2329, 0x232A, 2),
+	R(0x2E80, 0x3029, 2),
+	R(0x302A, 0x302F, 0),
+	R(0x3030, 0x303E, 2),
+	R(0x3099, 0x309A, 0),
+	R(0xA806, 0xA806, 0),
+	R(0xA80B, 0xA80B, 0),
+	R(0xA825, 0xA826, 0),
+	R(0xF900, 0xFAFF, 2),
+	R(0xFB1E, 0xFB1E, 0),
+	R(0xFE00, 0xFE0F, 0),
+	R(0xFE20, 0xFE23, 0),
+	R(0xFE30, 0xFE6F, 2),
+	R(0xFEFF, 0xFEFF, 0),
+	R(0xFF00, 0xFF60, 2),
+	R(0xFFE0, 0xFFE6, 2),
+	R(0x10A01, 0x10A03, 0),
+	R(0x10A05, 0x10A06, 0),
+	R(0x10A0C, 0x10A0F, 0),
+	R(0x10A38, 0x10A3A, 0),
+	R(0x10A3F, 0x10A3F, 0),
+	R(0x1D167, 0x1D169, 0),
+	R(0x1D173, 0x1D182, 0),
+	R(0x1D185, 0x1D18B, 0),
+	R(0x1D1AA, 0x1D1AD, 0),
+	R(0x1D242, 0x1D244, 0),
+	R(0xE0001, 0xE0001, 0),
+	R(0xE0020, 0xE007F, 0),
+	R(0xE0100, 0xE01EF, 0),
+};
+
+/* Note: because the len field is only 10 bits, we must special-case
+ * the two huge ranges of full width characters and exclude them
+ * from the binary search table. */
+
+int wcwidth(wchar_t wc)
+{
+	int a, n;
+	uint32_t c = wc;
+
+	if (c-0x20 < 0x5f) return 1;
+	if (!iswprint(c)) return wc ? -1 : 0;
+	if (c-0x20000 < 0x20000) return 2;
+
+	/* The following code is a branchless binary search. */
+	a = 0;
+	n = sizeof ranges / sizeof ranges[0];
+	do {
+		n >>= 1;
+		a += n+1 & (signed)(ranges[a+n].base-c)>>31;
+	} while (n);
+	if (ranges[a].base-c <= ranges[a].len)
+		return 2*ranges[a].width;
+	return 1 + (c-0x3040 < 0xd800-0x3040);
+}
diff --git a/src/dirent/__dirent.h b/src/dirent/__dirent.h
new file mode 100644
index 00000000..07b3ee68
--- /dev/null
+++ b/src/dirent/__dirent.h
@@ -0,0 +1,9 @@
+struct __DIR_s
+{
+	int lock;
+	int fd;
+	off_t tell;
+	int buf_pos;
+	int buf_end;
+	char buf[2048];
+};
diff --git a/src/dirent/__getdents.c b/src/dirent/__getdents.c
new file mode 100644
index 00000000..4195430b
--- /dev/null
+++ b/src/dirent/__getdents.c
@@ -0,0 +1,12 @@
+#include <dirent.h>
+#include "syscall.h"
+#include "libc.h"
+
+int __getdents(int fd, struct dirent *buf, size_t len)
+{
+	return syscall3(__NR_getdents64, fd, (long)buf, len);
+}
+
+weak_alias(__getdents, getdents);
+
+LFS64(getdents);
diff --git a/src/dirent/alphasort.c b/src/dirent/alphasort.c
new file mode 100644
index 00000000..42050fb7
--- /dev/null
+++ b/src/dirent/alphasort.c
@@ -0,0 +1,10 @@
+#include <string.h>
+#include <dirent.h>
+#include "libc.h"
+
+int alphasort(const struct dirent **a, const struct dirent **b)
+{
+	return strcoll((*a)->d_name, (*b)->d_name);
+}
+
+LFS64(alphasort);
diff --git a/src/dirent/closedir.c b/src/dirent/closedir.c
new file mode 100644
index 00000000..81e9591c
--- /dev/null
+++ b/src/dirent/closedir.c
@@ -0,0 +1,11 @@
+#include <dirent.h>
+#include <unistd.h>
+#include "__dirent.h"
+#include "libc.h"
+
+int closedir(DIR *dir)
+{
+	int ret = close(dir->fd);
+	free(dir);
+	return ret;
+}
diff --git a/src/dirent/dirfd.c b/src/dirent/dirfd.c
new file mode 100644
index 00000000..6c860073
--- /dev/null
+++ b/src/dirent/dirfd.c
@@ -0,0 +1,7 @@
+#include <dirent.h>
+#include "__dirent.h"
+
+int dirfd(DIR *d)
+{
+	return d->fd;
+}
diff --git a/src/dirent/fdopendir.c b/src/dirent/fdopendir.c
new file mode 100644
index 00000000..c4b8e61d
--- /dev/null
+++ b/src/dirent/fdopendir.c
@@ -0,0 +1,26 @@
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include "__dirent.h"
+
+DIR *fdopendir(int fd)
+{
+	DIR *dir;
+	struct stat st;
+
+	if (fstat(fd, &st) < 0 || !S_ISDIR(st.st_mode)) {
+		errno = ENOTDIR;
+		return 0;
+	}
+	if (!(dir = calloc(1, sizeof *dir))) {
+		return 0;
+	}
+
+	fcntl(fd, F_SETFD, FD_CLOEXEC);
+	dir->fd = fd;
+	return dir;
+}
diff --git a/src/dirent/opendir.c b/src/dirent/opendir.c
new file mode 100644
index 00000000..cefe6ce7
--- /dev/null
+++ b/src/dirent/opendir.c
@@ -0,0 +1,25 @@
+#define _GNU_SOURCE
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include "__dirent.h"
+
+DIR *opendir(const char *name)
+{
+	int fd;
+	DIR *dir;
+
+	if ((fd = open(name, O_RDONLY|O_DIRECTORY)) < 0)
+		return 0;
+	fcntl(fd, F_SETFD, FD_CLOEXEC);
+	if (!(dir = calloc(1, sizeof *dir))) {
+		close(fd);
+		return 0;
+	}
+	dir->fd = fd;
+	return dir;
+}
diff --git a/src/dirent/readdir.c b/src/dirent/readdir.c
new file mode 100644
index 00000000..1aeb25a5
--- /dev/null
+++ b/src/dirent/readdir.c
@@ -0,0 +1,32 @@
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "__dirent.h"
+#include "syscall.h"
+#include "libc.h"
+
+int __getdents(int, struct dirent *, size_t);
+
+struct dirent *readdir(DIR *dir)
+{
+	struct dirent *de;
+	
+	if (dir->buf_pos >= dir->buf_end) {
+		int len = __getdents(dir->fd, (void *)dir->buf, sizeof dir->buf);
+		if (len < 0) {
+			dir->lock = 0;
+			return NULL;
+		} else if (len == 0) return 0;
+		dir->buf_end = len;
+		dir->buf_pos = 0;
+	}
+	de = (void *)(dir->buf + dir->buf_pos);
+	dir->buf_pos += de->d_reclen;
+	dir->tell = de->d_off;
+	return de;
+}
+
+LFS64(readdir);
diff --git a/src/dirent/readdir_r.c b/src/dirent/readdir_r.c
new file mode 100644
index 00000000..58f60325
--- /dev/null
+++ b/src/dirent/readdir_r.c
@@ -0,0 +1,30 @@
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "__dirent.h"
+#include "libc.h"
+
+int readdir_r(DIR *dir, struct dirent *buf, struct dirent **result)
+{
+	struct dirent *de;
+	int errno_save = errno;
+	int ret;
+	
+	LOCK(&dir->lock);
+	errno = 0;
+	de = readdir(dir);
+	if ((ret = errno)) {
+		UNLOCK(&dir->lock);
+		return ret;
+	}
+	errno = errno_save;
+	if (de) memcpy(buf, de, de->d_reclen);
+	else buf = NULL;
+
+	UNLOCK(&dir->lock);
+	*result = buf;
+	return 0;
+}
+
+LFS64_2(readdir_r, readdir64_r);
diff --git a/src/dirent/rewinddir.c b/src/dirent/rewinddir.c
new file mode 100644
index 00000000..c6138f7c
--- /dev/null
+++ b/src/dirent/rewinddir.c
@@ -0,0 +1,13 @@
+#include <dirent.h>
+#include <unistd.h>
+#include "__dirent.h"
+#include "libc.h"
+
+void rewinddir(DIR *dir)
+{
+	LOCK(&dir->lock);
+	lseek(dir->fd, 0, SEEK_SET);
+	dir->buf_pos = dir->buf_end = 0;
+	dir->tell = 0;
+	UNLOCK(&dir->lock);
+}
diff --git a/src/dirent/scandir.c b/src/dirent/scandir.c
new file mode 100644
index 00000000..6a0a9993
--- /dev/null
+++ b/src/dirent/scandir.c
@@ -0,0 +1,50 @@
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stddef.h>
+#include <libc.h>
+
+int scandir(const char *path, struct dirent ***res,
+	int (*sel)(const struct dirent *),
+	int (*cmp)(const struct dirent **, const struct dirent **))
+{
+	DIR *d = opendir(path);
+	struct dirent *de, **names=0, **tmp;
+	size_t cnt=0, len=0, size;
+	int old_errno = errno;
+
+	if (!d) return -1;
+
+	while ((errno=0), (de = readdir(d))) {
+		if (sel && !sel(de)) continue;
+		if (cnt >= len) {
+			len = 2*len+1;
+			if (len > SIZE_MAX/sizeof *names) break;
+			tmp = realloc(names, len * sizeof *names);
+			if (!tmp) break;
+			names = tmp;
+		}
+		size = offsetof(struct dirent,d_name) + strlen(de->d_name) + 1;
+		names[cnt] = malloc(size);
+		if (!names[cnt]) break;
+		memcpy(names[cnt++], de, size);
+	}
+
+	closedir(d);
+
+	if (errno) {
+		old_errno = errno;
+		if (names) while (cnt-->0) free(names[cnt]);
+		free(names);
+		errno = old_errno;
+		return -1;
+	}
+
+	if (cmp) qsort(names, cnt, sizeof *names, (int (*)(const void *, const void *))cmp);
+	*res = names;
+	return cnt;
+}
+
+LFS64(scandir);
diff --git a/src/dirent/seekdir.c b/src/dirent/seekdir.c
new file mode 100644
index 00000000..81a0e331
--- /dev/null
+++ b/src/dirent/seekdir.c
@@ -0,0 +1,12 @@
+#include <dirent.h>
+#include <unistd.h>
+#include "__dirent.h"
+#include "libc.h"
+
+void seekdir(DIR *dir, long off)
+{
+	LOCK(&dir->lock);
+	dir->tell = lseek(dir->fd, off, SEEK_SET);
+	dir->buf_pos = dir->buf_end = 0;
+	UNLOCK(&dir->lock);
+}
diff --git a/src/dirent/telldir.c b/src/dirent/telldir.c
new file mode 100644
index 00000000..cf25acff
--- /dev/null
+++ b/src/dirent/telldir.c
@@ -0,0 +1,7 @@
+#include <dirent.h>
+#include "__dirent.h"
+
+long telldir(DIR *dir)
+{
+	return dir->tell;
+}
diff --git a/src/env/__environ.c b/src/env/__environ.c
new file mode 100644
index 00000000..d7bd5e50
--- /dev/null
+++ b/src/env/__environ.c
@@ -0,0 +1,7 @@
+#include "libc.h"
+
+#undef environ
+char **___environ = 0;
+weak_alias(___environ, __environ);
+weak_alias(___environ, _environ);
+weak_alias(___environ, environ);
diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c
new file mode 100644
index 00000000..70af77b5
--- /dev/null
+++ b/src/env/__libc_start_main.c
@@ -0,0 +1,26 @@
+#include "libc.h"
+
+/* Any use of __environ/environ will override this symbol. */
+char **__dummy_environ = (void *)-1;
+weak_alias(__dummy_environ, ___environ);
+
+int __libc_start_main(
+	int (*main)(int, char **, char **), int argc, char **argv,
+	int (*init)(int, char **, char **), void (*fini)(void),
+	void (*ldso_fini)(void))
+{
+	/* Save the environment if it may be used by libc/application */
+	char **envp = argv+argc+1;
+	if (___environ != (void *)-1) ___environ = envp;
+
+	/* Avoid writing 0 and triggering unnecessary COW */
+	if (ldso_fini) libc.ldso_fini = ldso_fini;
+	if (fini) libc.fini = fini;
+
+	/* Execute constructors (static) linked into the application */
+	if (init) init(argc, argv, envp);
+
+	/* Pass control to to application */
+	exit(main(argc, argv, envp));
+	return 0;
+}
diff --git a/src/env/clearenv.c b/src/env/clearenv.c
new file mode 100644
index 00000000..a2475ce7
--- /dev/null
+++ b/src/env/clearenv.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+extern char **__environ;
+
+int clearenv()
+{
+	__environ[0] = 0;
+	return 0;
+}
diff --git a/src/env/getenv.c b/src/env/getenv.c
new file mode 100644
index 00000000..00c1bce0
--- /dev/null
+++ b/src/env/getenv.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <string.h>
+#include "libc.h"
+
+char *getenv(const char *name)
+{
+	int i;
+	size_t l = strlen(name);
+	if (!__environ || !*name || strchr(name, '=')) return NULL;
+	for (i=0; __environ[i] && (strncmp(name, __environ[i], l)
+		|| __environ[i][l] != '='); i++);
+	if (__environ[i]) return __environ[i] + l+1;
+	return NULL;
+}
diff --git a/src/env/putenv.c b/src/env/putenv.c
new file mode 100644
index 00000000..181a4181
--- /dev/null
+++ b/src/env/putenv.c
@@ -0,0 +1,59 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+extern char **__environ;
+char **__env_map;
+
+int __putenv(char *s, int a)
+{
+	int i=0, j=0;
+	char *end = strchr(s, '=');
+	size_t l = end-s+1;
+	char **newenv = 0;
+	char **newmap = 0;
+	static char **oldenv;
+	
+	if (!end || l == 1) return -1;
+	for (; __environ[i] && memcmp(s, __environ[i], l); i++);
+	if (a) {
+		if (!__env_map) {
+			__env_map = calloc(2, sizeof(char *));
+			if (__env_map) __env_map[0] = s;
+		} else {
+			for (; __env_map[j] && __env_map[j] != __environ[i]; j++);
+			if (!__env_map[j]) {
+				newmap = realloc(__env_map, sizeof(char *)*(j+2));
+				if (newmap) {
+					__env_map = newmap;
+					__env_map[j] = s;
+					__env_map[j+1] = NULL;
+				}
+			} else {
+				free(__env_map[j]);
+			}
+		}
+	}
+	if (!__environ[i]) {
+		newenv = malloc(sizeof(char *)*(i+2));
+		if (!newenv) {
+			if (a && __env_map) __env_map[j] = 0;
+			return -1;
+		}
+		memcpy(newenv, __environ, sizeof(char *)*i);
+		newenv[i] = s;
+		newenv[i+1] = 0;
+		__environ = newenv;
+		free(oldenv);
+		oldenv = __environ;
+	}
+
+	__environ[i] = s;
+	return 0;
+}
+
+int putenv(char *s)
+{
+	return __putenv(s, 0);
+}
diff --git a/src/env/setenv.c b/src/env/setenv.c
new file mode 100644
index 00000000..03e165c8
--- /dev/null
+++ b/src/env/setenv.c
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+int __putenv(char *s, int a);
+
+int setenv(const char *var, const char *value, int overwrite)
+{
+	char *s;
+	int l1, l2;
+
+	if (strchr(var, '=')) {
+		errno = EINVAL;
+		return -1;
+	}
+	if (!overwrite && getenv(var)) return 0;
+
+	l1 = strlen(var);
+	l2 = strlen(value);
+	s = malloc(l1+l2+2);
+	memcpy(s, var, l1);
+	s[l1] = '=';
+	memcpy(s+l1+1, value, l2);
+	s[l1+l2+1] = 0;
+	if (__putenv(s, 1)) {
+		free(s);
+		errno = ENOMEM;
+		return -1;
+	}
+	return 0;
+}
diff --git a/src/env/unsetenv.c b/src/env/unsetenv.c
new file mode 100644
index 00000000..7493d970
--- /dev/null
+++ b/src/env/unsetenv.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+extern char **__environ;
+extern char **__env_map;
+
+int unsetenv(const char *name)
+{
+	int i, j;
+	size_t l = strlen(name);
+
+	if (!*name || strchr(name, '=')) {
+		errno = EINVAL;
+		return -1;
+	}
+again:
+	for (i=0; __environ[i] && (memcmp(name, __environ[i], l) || __environ[i][l] != '='); i++);
+	if (__environ[i]) {
+		if (__env_map) {
+			for (j=0; __env_map[j] && __env_map[j] != __environ[i]; j++);
+			free (__env_map[j]);
+			for (; __env_map[j]; j++)
+				__env_map[j] = __env_map[j+1];
+		}
+		for (; __environ[i]; i++)
+			__environ[i] = __environ[i+1];
+		goto again;
+	}
+	return 0;
+}
diff --git a/src/errno/__errno_location.c b/src/errno/__errno_location.c
new file mode 100644
index 00000000..0a220b63
--- /dev/null
+++ b/src/errno/__errno_location.c
@@ -0,0 +1,11 @@
+#include <errno.h>
+#include "libc.h"
+
+#undef errno
+int errno;
+
+int *__errno_location(void)
+{
+	if (libc.errno_location) return libc.errno_location();
+	return &errno;
+}
diff --git a/src/errno/__strerror.h b/src/errno/__strerror.h
new file mode 100644
index 00000000..00eaf938
--- /dev/null
+++ b/src/errno/__strerror.h
@@ -0,0 +1,101 @@
+/* This file is sorted such that 'errors' which represent exceptional
+ * conditions under which a correct program may fail come first, followed
+ * by messages that indicate an incorrect program or system failure. The
+ * macro E() along with double-inclusion is used to ensure that ordering
+ * of the strings remains synchronized. */
+
+E(EILSEQ,       "Illegal byte sequence")
+E(EDOM,         "Argument outside domain")
+E(ERANGE,       "Result not representable")
+
+E(ENOTTY,       "Not a tty")
+E(EACCES,       "Permission denied")
+E(EPERM,        "Operation not permitted")
+E(ENOENT,       "No such file or directory")
+E(ESRCH,        "No such process")
+E(EEXIST,       "File exists")
+
+E(EOVERFLOW,    "Value too large for defined data type")
+E(ENOSPC,       "No space left on device")
+E(ENOMEM,       "Out of memory")
+
+E(EBUSY,        "Device or resource busy")
+E(EINTR,        "Interrupted system call")
+E(EAGAIN,       "Operation would block")
+E(ESPIPE,       "Illegal seek")
+
+E(EXDEV,        "Cross-device link")
+E(EROFS,        "Read-only file system")
+E(ENOTEMPTY,    "Directory not empty")
+
+E(ECONNRESET,   "Connection reset by peer")
+E(ETIMEDOUT,    "Connection timed out")
+E(ECONNREFUSED, "Connection refused")
+E(EHOSTDOWN,    "Host is down")
+E(EHOSTUNREACH, "No route to host")
+E(EADDRINUSE,   "Address already in use")
+
+E(EPIPE,        "Broken pipe")
+E(EIO,          "I/O error")
+E(ENXIO,        "No such device or address")
+E(ENOTBLK,      "Block device required")
+E(ENODEV,       "No such device")
+E(ENOTDIR,      "Not a directory")
+E(EISDIR,       "Is a directory")
+E(ETXTBSY,      "Text file busy")
+E(ENOEXEC,      "Exec format error")
+
+E(EINVAL,       "Invalid argument")
+
+E(E2BIG,        "Argument list too long")
+E(ELOOP,        "Too many levels of symbolic links")
+E(ENAMETOOLONG, "Filename too long")
+E(ENFILE,       "File table overflow")
+E(EMFILE,       "Too many open files")
+E(EBADF,        "Bad file number")
+E(ECHILD,       "No child processes")
+E(EFAULT,       "Bad address")
+E(EFBIG,        "File too large")
+E(EMLINK,       "Too many links")
+E(ENOLCK,       "No record locks available")
+
+E(EDEADLK,      "Resource deadlock would occur")
+E(ENOSYS,       "Function not supported")
+E(ENOMSG,       "No message of desired type")
+E(EIDRM,        "Identifier removed")
+E(ENOSTR,       "Device not a stream")
+E(ENODATA,      "No data available")
+E(ETIME,        "Timer expired")
+E(ENOSR,        "Out of streams resources")
+E(ENOLINK,      "Link has been severed")
+E(EPROTO,       "Protocol error")
+E(EBADMSG,      "Not a data message")
+E(EBADFD,       "File descriptor in bad state")
+E(ENOTSOCK,     "Socket operation on non-socket")
+E(EDESTADDRREQ, "Destination address required")
+E(EMSGSIZE,     "Message too long")
+E(EPROTOTYPE,   "Protocol wrong type for socket")
+E(ENOPROTOOPT,  "Protocol not available")
+E(EPROTONOSUPPORT,"Protocol not supported")
+E(ESOCKTNOSUPPORT,"Socket type not supported")
+E(EOPNOTSUPP,   "Operation not supported on socket")
+E(EPFNOSUPPORT, "Protocol family not supported")
+E(EAFNOSUPPORT, "Address family not supported by protocol")
+E(EADDRNOTAVAIL,"Cannot assign requested address")
+E(ENETDOWN,     "Network is down")
+E(ENETUNREACH,  "Network is unreachable")
+E(ENETRESET,    "Network dropped connection because of reset")
+E(ECONNABORTED, "Software caused connection abort")
+E(ENOBUFS,      "No buffer space available")
+E(EISCONN,      "Socket is connected")
+E(ENOTCONN,     "Socket is not connected")
+E(ESHUTDOWN,    "Cannot send after socket shutdown")
+E(EALREADY,     "Operation already in progress")
+E(EINPROGRESS,  "Operation now in progress")
+E(ESTALE,       "Stale NFS file handle")
+E(EREMOTEIO,    "Remote I/O error")
+E(EDQUOT,       "Quota exceeded")
+E(ENOMEDIUM,    "No medium found")
+E(EMEDIUMTYPE,  "Wrong medium type")
+
+E(0,            "Invalid error number")
diff --git a/src/errno/strerror.c b/src/errno/strerror.c
new file mode 100644
index 00000000..b8fbc6db
--- /dev/null
+++ b/src/errno/strerror.c
@@ -0,0 +1,22 @@
+#include <errno.h>
+#include <string.h>
+
+#define E(a,b) a,
+static const unsigned char errid[] = {
+#include "__strerror.h"
+};
+
+#undef E
+#define E(a,b) b "\0"
+static const char errmsg[] =
+#include "__strerror.h"
+;
+
+char *strerror(int e)
+{
+	const char *s;
+	int i;
+	for (i=0; errid[i] && errid[i] != e; i++);
+	for (s=errmsg; i; s++, i--) for (; *s; s++);
+	return (char *)s;
+}
diff --git a/src/exit/_Exit.c b/src/exit/_Exit.c
new file mode 100644
index 00000000..8ef85a8f
--- /dev/null
+++ b/src/exit/_Exit.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#define SYSCALL_NORETURN
+#include "syscall.h"
+
+void _Exit(int ec)
+{
+	syscall1(__NR_exit_group, ec);
+	syscall1(__NR_exit, ec);
+}
diff --git a/src/exit/abort.c b/src/exit/abort.c
new file mode 100644
index 00000000..9a1c3d40
--- /dev/null
+++ b/src/exit/abort.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <signal.h>
+
+void abort(void)
+{
+	raise(SIGABRT);
+	for (;;);
+}
diff --git a/src/exit/assert.c b/src/exit/assert.c
new file mode 100644
index 00000000..e87442a7
--- /dev/null
+++ b/src/exit/assert.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void __assert_fail(const char *expr, const char *file, int line, const char *func)
+{
+	fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line);
+	fflush(NULL);
+	abort();
+}
diff --git a/src/exit/atexit.c b/src/exit/atexit.c
new file mode 100644
index 00000000..49c060e6
--- /dev/null
+++ b/src/exit/atexit.c
@@ -0,0 +1,57 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "libc.h"
+
+/* Ensure that at least 32 atexit handlers can be registered without malloc */
+#define COUNT 32
+
+static struct fl
+{
+	struct fl *next;
+	void (*f[COUNT])(void);
+} builtin, *head;
+
+static int run_atexit_functions(void)
+{
+	int i;
+	for (; head; head=head->next) {
+		for (i=COUNT-1; i>=0 && !head->f[i]; i--);
+		for (; i>=0; i--) head->f[i]();
+	}
+	return 0;
+}
+
+int (*const __funcs_on_exit)(void) = run_atexit_functions;
+
+int atexit(void (*func)(void))
+{
+	static int lock;
+	int i;
+
+	/* Hook for atexit extensions */
+	if (libc.atexit) return libc.atexit(func);
+
+	LOCK(&lock);
+
+	/* Defer initialization of head so it can be in BSS */
+	if (!head) head = &builtin;
+
+	/* If the current function list is full, add a new one */
+	if (head->f[COUNT-1]) {
+		struct fl *new_fl = calloc(sizeof(struct fl), 1);
+		if (!new_fl) {
+			UNLOCK(&lock);
+			return -1;
+		}
+		new_fl->next = head;
+		head = new_fl;
+	}
+
+	/* Append function to the list. */
+	for (i=0; i<COUNT && head->f[i]; i++);
+	head->f[i] = func;
+
+	UNLOCK(&lock);
+	return 0;
+}
diff --git a/src/exit/exit.c b/src/exit/exit.c
new file mode 100644
index 00000000..d0c1bfc1
--- /dev/null
+++ b/src/exit/exit.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "libc.h"
+
+/* __overflow.c and atexit.c override these */
+static int (*const dummy)() = 0;
+weak_alias(dummy, __funcs_on_exit);
+weak_alias(dummy, __fflush_on_exit);
+
+void exit(int code)
+{
+	static int lock;
+
+	/* If more than one thread calls exit, hang until _Exit ends it all */
+	LOCK(&lock);
+
+	/* Only do atexit & stdio flush if they were actually used */
+	if (__funcs_on_exit) __funcs_on_exit();
+	if (__fflush_on_exit) __fflush_on_exit(0);
+
+	/* Destructor s**t is kept separate from atexit to avoid bloat */
+	if (libc.fini) libc.fini();
+	if (libc.ldso_fini) libc.ldso_fini();
+
+	_Exit(code);
+	for(;;);
+}
diff --git a/src/fcntl/creat.c b/src/fcntl/creat.c
new file mode 100644
index 00000000..be05faae
--- /dev/null
+++ b/src/fcntl/creat.c
@@ -0,0 +1,9 @@
+#include <fcntl.h>
+#include "libc.h"
+
+int creat(const char *filename, mode_t mode)
+{
+	return open(filename, O_CREAT|O_WRONLY|O_TRUNC, mode);
+}
+
+LFS64(creat);
diff --git a/src/fcntl/fcntl.c b/src/fcntl/fcntl.c
new file mode 100644
index 00000000..464dbf00
--- /dev/null
+++ b/src/fcntl/fcntl.c
@@ -0,0 +1,22 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "syscall.h"
+#include "libc.h"
+
+int fcntl(int fd, int cmd, ...)
+{
+	int r;
+	long arg;
+	va_list ap;
+	va_start(ap, cmd);
+	arg = va_arg(ap, long);
+	va_end(ap);
+	if (cmd == F_SETFL) arg |= O_LARGEFILE;
+	if (cmd == F_SETLKW) CANCELPT_BEGIN;
+	r = __syscall_fcntl(fd, cmd, arg);
+	if (cmd == F_SETLKW) CANCELPT_END;
+	return r;
+}
+
+LFS64(fcntl);
diff --git a/src/fcntl/open.c b/src/fcntl/open.c
new file mode 100644
index 00000000..4c1a591d
--- /dev/null
+++ b/src/fcntl/open.c
@@ -0,0 +1,21 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "syscall.h"
+#include "libc.h"
+
+int open(const char *filename, int flags, ...)
+{
+	int r;
+	mode_t mode;
+	va_list ap;
+	va_start(ap, flags);
+	mode = va_arg(ap, mode_t);
+	va_end(ap);
+	CANCELPT_BEGIN;
+	r = __syscall_open(filename, flags, mode);
+	CANCELPT_END;
+	return r;
+}
+
+LFS64(open);
diff --git a/src/fcntl/openat.c b/src/fcntl/openat.c
new file mode 100644
index 00000000..eefa0901
--- /dev/null
+++ b/src/fcntl/openat.c
@@ -0,0 +1,21 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "syscall.h"
+#include "libc.h"
+
+int openat(int fd, const char *filename, int flags, ...)
+{
+	int r;
+	mode_t mode;
+	va_list ap;
+	va_start(ap, flags);
+	mode = va_arg(ap, mode_t);
+	va_end(ap);
+	CANCELPT_BEGIN;
+	r = syscall4(__NR_openat, fd, (long)filename, flags|O_LARGEFILE, mode);
+	CANCELPT_END;
+	return r;
+}
+
+LFS64(openat);
diff --git a/src/internal/atomic.h b/src/internal/atomic.h
new file mode 100644
index 00000000..a15f8c2a
--- /dev/null
+++ b/src/internal/atomic.h
@@ -0,0 +1,110 @@
+#ifndef _INTERNAA_ATOMIC_H
+#define _INTERNAA_ATOMIC_H
+
+#include <stdint.h>
+
+static inline int a_ctz_64(uint64_t x)
+{
+	int r;
+	__asm__( "bsf %1,%0 ; jnz 1f ; bsf %2,%0 ; addl $32,%0\n1:"
+		: "=r"(r) : "r"((unsigned)x), "r"((unsigned)(x>>32)) );
+	return r;
+}
+
+
+static inline void a_and_64(volatile uint64_t *p, uint64_t v)
+{
+	__asm__( "lock ; andl %1, (%0) ; lock ; andl %2, 4(%0)"
+		: : "r"((long *)p), "r"((unsigned)v), "r"((unsigned)(v>>32)) );
+}
+
+static inline void a_or_64(volatile uint64_t *p, uint64_t v)
+{
+	__asm__( "lock ; orl %1, (%0) ; lock ; orl %2, 4(%0)"
+		: : "r"((long *)p), "r"((unsigned)v), "r"((unsigned)(v>>32)) );
+}
+
+static inline void a_store_l(volatile void *p, long x)
+{
+	__asm__( "movl %1, %0" : "=m"(*(long *)p) : "r"(x) : "memory" );
+}
+
+static inline void a_or_l(volatile void *p, long v)
+{
+	__asm__( "lock ; orl %1, %0"
+		: "=m"(*(long *)p) : "r"(v) );
+}
+
+static inline void *a_cas_p(volatile void *p, void *t, void *s)
+{
+	__asm__( "lock ; cmpxchg %3, %1"
+		: "=a"(t), "=m"(*(long *)p) : "a"(t), "r"(s) );
+	return t;
+}
+
+static inline long a_cas_l(volatile void *p, long t, long s)
+{
+	__asm__( "lock ; cmpxchg %3, %1"
+		: "=a"(t), "=m"(*(long *)p) : "a"(t), "r"(s) );
+	return t;
+}
+
+static inline void *a_swap_p(void *volatile *x, void *v)
+{
+	__asm__( "xchg %0, %1" : "=r"(v), "=m"(*(void **)x) : "0"(v) );
+	return v;
+}
+static inline long a_swap_l(volatile void *x, long v)
+{
+	__asm__( "xchg %0, %1" : "=r"(v), "=m"(*(long *)x) : "0"(v) );
+	return v;
+}
+
+static inline void a_or(volatile void *p, int v)
+{
+	__asm__( "lock ; orl %1, %0"
+		: "=m"(*(int *)p) : "r"(v) );
+}
+
+static inline void a_and(volatile void *p, int v)
+{
+	__asm__( "lock ; andl %1, %0"
+		: "=m"(*(int *)p) : "r"(v) );
+}
+
+static inline int a_swap(volatile int *x, int v)
+{
+	__asm__( "xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) );
+	return v;
+}
+
+#define a_xchg a_swap
+
+static inline int a_fetch_add(volatile int *x, int v)
+{
+	__asm__( "lock ; xadd %0, %1" : "=r"(v), "=m"(*x) : "0"(v) );
+	return v;
+}
+
+static inline void a_inc(volatile int *x)
+{
+	__asm__( "lock ; incl %0" : "=m"(*x) : "m"(*x) );
+}
+
+static inline void a_dec(volatile int *x)
+{
+	__asm__( "lock ; decl %0" : "=m"(*x) : "m"(*x) );
+}
+
+static inline void a_store(volatile int *p, int x)
+{
+	__asm__( "movl %1, %0" : "=m"(*p) : "r"(x) : "memory" );
+}
+
+static inline void a_spin()
+{
+	__asm__ __volatile__( "pause" : : : "memory" );
+}
+
+
+#endif
diff --git a/src/internal/clone.h b/src/internal/clone.h
new file mode 100644
index 00000000..cc84aeb4
--- /dev/null
+++ b/src/internal/clone.h
@@ -0,0 +1,22 @@
+#define CLONE_VM      0x00000100
+#define CLONE_FS      0x00000200
+#define CLONE_FILES   0x00000400
+#define CLONE_SIGHAND 0x00000800
+#define CLONE_PTRACE  0x00002000
+#define CLONE_VFORK   0x00004000
+#define CLONE_PARENT  0x00008000
+#define CLONE_THREAD  0x00010000
+#define CLONE_NEWNS   0x00020000
+#define CLONE_SYSVSEM 0x00040000
+#define CLONE_SETTLS  0x00080000
+#define CLONE_PARENT_SETTID 0x00100000
+#define CLONE_CHILD_CLEARTID 0x00200000
+#define CLONE_DETACHED 0x00400000
+#define CLONE_UNTRACED 0x00800000
+#define CLONE_CHILD_SETTID 0x01000000
+#define CLONE_NEWUTS	0x04000000
+#define CLONE_NEWIPC	0x08000000
+#define CLONE_NEWUSER	0x10000000
+#define CLONE_NEWPID	0x20000000
+#define CLONE_NEWNET	0x40000000
+#define CLONE_IO	0x80000000
diff --git a/src/internal/futex.h b/src/internal/futex.h
new file mode 100644
index 00000000..c0453822
--- /dev/null
+++ b/src/internal/futex.h
@@ -0,0 +1,16 @@
+#ifndef _INTERNAL_FUTEX_H
+#define _INTERNAL_FUTEX_H
+
+#define FUTEX_WAIT		0
+#define FUTEX_WAKE		1
+#define FUTEX_FD		2
+#define FUTEX_REQUEUE		3
+#define FUTEX_CMP_REQUEUE	4
+#define FUTEX_WAKE_OP		5
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
+
+int __futex(volatile int *, int, int, void *);
+
+#endif
diff --git a/src/internal/libc.c b/src/internal/libc.c
new file mode 100644
index 00000000..5e8e9d95
--- /dev/null
+++ b/src/internal/libc.c
@@ -0,0 +1,3 @@
+#include "libc.h"
+
+struct libc libc;
diff --git a/src/internal/libc.h b/src/internal/libc.h
new file mode 100644
index 00000000..e353f363
--- /dev/null
+++ b/src/internal/libc.h
@@ -0,0 +1,43 @@
+#ifndef LIBC_H
+#define LIBC_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define libc __libc
+extern struct libc {
+	void (*lock)(volatile int *);
+	void (*cancelpt)(int);
+	int (*atexit)(void (*)(void));
+	void (*fini)(void);
+	void (*ldso_fini)(void);
+	int *(*errno_location)(void);
+	volatile int threads_minus_1;
+	int (*rsyscall)(int, long, long, long, long, long, long);
+	void (**tsd_keys)(void *);
+} libc;
+
+
+/* Designed to avoid any overhead in non-threaded processes */
+void __lock(volatile int *);
+#define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1))
+#define UNLOCK(x) (*(x)=0)
+#define CANCELPT(x) (libc.cancelpt ? libc.cancelpt((x)),0 : (void)(x),0)
+#define CANCELPT_BEGIN CANCELPT(1)
+#define CANCELPT_END CANCELPT(0)
+
+extern char **__environ;
+#define environ __environ
+
+#undef weak_alias
+#define weak_alias(old, new) \
+	extern __typeof(old) new __attribute__((weak, alias(#old)))
+
+#undef LFS64_2
+//#define LFS64_2(x, y) weak_alias(x, y)
+#define LFS64_2(x, y) extern __typeof(x) y
+
+#undef LFS64
+#define LFS64(x) LFS64_2(x, x##64)
+
+#endif
diff --git a/src/internal/locale_impl.h b/src/internal/locale_impl.h
new file mode 100644
index 00000000..c268124f
--- /dev/null
+++ b/src/internal/locale_impl.h
@@ -0,0 +1,5 @@
+#include <locale.h>
+
+struct __locale {
+	int dummy;
+};
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
new file mode 100644
index 00000000..b7892103
--- /dev/null
+++ b/src/internal/pthread_impl.h
@@ -0,0 +1,68 @@
+#ifndef _PTHREAD_IMPL_H
+#define _PTHREAD_IMPL_H
+
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <setjmp.h>
+#include <string.h>
+#include <time.h>
+#include "libc.h"
+#include "syscall.h"
+#include "atomic.h"
+#include "futex.h"
+
+#define pthread __pthread
+
+struct pthread {
+	struct pthread *self, *join;
+	int errno_val;
+	pid_t tid, pid;
+	volatile int canceldisable, cancelasync, cancelpoint, cancel;
+	unsigned char *map_base;
+	size_t map_size;
+	void *start_arg;
+	void *(*start)(void *);
+	void *result;
+	jmp_buf exit_jmp_buf;
+	int detached;
+	int exitlock;
+	unsigned long tlsdesc[4];
+	struct __ptcb *cancelbuf;
+	void **tsd;
+	int tsd_used;
+	pthread_attr_t attr;
+	int *errno_ptr;
+};
+
+static inline struct pthread *__pthread_self()
+{
+	struct pthread *self;
+	__asm__ ("movl %%gs:0,%0" : "=r" (self) );
+	return self;
+}
+
+#define SIGCANCEL 32
+#define SIGSYSCALL 33
+#define SIGTIMER  32 /* ?? */
+
+int __set_thread_area(unsigned long *);
+int __set_pthread_self(void *);
+int __libc_sigaction(int, const struct sigaction *, struct sigaction *);
+int __libc_sigprocmask(int, const sigset_t *, sigset_t *);
+void __lock(volatile int *);
+void __unmapself(void *, size_t);
+
+int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int);
+void __wait(volatile int *, volatile int *, int, int);
+void __wake(volatile int *, int, int);
+
+#define DEFAULT_STACK_SIZE (16384-PAGE_SIZE)
+#define DEFAULT_GUARD_SIZE PAGE_SIZE
+
+#endif
diff --git a/src/internal/stdio_impl.h b/src/internal/stdio_impl.h
new file mode 100644
index 00000000..1e9159f6
--- /dev/null
+++ b/src/internal/stdio_impl.h
@@ -0,0 +1,100 @@
+#ifndef _STDIO_IMPL_H
+#define _STDIO_IMPL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <math.h>
+#include <float.h>
+#include "syscall.h"
+#include "libc.h"
+
+#define UNGET 4
+
+#define FLOCK(f) LOCK(&f->lock)
+#define FUNLOCK(f) UNLOCK(&f->lock)
+
+#define F_PERM 1
+#define F_NORD 4
+#define F_NOWR 8
+#define F_EOF 16
+#define F_ERR 32
+
+struct __FILE_s {
+	unsigned flags;
+	unsigned char *rpos, *rstop;
+	unsigned char *rend, *wend;
+	unsigned char *wpos, *wstop;
+	unsigned char *wbase;
+	unsigned char *dummy01[3];
+	unsigned char *buf;
+	size_t buf_size;
+	FILE *prev, *next;
+	int fd;
+	int pipe_pid;
+	long dummy2;
+	short dummy3;
+	char dummy4;
+	signed char lbf;
+	int lock;
+	int lockcount;
+	void *owner;
+	off_t off;
+	int (*flush)(FILE *);
+	void **wide_data; /* must be NULL */
+	size_t (*read)(FILE *, unsigned char *, size_t);
+	size_t (*write)(FILE *, const unsigned char *, size_t);
+	off_t (*seek)(FILE *, off_t, int);
+	int mode;
+	int (*close)(FILE *);
+};
+
+size_t __stdio_read(FILE *, unsigned char *, size_t);
+size_t __stdio_write(FILE *, const unsigned char *, size_t);
+off_t __stdio_seek(FILE *, off_t, int);
+int __stdio_close(FILE *);
+
+int __overflow(FILE *, int);
+int __oflow(FILE *);
+int __uflow(FILE *);
+int __underflow(FILE *);
+
+int __fseeko(FILE *, off_t, int);
+int __fseeko_unlocked(FILE *, off_t, int);
+off_t __ftello(FILE *);
+off_t __ftello_unlocked(FILE *);
+size_t __fwritex(const unsigned char *, size_t, FILE *);
+int __putc_unlocked(int, FILE *);
+
+FILE *__fdopen(int, const char *);
+
+extern struct ofl
+{
+	FILE *head;
+	int lock;
+} __ofl;
+
+#define OFLLOCK() LOCK(&__ofl.lock)
+#define OFLUNLOCK() UNLOCK(&__ofl.lock)
+#define ofl_head (__ofl.head)
+
+#define feof(f) ((f)->flags & F_EOF)
+#define ferror(f) ((f)->flags & F_ERR)
+
+/* Caller-allocated FILE * operations */
+FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t);
+int __fclose_ca(FILE *);
+
+#endif
diff --git a/src/internal/syscall.c b/src/internal/syscall.c
new file mode 100644
index 00000000..4f159e0b
--- /dev/null
+++ b/src/internal/syscall.c
@@ -0,0 +1,11 @@
+#include <errno.h>
+#include <unistd.h>
+
+long __syscall_ret(unsigned long r)
+{
+	if (r >= (unsigned long)-1 - 4096) {
+		errno = -(long)r;
+		return -1;
+	}
+	return (long)r;
+}
diff --git a/src/internal/syscall.h b/src/internal/syscall.h
new file mode 100644
index 00000000..4b3c0a73
--- /dev/null
+++ b/src/internal/syscall.h
@@ -0,0 +1,469 @@
+#ifndef _SYSCALL_H
+#define _SYSCALL_H
+
+#define SYSCALL_LL(x) \
+((union { long long ll; long l[2]; }){ .ll = x }).l[0], \
+((union { long long ll; long l[2]; }){ .ll = x }).l[1]
+
+#define SYSCALL_SIGSET_SIZE 8
+
+#if defined(SYSCALL_STANDALONE)
+#include <errno.h>
+static inline long __syscall_ret(unsigned long r)
+{
+	if (r >= (unsigned long)-1 - 4096) {
+		errno = -(long)r;
+		return -1;
+	}
+	return (long)r;
+}
+#elif defined(SYSCALL_NORETURN)
+static inline long __syscall_ret(unsigned long r)
+{
+	for(;;);
+	return 0;
+}
+#elif defined(SYSCALL_RETURN_ERRNO)
+static inline long __syscall_ret(unsigned long r)
+{
+	return -r;
+}
+#else
+extern long __syscall_ret(unsigned long);
+#endif
+
+#define SYSCALL0 "int $128"
+
+#ifdef __PIC__
+#define SYSCALL "xchgl %%ebx,%2\n\t" SYSCALL0 "\n\txchgl %%ebx,%2"
+#define EBX "m"
+#else
+#define SYSCALL SYSCALL0
+#define EBX "b"
+#endif
+
+static inline long syscall0(long n)
+{
+	unsigned long ret;
+	__asm__ __volatile__ (SYSCALL0 : "=a"(ret) : "a"(n) : "memory");
+	return __syscall_ret(ret);
+}
+
+static inline long syscall1(long n, long a1)
+{
+	unsigned long ret;
+	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1) : "memory");
+	return __syscall_ret(ret);
+}
+
+static inline long syscall2(long n, long a1, long a2)
+{
+	unsigned long ret;
+	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2) : "memory");
+	return __syscall_ret(ret);
+}
+
+static inline long syscall3(long n, long a1, long a2, long a3)
+{
+	unsigned long ret;
+	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3) : "memory");
+	return __syscall_ret(ret);
+}
+
+static inline long syscall4(long n, long a1, long a2, long a3, long a4)
+{
+	unsigned long ret;
+	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4) : "memory");
+	return __syscall_ret(ret);
+}
+
+static inline long syscall5(long n, long a1, long a2, long a3, long a4, long a5)
+{
+	unsigned long ret;
+	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory");
+	return __syscall_ret(ret);
+}
+
+#ifdef __PIC__
+/* note: it's probably only safe to use this when a6 is on the stack */
+static inline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6)
+{
+	unsigned long ret;
+	__asm__ __volatile__ ("xchgl %%ebx,%2 ; pushl %1 ; pushl %%ebp ; movl %%eax,%%ebp ; movl 4(%%esp),%%eax ; int $128 ; popl %%ebp ; popl %%ecx ; xchgl %%ebx,%2"
+		: "=a"(ret) : "g"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "a"(a6) : "memory");
+	return __syscall_ret(ret);
+}
+#else
+static inline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6)
+{
+	unsigned long ret;
+	__asm__ __volatile__ ("pushl %%ebp ; mov %1, %%ebp ; xchg %%ebp, %7 ; int $128 ; popl %%ebp"
+		: "=a"(ret) : "g"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "a"(a6) : "memory");
+	return __syscall_ret(ret);
+}
+#endif
+
+#define __NR_restart_syscall      0
+#define __NR_exit		  1
+#define __NR_fork		  2
+#define __NR_read		  3
+#define __NR_write		  4
+#define __NR_open		  5
+#define __NR_close		  6
+#define __NR_waitpid		  7
+#define __NR_creat		  8
+#define __NR_link		  9
+#define __NR_unlink		 10
+#define __NR_execve		 11
+#define __NR_chdir		 12
+#define __NR_time		 13
+#define __NR_mknod		 14
+#define __NR_chmod		 15
+#define __NR_lchown		 16
+#define __NR_break		 17
+#define __NR_oldstat		 18
+#define __NR_lseek		 19
+#define __NR_getpid		 20
+#define __NR_mount		 21
+#define __NR_umount		 22
+#define __NR_setuid		 23
+#define __NR_getuid		 24
+#define __NR_stime		 25
+#define __NR_ptrace		 26
+#define __NR_alarm		 27
+#define __NR_oldfstat		 28
+#define __NR_pause		 29
+#define __NR_utime		 30
+#define __NR_stty		 31
+#define __NR_gtty		 32
+#define __NR_access		 33
+#define __NR_nice		 34
+#define __NR_ftime		 35
+#define __NR_sync		 36
+#define __NR_kill		 37
+#define __NR_rename		 38
+#define __NR_mkdir		 39
+#define __NR_rmdir		 40
+#define __NR_dup		 41
+#define __NR_pipe		 42
+#define __NR_times		 43
+#define __NR_prof		 44
+#define __NR_brk		 45
+#define __NR_setgid		 46
+#define __NR_getgid		 47
+#define __NR_signal		 48
+#define __NR_geteuid		 49
+#define __NR_getegid		 50
+#define __NR_acct		 51
+#define __NR_umount2		 52
+#define __NR_lock		 53
+#define __NR_ioctl		 54
+#define __NR_fcntl		 55
+#define __NR_mpx		 56
+#define __NR_setpgid		 57
+#define __NR_ulimit		 58
+#define __NR_oldolduname	 59
+#define __NR_umask		 60
+#define __NR_chroot		 61
+#define __NR_ustat		 62
+#define __NR_dup2		 63
+#define __NR_getppid		 64
+#define __NR_getpgrp		 65
+#define __NR_setsid		 66
+#define __NR_sigaction		 67
+#define __NR_sgetmask		 68
+#define __NR_ssetmask		 69
+#define __NR_setreuid		 70
+#define __NR_setregid		 71
+#define __NR_sigsuspend		 72
+#define __NR_sigpending		 73
+#define __NR_sethostname	 74
+#define __NR_setrlimit		 75
+#define __NR_getrlimit		 76   /* Back compatible 2Gig limited rlimit */
+#define __NR_getrusage		 77
+#define __NR_gettimeofday	 78
+#define __NR_settimeofday	 79
+#define __NR_getgroups		 80
+#define __NR_setgroups		 81
+#define __NR_select		 82
+#define __NR_symlink		 83
+#define __NR_oldlstat		 84
+#define __NR_readlink		 85
+#define __NR_uselib		 86
+#define __NR_swapon		 87
+#define __NR_reboot		 88
+#define __NR_readdir		 89
+#define __NR_mmap		 90
+#define __NR_munmap		 91
+#define __NR_truncate		 92
+#define __NR_ftruncate		 93
+#define __NR_fchmod		 94
+#define __NR_fchown		 95
+#define __NR_getpriority	 96
+#define __NR_setpriority	 97
+#define __NR_profil		 98
+#define __NR_statfs		99
+#define __NR_fstatfs		100
+#define __NR_ioperm		101
+#define __NR_socketcall		102
+#define __NR_syslog		103
+#define __NR_setitimer		104
+#define __NR_getitimer		105
+#define __NR_stat		106
+#define __NR_lstat		107
+#define __NR_fstat		108
+#define __NR_olduname		109
+#define __NR_iopl		110
+#define __NR_vhangup		111
+#define __NR_idle		112
+#define __NR_vm86old		113
+#define __NR_wait4		114
+#define __NR_swapoff		115
+#define __NR_sysinfo		116
+#define __NR_ipc		117
+#define __NR_fsync		118
+#define __NR_sigreturn		119
+#define __NR_clone		120
+#define __NR_setdomainname	121
+#define __NR_uname		122
+#define __NR_modify_ldt		123
+#define __NR_adjtimex		124
+#define __NR_mprotect		125
+#define __NR_sigprocmask	126
+#define __NR_create_module	127
+#define __NR_init_module	128
+#define __NR_delete_module	129
+#define __NR_get_kernel_syms	130
+#define __NR_quotactl		131
+#define __NR_getpgid		132
+#define __NR_fchdir		133
+#define __NR_bdflush		134
+#define __NR_sysfs		135
+#define __NR_personality	136
+#define __NR_afs_syscall	137
+#define __NR_setfsuid		138
+#define __NR_setfsgid		139
+#define __NR__llseek		140
+#define __NR_getdents		141
+#define __NR__newselect		142
+#define __NR_flock		143
+#define __NR_msync		144
+#define __NR_readv		145
+#define __NR_writev		146
+#define __NR_getsid		147
+#define __NR_fdatasync		148
+#define __NR__sysctl		149
+#define __NR_mlock		150
+#define __NR_munlock		151
+#define __NR_mlockall		152
+#define __NR_munlockall		153
+#define __NR_sched_setparam		154
+#define __NR_sched_getparam		155
+#define __NR_sched_setscheduler		156
+#define __NR_sched_getscheduler		157
+#define __NR_sched_yield		158
+#define __NR_sched_get_priority_max	159
+#define __NR_sched_get_priority_min	160
+#define __NR_sched_rr_get_interval	161
+#define __NR_nanosleep		162
+#define __NR_mremap		163
+#define __NR_setresuid		164
+#define __NR_getresuid		165
+#define __NR_vm86		166
+#define __NR_query_module	167
+#define __NR_poll		168
+#define __NR_nfsservctl		169
+#define __NR_setresgid		170
+#define __NR_getresgid		171
+#define __NR_prctl              172
+#define __NR_rt_sigreturn	173
+#define __NR_rt_sigaction	174
+#define __NR_rt_sigprocmask	175
+#define __NR_rt_sigpending	176
+#define __NR_rt_sigtimedwait	177
+#define __NR_rt_sigqueueinfo	178
+#define __NR_rt_sigsuspend	179
+#define __NR_pread64		180
+#define __NR_pwrite64		181
+#define __NR_chown		182
+#define __NR_getcwd		183
+#define __NR_capget		184
+#define __NR_capset		185
+#define __NR_sigaltstack	186
+#define __NR_sendfile		187
+#define __NR_getpmsg		188
+#define __NR_putpmsg		189
+#define __NR_vfork		190
+#define __NR_ugetrlimit		191
+#define __NR_mmap2		192
+#define __NR_truncate64		193
+#define __NR_ftruncate64	194
+#define __NR_stat64		195
+#define __NR_lstat64		196
+#define __NR_fstat64		197
+#define __NR_lchown32		198
+#define __NR_getuid32		199
+#define __NR_getgid32		200
+#define __NR_geteuid32		201
+#define __NR_getegid32		202
+#define __NR_setreuid32		203
+#define __NR_setregid32		204
+#define __NR_getgroups32	205
+#define __NR_setgroups32	206
+#define __NR_fchown32		207
+#define __NR_setresuid32	208
+#define __NR_getresuid32	209
+#define __NR_setresgid32	210
+#define __NR_getresgid32	211
+#define __NR_chown32		212
+#define __NR_setuid32		213
+#define __NR_setgid32		214
+#define __NR_setfsuid32		215
+#define __NR_setfsgid32		216
+#define __NR_pivot_root		217
+#define __NR_mincore		218
+#define __NR_madvise		219
+#define __NR_madvise1		219
+#define __NR_getdents64		220
+#define __NR_fcntl64		221
+/* 223 is unused */
+#define __NR_gettid		224
+#define __NR_readahead		225
+#define __NR_setxattr		226
+#define __NR_lsetxattr		227
+#define __NR_fsetxattr		228
+#define __NR_getxattr		229
+#define __NR_lgetxattr		230
+#define __NR_fgetxattr		231
+#define __NR_listxattr		232
+#define __NR_llistxattr		233
+#define __NR_flistxattr		234
+#define __NR_removexattr	235
+#define __NR_lremovexattr	236
+#define __NR_fremovexattr	237
+#define __NR_tkill		238
+#define __NR_sendfile64		239
+#define __NR_futex		240
+#define __NR_sched_setaffinity	241
+#define __NR_sched_getaffinity	242
+#define __NR_set_thread_area	243
+#define __NR_get_thread_area	244
+#define __NR_io_setup		245
+#define __NR_io_destroy		246
+#define __NR_io_getevents	247
+#define __NR_io_submit		248
+#define __NR_io_cancel		249
+#define __NR_fadvise64		250
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
+#define __NR_exit_group		252
+#define __NR_lookup_dcookie	253
+#define __NR_epoll_create	254
+#define __NR_epoll_ctl		255
+#define __NR_epoll_wait		256
+#define __NR_remap_file_pages	257
+#define __NR_set_tid_address	258
+#define __NR_timer_create	259
+#define __NR_timer_settime	(__NR_timer_create+1)
+#define __NR_timer_gettime	(__NR_timer_create+2)
+#define __NR_timer_getoverrun	(__NR_timer_create+3)
+#define __NR_timer_delete	(__NR_timer_create+4)
+#define __NR_clock_settime	(__NR_timer_create+5)
+#define __NR_clock_gettime	(__NR_timer_create+6)
+#define __NR_clock_getres	(__NR_timer_create+7)
+#define __NR_clock_nanosleep	(__NR_timer_create+8)
+#define __NR_statfs64		268
+#define __NR_fstatfs64		269
+#define __NR_tgkill		270
+#define __NR_utimes		271
+#define __NR_fadvise64_64	272
+#define __NR_vserver		273
+#define __NR_mbind		274
+#define __NR_get_mempolicy	275
+#define __NR_set_mempolicy	276
+#define __NR_mq_open 		277
+#define __NR_mq_unlink		(__NR_mq_open+1)
+#define __NR_mq_timedsend	(__NR_mq_open+2)
+#define __NR_mq_timedreceive	(__NR_mq_open+3)
+#define __NR_mq_notify		(__NR_mq_open+4)
+#define __NR_mq_getsetattr	(__NR_mq_open+5)
+#define __NR_kexec_load		283
+#define __NR_waitid		284
+/* #define __NR_sys_setaltroot	285 */
+#define __NR_add_key		286
+#define __NR_request_key	287
+#define __NR_keyctl		288
+#define __NR_ioprio_set		289
+#define __NR_ioprio_get		290
+#define __NR_inotify_init	291
+#define __NR_inotify_add_watch	292
+#define __NR_inotify_rm_watch	293
+#define __NR_migrate_pages	294
+#define __NR_openat		295
+#define __NR_mkdirat		296
+#define __NR_mknodat		297
+#define __NR_fchownat		298
+#define __NR_futimesat		299
+#define __NR_fstatat64		300
+#define __NR_unlinkat		301
+#define __NR_renameat		302
+#define __NR_linkat		303
+#define __NR_symlinkat		304
+#define __NR_readlinkat		305
+#define __NR_fchmodat		306
+#define __NR_faccessat		307
+#define __NR_pselect6		308
+#define __NR_ppoll		309
+#define __NR_unshare		310
+#define __NR_set_robust_list	311
+#define __NR_get_robust_list	312
+#define __NR_splice		313
+#define __NR_sync_file_range	314
+#define __NR_tee		315
+#define __NR_vmsplice		316
+#define __NR_move_pages		317
+#define __NR_getcpu		318
+#define __NR_epoll_pwait	319
+#define __NR_utimensat		320
+#define __NR_signalfd		321
+#define __NR_timerfd_create	322
+#define __NR_eventfd		323
+#define __NR_fallocate		324
+#define __NR_timerfd_settime	325
+#define __NR_timerfd_gettime	326
+#define __NR_signalfd4		327
+#define __NR_eventfd2		328
+#define __NR_epoll_create1	329
+#define __NR_dup3		330
+#define __NR_pipe2		331
+#define __NR_inotify_init1	332
+#define __NR_preadv		333
+#define __NR_pwritev		334
+
+
+#undef O_LARGEFILE
+#define O_LARGEFILE 0100000
+
+/* the following are needed for iso c functions to use */
+#define __syscall_open(filename, flags, mode) syscall3(__NR_open, (long)(filename), (flags)|O_LARGEFILE, (mode))
+#define __syscall_read(fd, buf, len)          syscall3(__NR_read, (fd), (long)(buf), (len))
+#define __syscall_write(fd, buf, len)         syscall3(__NR_write, (fd), (long)(buf), (len))
+#define __syscall_close(fd)                   syscall1(__NR_close, (fd))
+#define __syscall_fcntl(fd, cmd, arg)         syscall3(__NR_fcntl64, (fd), (cmd), (long)(arg))
+#define __syscall_dup2(old, new)              syscall2(__NR_dup2, (old), (new))
+#define __syscall_unlink(path)                syscall1(__NR_unlink, (long)(path))
+#define __syscall_getpid()                    syscall0(__NR_getpid)
+#define __syscall_kill(pid,sig)               syscall2(__NR_kill, (pid), (sig))
+#define __syscall_sigaction(sig,new,old)      syscall4(__NR_rt_sigaction, (sig), (long)(new), (long)(old), SYSCALL_SIGSET_SIZE)
+#define __syscall_ioctl(fd,ioc,arg)           syscall3(__NR_ioctl, (fd), (ioc), (long)(arg))
+#define __syscall_exit(code)                  syscall1(__NR_exit, code)
+
+#define __NEED_off_t
+#include <bits/alltypes.h>
+
+static inline off_t __syscall_lseek(int fd, off_t offset, int whence)
+{
+	off_t result;
+	return syscall5(__NR__llseek, fd, offset>>32, offset, (long)&result, whence) ? -1 : result;
+}
+
+#endif
diff --git a/src/internal/util.h b/src/internal/util.h
new file mode 100644
index 00000000..7c7c3a17
--- /dev/null
+++ b/src/internal/util.h
@@ -0,0 +1,5 @@
+#ifndef _INTERNAL_UTIL_H
+#define _INTERNAL_UTIL_H
+
+
+#endif
diff --git a/src/ipc/ftok.c b/src/ipc/ftok.c
new file mode 100644
index 00000000..cd6002ed
--- /dev/null
+++ b/src/ipc/ftok.c
@@ -0,0 +1,10 @@
+#include <sys/ipc.h>
+#include <sys/stat.h>
+
+key_t ftok(const char *path, int id)
+{
+	struct stat st;
+	if (stat(path, &st) < 0) return -1;
+
+	return ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 0xff) << 24));
+}
diff --git a/src/ipc/ipc.h b/src/ipc/ipc.h
new file mode 100644
index 00000000..9edd5ecf
--- /dev/null
+++ b/src/ipc/ipc.h
@@ -0,0 +1,13 @@
+#define IPCOP_semop      1
+#define IPCOP_semget     2
+#define IPCOP_semctl     3
+#define IPCOP_msgsnd    11
+#define IPCOP_msgrcv    12
+#define IPCOP_msgget    13
+#define IPCOP_msgctl    14
+#define IPCOP_shmat     21
+#define IPCOP_shmdt     22
+#define IPCOP_shmget    23
+#define IPCOP_shmctl    24
+
+#define IPC_MODERN   0x100
diff --git a/src/ipc/semctl.c b/src/ipc/semctl.c
new file mode 100644
index 00000000..7ada116b
--- /dev/null
+++ b/src/ipc/semctl.c
@@ -0,0 +1,18 @@
+#include <sys/sem.h>
+#include <stdarg.h>
+#include "syscall.h"
+#include "ipc.h"
+
+int semctl(int id, int num, int cmd, ...)
+{
+	long arg;
+	va_list ap;
+	va_start(ap, cmd);
+	arg = va_arg(ap, long);
+	va_end(ap);
+#ifdef __NR_semctl
+	return syscall4(__NR_semctl, id, num, cmd, arg);
+#else
+	return syscall5(__NR_ipc, IPCOP_semctl, id, num, cmd | 0x100, (long)&arg);
+#endif
+}
diff --git a/src/ipc/semget.c b/src/ipc/semget.c
new file mode 100644
index 00000000..2dcf6eac
--- /dev/null
+++ b/src/ipc/semget.c
@@ -0,0 +1,12 @@
+#include <sys/sem.h>
+#include "syscall.h"
+#include "ipc.h"
+
+int semget(key_t key, int n, int fl)
+{
+#ifdef __NR_semget
+	return syscall3(__NR_semget, key, n, fl);
+#else
+	return syscall4(__NR_ipc, IPCOP_semget, key, n, fl);
+#endif
+}
diff --git a/src/ipc/semop.c b/src/ipc/semop.c
new file mode 100644
index 00000000..48d8a654
--- /dev/null
+++ b/src/ipc/semop.c
@@ -0,0 +1,12 @@
+#include <sys/sem.h>
+#include "syscall.h"
+#include "ipc.h"
+
+int semop(int id, struct sembuf *buf, size_t n)
+{
+#ifdef __NR_semop
+	return syscall3(__NR_semop, id, (long)buf, n);
+#else
+	return syscall5(__NR_ipc, IPCOP_semop, id, n, 0, (long)buf);
+#endif
+}
diff --git a/src/ipc/shmat.c b/src/ipc/shmat.c
new file mode 100644
index 00000000..ff65b6a4
--- /dev/null
+++ b/src/ipc/shmat.c
@@ -0,0 +1,17 @@
+#include <sys/shm.h>
+#include "syscall.h"
+#include "ipc.h"
+
+#ifdef __NR_shmat
+void *shmat(int id, const void *addr, int flag)
+{
+	return syscall3(__NR_shmat, id, (long)addr, flag);
+}
+#else
+void *shmat(int id, const void *addr, int flag)
+{
+	unsigned long ret;
+	ret = syscall5(__NR_ipc, IPCOP_shmat, id, flag, (long)&addr, (long)addr);
+	return (ret > -(unsigned long)SHMLBA) ? (void *)ret : (void *)addr;
+}
+#endif
diff --git a/src/ipc/shmctl.c b/src/ipc/shmctl.c
new file mode 100644
index 00000000..da357fa8
--- /dev/null
+++ b/src/ipc/shmctl.c
@@ -0,0 +1,12 @@
+#include <sys/shm.h>
+#include "syscall.h"
+#include "ipc.h"
+
+int shmctl(int id, int cmd, struct shmid_ds *buf)
+{
+#ifdef __NR_shmctl
+	return syscall3(__NR_shmctl, id, cmd, (long)buf);
+#else
+	return syscall4(__NR_ipc, IPCOP_shmctl, id, cmd | IPC_MODERN, (long)buf);
+#endif
+}
diff --git a/src/ipc/shmdt.c b/src/ipc/shmdt.c
new file mode 100644
index 00000000..e04188f9
--- /dev/null
+++ b/src/ipc/shmdt.c
@@ -0,0 +1,12 @@
+#include <sys/shm.h>
+#include "syscall.h"
+#include "ipc.h"
+
+int shmdt(const void *addr)
+{
+#ifdef __NR_shmdt
+	return syscall1(__NR_shmdt, (long)addr);
+#else
+	return syscall2(__NR_ipc, IPCOP_shmdt, (long)addr);
+#endif
+}
diff --git a/src/ipc/shmget.c b/src/ipc/shmget.c
new file mode 100644
index 00000000..86e254af
--- /dev/null
+++ b/src/ipc/shmget.c
@@ -0,0 +1,12 @@
+#include <sys/shm.h>
+#include "syscall.h"
+#include "ipc.h"
+
+int shmget(key_t key, size_t size, int flag)
+{
+#ifdef __NR_shmget
+	return syscall3(__NR_shmget, key, size, flag);
+#else
+	return syscall4(__NR_ipc, IPCOP_shmget, key, size, flag);
+#endif
+}
diff --git a/src/linux/brk.c b/src/linux/brk.c
new file mode 100644
index 00000000..3c2982c6
--- /dev/null
+++ b/src/linux/brk.c
@@ -0,0 +1,6 @@
+#include "syscall.h"
+
+int brk(void *end)
+{
+	return -(syscall1(__NR_brk, (long)end) == -1);
+}
diff --git a/src/linux/chroot.c b/src/linux/chroot.c
new file mode 100644
index 00000000..b5af62dc
--- /dev/null
+++ b/src/linux/chroot.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int chroot(const char *path)
+{
+	return syscall1(__NR_chroot, (long)path);
+}
diff --git a/src/linux/daemon.c b/src/linux/daemon.c
new file mode 100644
index 00000000..632d1203
--- /dev/null
+++ b/src/linux/daemon.c
@@ -0,0 +1,31 @@
+#include <fcntl.h>
+#include <unistd.h>
+
+int daemon(int nochdir, int noclose)
+{
+	int fd;
+
+	switch(fork()) {
+	case 0: break;
+	case -1: return -1;
+	default: _exit(0);
+	}
+
+	if (setsid() < 0) return -1;
+
+	switch(fork()) {
+	case 0: break;
+	case -1: return -1;
+	default: _exit(0);
+	}
+
+	if (!nochdir) chdir("/");
+	if (!noclose && (fd = open("/dev/null", O_RDWR)) >= 0) {
+		dup2(fd, 0);
+		dup2(fd, 1);
+		dup2(fd, 2);
+		if (fd > 2) close(fd);
+	}
+
+	return 0;
+}
diff --git a/src/linux/epoll_create.c b/src/linux/epoll_create.c
new file mode 100644
index 00000000..c9dea8ce
--- /dev/null
+++ b/src/linux/epoll_create.c
@@ -0,0 +1,7 @@
+#include <sys/epoll.h>
+#include "syscall.h"
+
+int epoll_create(int size)
+{
+	return syscall1(__NR_epoll_create, size);
+}
diff --git a/src/linux/epoll_create1.c b/src/linux/epoll_create1.c
new file mode 100644
index 00000000..2e82e995
--- /dev/null
+++ b/src/linux/epoll_create1.c
@@ -0,0 +1,7 @@
+#include <sys/epoll.h>
+#include "syscall.h"
+
+int epoll_create1(int flags)
+{
+	return syscall1(__NR_epoll_create1, flags);
+}
diff --git a/src/linux/epoll_ctl.c b/src/linux/epoll_ctl.c
new file mode 100644
index 00000000..4214f407
--- /dev/null
+++ b/src/linux/epoll_ctl.c
@@ -0,0 +1,7 @@
+#include <sys/epoll.h>
+#include "syscall.h"
+
+int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
+{
+	return syscall4(__NR_epoll_ctl, fd, op, fd2, (long)ev);
+}
diff --git a/src/linux/epoll_pwait.c b/src/linux/epoll_pwait.c
new file mode 100644
index 00000000..5aaacba6
--- /dev/null
+++ b/src/linux/epoll_pwait.c
@@ -0,0 +1,7 @@
+#include <sys/epoll.h>
+#include "syscall.h"
+
+int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, const sigset_t *sigs)
+{
+	return syscall6(__NR_epoll_pwait, fd, (long)ev, cnt, to, (long)sigs, 8);
+}
diff --git a/src/linux/epoll_wait.c b/src/linux/epoll_wait.c
new file mode 100644
index 00000000..8a68ebdd
--- /dev/null
+++ b/src/linux/epoll_wait.c
@@ -0,0 +1,7 @@
+#include <sys/epoll.h>
+#include "syscall.h"
+
+int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
+{
+	return syscall4(__NR_epoll_wait, fd, (long)ev, cnt, to);
+}
diff --git a/src/linux/getdtablesize.c b/src/linux/getdtablesize.c
new file mode 100644
index 00000000..623a6af3
--- /dev/null
+++ b/src/linux/getdtablesize.c
@@ -0,0 +1,9 @@
+#include <limits.h>
+#include <sys/resource.h>
+
+int getdtablesize(void)
+{
+	struct rlimit rl;
+	getrlimit(RLIMIT_NOFILE, &rl);
+	return rl.rlim_max < INT_MAX ? rl.rlim_max : INT_MAX;
+}
diff --git a/src/linux/gethostid.c b/src/linux/gethostid.c
new file mode 100644
index 00000000..ea65611a
--- /dev/null
+++ b/src/linux/gethostid.c
@@ -0,0 +1,4 @@
+long gethostid()
+{
+	return 0;
+}
diff --git a/src/linux/getopt_long.c b/src/linux/getopt_long.c
new file mode 100644
index 00000000..d80cd1b6
--- /dev/null
+++ b/src/linux/getopt_long.c
@@ -0,0 +1,52 @@
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <getopt.h>
+#include <stdio.h>
+
+static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
+{
+	if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1;
+	if ((longonly && argv[optind][1]) ||
+		(argv[optind][1] == '-' && argv[optind][2]))
+	{
+		int i;
+		for (i=0; longopts[i].name; i++) {
+			const char *name = longopts[i].name;
+			char *opt = argv[optind]+1;
+			if (*opt == '-') opt++;
+			while (*name && *name++ == *opt++);
+			if (*name || (*opt && *opt != '=')) continue;
+			if (*opt == '=') {
+				if (!longopts[i].has_arg) continue;
+				optarg = opt+1;
+			} else {
+				if (longopts[i].has_arg == required_argument) {
+					if (!(optarg = argv[++optind]))
+						return ':';
+				} else optarg = NULL;
+			}
+			optind++;
+			if (idx) *idx = i;
+			if (longopts[i].flag) {
+				*longopts[i].flag = longopts[i].val;
+				return 0;
+			}
+			return longopts[i].val;
+		}
+		if (argv[optind][1] == '-') {
+			optind++;
+			return '?';
+		}
+	}
+	return getopt(argc, argv, optstring);
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+	return __getopt_long(argc, argv, optstring, longopts, idx, 0);
+}
+
+int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+	return __getopt_long(argc, argv, optstring, longopts, idx, 1);
+}
diff --git a/src/linux/getpagesize.c b/src/linux/getpagesize.c
new file mode 100644
index 00000000..5ede652b
--- /dev/null
+++ b/src/linux/getpagesize.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <limits.h>
+
+int getpagesize(void)
+{
+	return PAGE_SIZE;
+}
diff --git a/src/linux/getpass.c b/src/linux/getpass.c
new file mode 100644
index 00000000..d439a2a5
--- /dev/null
+++ b/src/linux/getpass.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+char *getpass(const char *prompt)
+{
+	int fd;
+	struct termios s, t;
+	ssize_t l;
+	static char password[128];
+
+	if ((fd = open("/dev/tty", O_RDONLY|O_NOCTTY)) < 0) fd = 0;
+
+	tcgetattr(fd, &t);
+	s = t;
+	t.c_lflag &= ~(ECHO|ISIG);
+	t.c_lflag |= ICANON;
+	t.c_iflag &= ~(INLCR|IGNCR);
+	t.c_iflag |= ICRNL;
+	tcsetattr(fd, TCSAFLUSH, &t);
+	tcdrain(fd);
+
+	fputs(prompt, stderr);
+	fflush(stderr);
+
+	l = read(fd, password, sizeof password);
+	if (l >= 0) {
+		if (l > 0 && password[l-1] == '\n') l--;
+		password[l] = 0;
+	}
+
+	tcsetattr(fd, TCSAFLUSH, &s);
+
+	if (fd > 2) close(fd);
+
+	return password;
+}
diff --git a/src/linux/initgroups.c b/src/linux/initgroups.c
new file mode 100644
index 00000000..ef9bc10a
--- /dev/null
+++ b/src/linux/initgroups.c
@@ -0,0 +1,15 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+#include <limits.h>
+
+int getgrouplist(const char *, gid_t, gid_t *, int *);
+int setgroups(size_t, const gid_t *);
+
+int initgroups(const char *user, gid_t gid)
+{
+	gid_t groups[NGROUPS_MAX];
+	int count;
+	if (getgrouplist(user, gid, groups, &count) < 0) return -1;
+	return setgroups(count, groups);
+}
diff --git a/src/linux/klogctl.c b/src/linux/klogctl.c
new file mode 100644
index 00000000..6c288aff
--- /dev/null
+++ b/src/linux/klogctl.c
@@ -0,0 +1,7 @@
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int klogctl (int type, char *buf, int len)
+{
+	return syscall3(__NR_syslog, type, (long)buf, len);
+}
diff --git a/src/linux/mntent.c b/src/linux/mntent.c
new file mode 100644
index 00000000..e3735666
--- /dev/null
+++ b/src/linux/mntent.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <mntent.h>
+
+FILE *setmntent(const char *name, const char *mode)
+{
+	return fopen(name, mode);
+}
+
+int endmntent(FILE *f)
+{
+	fclose(f);
+	return 1;
+}
+
+struct mntent *getmntent(FILE *f)
+{
+	static char linebuf[256];
+	static struct mntent mnt;
+	int cnt, n[8];
+
+	mnt.mnt_freq = 0;
+	mnt.mnt_passno = 0;
+
+	do {
+		fgets(linebuf, sizeof linebuf, f);
+		if (feof(f)) return NULL;
+		cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
+			n, n+1, n+2, n+3, n+4, n+5, n+6, n+7,
+			&mnt.mnt_freq, &mnt.mnt_passno);
+	} while (cnt >= 8 && linebuf[n[0]] != '#');
+
+	linebuf[n[1]] = 0;
+	linebuf[n[3]] = 0;
+	linebuf[n[5]] = 0;
+	linebuf[n[7]] = 0;
+
+	mnt.mnt_fsname = linebuf+n[0];
+	mnt.mnt_dir = linebuf+n[2];
+	mnt.mnt_type = linebuf+n[4];
+	mnt.mnt_opts = linebuf+n[6];
+
+	return &mnt;
+}
+
+int addmntent(FILE *f, const struct mntent *mnt)
+{
+	fseek(f, 0, SEEK_END);
+	return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n",
+		mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts,
+		mnt->mnt_freq, mnt->mnt_passno) < 0;
+}
+
+char *hasmntopt(const struct mntent *mnt, const char *opt)
+{
+	return strstr(mnt->mnt_opts, opt);
+}
diff --git a/src/linux/mount.c b/src/linux/mount.c
new file mode 100644
index 00000000..61299d48
--- /dev/null
+++ b/src/linux/mount.c
@@ -0,0 +1,8 @@
+#include <sys/mount.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int mount(const char *special, const char *dir, const char *fstype, unsigned long flags, const void *data)
+{
+	return syscall5(__NR_mount, (long)special, (long)dir, (long)fstype, flags, (long)data);
+}
diff --git a/src/linux/prctl.c b/src/linux/prctl.c
new file mode 100644
index 00000000..d5516830
--- /dev/null
+++ b/src/linux/prctl.c
@@ -0,0 +1,13 @@
+#include <sys/prctl.h>
+#include <stdarg.h>
+#include "syscall.h"
+
+int prctl(int op, ...)
+{
+	unsigned long x[4];
+	int i;
+	va_list ap;
+	va_start(ap, op);
+	for (i=0; i<4; i++) x[i] = va_arg(ap, unsigned long);
+	return syscall5(__NR_prctl, op, x[0], x[1], x[2], x[3]);
+}
diff --git a/src/linux/reboot.c b/src/linux/reboot.c
new file mode 100644
index 00000000..68830d8e
--- /dev/null
+++ b/src/linux/reboot.c
@@ -0,0 +1,8 @@
+#include <sys/reboot.h>
+#include <errno.h>
+
+int reboot(int type)
+{
+	errno = ENOSYS;
+	return -1;
+}
diff --git a/src/linux/sbrk.c b/src/linux/sbrk.c
new file mode 100644
index 00000000..56f60d1b
--- /dev/null
+++ b/src/linux/sbrk.c
@@ -0,0 +1,7 @@
+#include <stddef.h>
+#include "syscall.h"
+
+void *sbrk(ptrdiff_t inc)
+{
+	return (void *)syscall1(__NR_brk, syscall1(__NR_brk, 0)+inc);
+}
diff --git a/src/linux/sendfile.c b/src/linux/sendfile.c
new file mode 100644
index 00000000..bfbc40ae
--- /dev/null
+++ b/src/linux/sendfile.c
@@ -0,0 +1,10 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+ssize_t sendfile(int out_fd, int in_fd, off_t *ofs, size_t count)
+{
+	return syscall4(__NR_sendfile, out_fd, in_fd, (long)ofs, count);
+}
+
+LFS64(sendfile);
diff --git a/src/linux/setgroups.c b/src/linux/setgroups.c
new file mode 100644
index 00000000..2368aa0d
--- /dev/null
+++ b/src/linux/setgroups.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int setgroups(int count, const gid_t list[])
+{
+	/* this depends on our gid_t being 32bit */
+	return syscall2(__NR_setgroups32, count, (long)list);
+}
diff --git a/src/linux/sethostname.c b/src/linux/sethostname.c
new file mode 100644
index 00000000..f61e0cb4
--- /dev/null
+++ b/src/linux/sethostname.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int sethostname(const char *name, size_t len)
+{
+	return syscall2(__NR_sethostname, (long)name, len);
+}
diff --git a/src/linux/settimeofday.c b/src/linux/settimeofday.c
new file mode 100644
index 00000000..bd7e4104
--- /dev/null
+++ b/src/linux/settimeofday.c
@@ -0,0 +1,7 @@
+#include <sys/time.h>
+#include "syscall.h"
+
+int settimeofday(const struct timeval *tv, void *tz)
+{
+	return syscall2(__NR_settimeofday, (long)tv, 0);
+}
diff --git a/src/linux/signalfd.c b/src/linux/signalfd.c
new file mode 100644
index 00000000..ecda263e
--- /dev/null
+++ b/src/linux/signalfd.c
@@ -0,0 +1,7 @@
+#include <sys/signalfd.h>
+#include "syscall.h"
+
+int signalfd(int fd, const sigset_t *sigs, int flags)
+{
+	return syscall3(__NR_signalfd, fd, (long)sigs, 8);
+}
diff --git a/src/linux/stime.c b/src/linux/stime.c
new file mode 100644
index 00000000..ec3ba821
--- /dev/null
+++ b/src/linux/stime.c
@@ -0,0 +1,7 @@
+#include <sys/time.h>
+
+int stime(time_t *t)
+{
+	struct timeval tv = { .tv_sec = *t, .tv_usec = 0 };
+	return settimeofday(&tv, (void *)0);
+}
diff --git a/src/linux/swapoff.c b/src/linux/swapoff.c
new file mode 100644
index 00000000..f6fa794e
--- /dev/null
+++ b/src/linux/swapoff.c
@@ -0,0 +1,8 @@
+#include <sys/swap.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int swapoff(const char *path)
+{
+	return syscall1(__NR_swapoff, (long)path);
+}
diff --git a/src/linux/swapon.c b/src/linux/swapon.c
new file mode 100644
index 00000000..13d2876b
--- /dev/null
+++ b/src/linux/swapon.c
@@ -0,0 +1,8 @@
+#include <sys/swap.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int swapon(const char *path, int flags)
+{
+	return syscall2(__NR_swapon, (long)path, flags);
+}
diff --git a/src/linux/sysinfo.c b/src/linux/sysinfo.c
new file mode 100644
index 00000000..98669472
--- /dev/null
+++ b/src/linux/sysinfo.c
@@ -0,0 +1,9 @@
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+struct sysinfo;
+
+int sysinfo(struct sysinfo *info)
+{
+	return syscall1(__NR_sysinfo, (long)info);
+}
diff --git a/src/linux/umount.c b/src/linux/umount.c
new file mode 100644
index 00000000..c35f994d
--- /dev/null
+++ b/src/linux/umount.c
@@ -0,0 +1,8 @@
+#include <sys/mount.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int umount(const char *special)
+{
+	return syscall1(__NR_umount, (long)special);
+}
diff --git a/src/linux/umount2.c b/src/linux/umount2.c
new file mode 100644
index 00000000..cab93fd0
--- /dev/null
+++ b/src/linux/umount2.c
@@ -0,0 +1,8 @@
+#include <sys/mount.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int umount2(const char *special, int flags)
+{
+	return syscall2(__NR_umount2, (long)special, flags);
+}
diff --git a/src/linux/utimes.c b/src/linux/utimes.c
new file mode 100644
index 00000000..99a3b2b8
--- /dev/null
+++ b/src/linux/utimes.c
@@ -0,0 +1,13 @@
+#include <sys/time.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+int utimes(const char *path, const struct timeval times[2])
+{
+	long ktimes[2];
+	if (times) {
+		ktimes[0] = times[0].tv_sec;
+		ktimes[1] = times[1].tv_sec;
+	}
+	return syscall2(__NR_utime, (long)path, times ? (long)ktimes : 0);
+}
diff --git a/src/linux/wait3.c b/src/linux/wait3.c
new file mode 100644
index 00000000..dd63707c
--- /dev/null
+++ b/src/linux/wait3.c
@@ -0,0 +1,11 @@
+#include <sys/wait.h>
+#include <sys/resource.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+pid_t wait4(pid_t, int *, int, struct rusage *);
+
+pid_t wait3(int *status, int options, struct rusage *usage)
+{
+	return wait4(-1, status, options, usage);
+}
diff --git a/src/linux/wait4.c b/src/linux/wait4.c
new file mode 100644
index 00000000..dda942d3
--- /dev/null
+++ b/src/linux/wait4.c
@@ -0,0 +1,19 @@
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <string.h>
+#define SYSCALL_STANDALONE
+#include "syscall.h"
+
+pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage)
+{
+	pid_t ret = syscall4(__NR_wait4, pid, (long)status, options, (long)usage);
+	/* Fixup kernel time_t... */
+	if (usage) {
+		long kusage[4];
+		memcpy(kusage, usage, sizeof kusage);
+		memmove((struct timeval *)usage + 2, (long *)usage + 4, sizeof *usage - 2*sizeof(struct timeval));
+		usage->ru_utime = (struct timeval){ kusage[0], kusage[1] };
+		usage->ru_stime = (struct timeval){ kusage[2], kusage[3] };
+	}
+	return ret;
+}
diff --git a/src/locale/catclose.c b/src/locale/catclose.c
new file mode 100644
index 00000000..02cd3e5c
--- /dev/null
+++ b/src/locale/catclose.c
@@ -0,0 +1,6 @@
+#include <nl_types.h>
+
+int catclose (nl_catd catd)
+{
+	return 0;
+}
diff --git a/src/locale/catgets.c b/src/locale/catgets.c
new file mode 100644
index 00000000..bbee8986
--- /dev/null
+++ b/src/locale/catgets.c
@@ -0,0 +1,6 @@
+#include <nl_types.h>
+
+char *catgets (nl_catd catd, int set_id, int msg_id, const char *s)
+{
+	return (char *)s;
+}
diff --git a/src/locale/catopen.c b/src/locale/catopen.c
new file mode 100644
index 00000000..4423c4d9
--- /dev/null
+++ b/src/locale/catopen.c
@@ -0,0 +1,6 @@
+#include <nl_types.h>
+
+nl_catd catopen (const char *name, int oflag)
+{
+	return (nl_catd)-1;
+}
diff --git a/src/locale/duplocale.c b/src/locale/duplocale.c
new file mode 100644
index 00000000..dd445d46
--- /dev/null
+++ b/src/locale/duplocale.c
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+#include <string.h>
+#include "locale_impl.h"
+
+locale_t duplocale(locale_t old)
+{
+	locale_t new;
+	new = calloc(1, sizeof *new);
+	if (new) memcpy(new, old, sizeof *new);
+	return new;
+}
diff --git a/src/locale/freelocale.c b/src/locale/freelocale.c
new file mode 100644
index 00000000..4e089f22
--- /dev/null
+++ b/src/locale/freelocale.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+#include "locale_impl.h"
+
+void freelocale(locale_t l)
+{
+	free(l);
+}
diff --git a/src/locale/iconv.c b/src/locale/iconv.c
new file mode 100644
index 00000000..4e46c7e4
--- /dev/null
+++ b/src/locale/iconv.c
@@ -0,0 +1,568 @@
+#include <iconv.h>
+#include <errno.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+
+#define UTF_32BE    000
+#define UTF_16LE    001
+#define UTF_16BE    002
+#define UTF_32LE    003
+#define UCS2BE      004
+#define UCS2LE      005
+#define WCHAR_T     007
+
+#define US_ASCII    021
+#define UTF_8       022
+#define LATIN_9     024
+#define TIS_620     025
+#define JIS_0201    026
+
+#define EUC         031
+#define EUC_TW      032
+#define SHIFT_JIS   033
+#define BIG5        034
+#define GBK         035
+
+/* FIXME: these are not implemented yet
+ * EUC:   A1-FE A1-FE
+ * GBK:   81-FE 40-7E,80-FE
+ * Big5:  A1-FE 40-7E,A1-FE
+ */
+
+/* Definitions of charmaps. Each charmap consists of:
+ * 1. Empty-string-terminated list of null-terminated aliases.
+ * 2. Special type code or bits per character.
+ * 3. Number of elided entries (128 for specials).
+ * 4. Character table (size determined by fields 2 and 3). */
+
+static const unsigned char charmaps[] =
+"utf8\0\0\022\x80"
+"wchart\0\0\007\x80"
+
+"ucs2\0ucs2be\0\0\004\x80"
+"ucs2le\0\0\005\x80"
+
+"utf16\0utf16be\0\0\002\x80"
+"utf16le\0\0\001\x80"
+
+"ucs4\0ucs4be\0utf32\0utf32be\0\0\000\x80"
+"ucs4le\0utf32le\0\0\003\x80"
+
+"ascii\0iso646\0usascii\0\0\021\x80"
+"latin1\0iso88591\0\0\x09\x80"
+"latin9\0iso885915\0\0\024\x80"
+"tis620\0iso885911\0\0\025\x80"
+"jis0201\0\0\026\x80"
+
+"iso88592\0\0\x0a\x21"
+"\x04\x61\x1b\x14\x29\x3d\x69\x75\x0a\x2a"
+"\x60\x79\x45\x56\x5e\xad\xf4\xb5\x17\x2c"
+"\x05\x6d\x2b\x14\x2d\x3e\x6d\x75\x2c\x2e"
+"\x61\x7d\x55\x96\x5e\xdd\xfa\xc5\x17\x55"
+"\xc1\x08\x23\x10\x31\x39\x19\x74\x0c\x43"
+"\xc9\x60\xb4\x8c\x46\xcd\x38\xe3\x10\x44"
+"\x43\x1d\x35\x0d\x35\x50\x59\x73\x0d\x56"
+"\x6e\x69\x03\x17\x37\xdd\x88\xf5\x4d\x55"
+"\xe1\x88\x33\x10\x39\x3a\x1d\x74\x4e\x43"
+"\xe9\x64\xb4\xce\x46\xed\xb8\xf3\x50\x44"
+"\x44\x21\x35\x0f\x3d\x51\xd9\x73\x4f\x56"
+"\x6f\xe9\x13\x17\x3f\xfd\x8c\x95\x2d"
+
+"iso88593\0\0\x0a\x21"
+"\x26\x61\x3b\x0a\x29\x00\x90\x74\x0a\x2a"
+"\x30\x79\xe5\x11\x4d\xad\x00\xb0\x17\x2c"
+"\x27\xc9\x32\x0b\x2d\xb5\x94\x74\x0b\x2e"
+"\x31\x7d\xf5\x51\x4d\xbd\x00\xc0\x17\x30"
+"\xc1\x08\x03\x00\x31\x0a\x21\x74\x0c\x32"
+"\xc9\x28\xb3\x0c\x33\xcd\x38\xf3\x0c\x00"
+"\xd1\x48\x33\x0d\x35\x20\x59\x73\x0d\x47"
+"\xd9\x68\xb3\x0d\x37\x6c\x71\xf5\x0d\x38"
+"\xe1\x88\x03\x00\x39\x0b\x25\x74\x0e\x3a"
+"\xe9\xa8\xb3\x0e\x3b\xed\xb8\xf3\x0e\x00"
+"\xf1\xc8\x33\x0f\x3d\x21\xd9\x73\x4f\x47"
+"\xf9\xe8\xb3\x0f\x3f\x6d\x75\x95\x2d"
+
+"iso88594\0\0\x0a\x21"
+"\x04\xe1\x64\x15\x29\x28\xed\x74\x0a\x2a"
+"\x60\x49\x24\x92\x59\xad\xf4\xf5\x0a\x2c"
+"\x05\x6d\x7b\x15\x2d\x29\xf1\x74\x2c\x2e"
+"\x61\x4d\x34\xd2\x59\x4a\xf9\xb5\x14\x40"
+"\xc1\x08\x33\x0c\x31\xc5\x18\xe3\x12\x43"
+"\xc9\x60\xb4\x8c\x45\xcd\x38\xa3\x12\x44"
+"\x45\x31\x65\x13\x35\xd5\x58\x73\x0d\x36"
+"\x72\x69\xb3\x0d\x37\x68\xa9\xf5\x4d\x40"
+"\xe1\x88\x33\x0e\x39\xe5\x98\xf3\x52\x43"
+"\xe9\x64\xb4\xce\x45\xed\xb8\xb3\x52\x44"
+"\x46\x35\x75\x13\x3d\xf5\xd8\x73\x0f\x3e"
+"\x73\xe9\xb3\x0f\x3f\x69\xad\x95\x2d"
+
+"iso88595\0\0\x0e\x21"
+"\x01\x84\x00\x31\x40\x10\x10\x05\x84\x01"
+"\x71\x40\x20\x10\x09\x84\x02\xb1\x40\x30"
+"\x10\xad\x80\x03\xf1\x40\x40\x10\x11\x84"
+"\x04\x31\x41\x50\x10\x15\x84\x05\x71\x41"
+"\x60\x10\x19\x84\x06\xb1\x41\x70\x10\x1d"
+"\x84\x07\xf1\x41\x80\x10\x21\x84\x08\x31"
+"\x42\x90\x10\x25\x84\x09\x71\x42\xa0\x10"
+"\x29\x84\x0a\xb1\x42\xb0\x10\x2d\x84\x0b"
+"\xf1\x42\xc0\x10\x31\x84\x0c\x31\x43\xd0"
+"\x10\x35\x84\x0d\x71\x43\xe0\x10\x39\x84"
+"\x0e\xb1\x43\xf0\x10\x3d\x84\x0f\xf1\x43"
+"\x00\x11\x41\x84\x10\x31\x44\x10\x11\x45"
+"\x84\x11\x71\x44\x20\x11\x49\x84\x12\xb1"
+"\x44\x30\x11\x4d\x84\x13\xf1\x44\x58\x84"
+"\x51\x84\x14\x31\x45\x50\x11\x55\x84\x15"
+"\x71\x45\x60\x11\x59\x84\x16\xb1\x45\x70"
+"\x11\xa7\x80\x17\xf1\x45\x00"
+
+"iso88596\0\0\x0b\x21"
+"\x00\x00\x00\x00\x48\x01\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x18\xdc\x0a\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\xc0\x86\x01\x00\x00"
+"\x00\x7c\x18\x00\x21\x16\xf1\x88\x49\x5c"
+"\x62\x13\x9f\x18\xc5\x29\x56\xf1\x8a\x59"
+"\xdc\x62\x17\xbf\x18\xc6\x31\x96\xf1\x8c"
+"\x69\x5c\x63\x1b\xdf\x18\xc7\x39\xd6\x31"
+"\x00\x00\x00\x00\x00\x00\x00\xc8\x41\x16"
+"\xf2\x90\x89\x5c\x64\x23\x1f\x19\xc9\x49"
+"\x56\xf2\x92\x99\xdc\x64\x27\x3f\x19\xca"
+"\x51\x96\x32\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00"
+
+"iso88597\0\0\x0e\x21"
+"\x18\x60\x06\x38\x0a\xb0\x82\xaf\xa0\x29"
+"\x70\x0a\xa0\x02\xa9\x80\xde\xb0\x0a\xb0"
+"\x02\xad\x00\x00\x50\x01\xc2\x02\xb1\x80"
+"\x2c\x30\x0b\x10\x0e\x85\x83\xe1\x70\x0b"
+"\x20\x0e\x89\x83\xe2\xb0\x0b\x30\x0e\xbd"
+"\x80\xe3\xf0\x38\x40\x0e\x91\x83\xe4\x30"
+"\x39\x50\x0e\x95\x83\xe5\x70\x39\x60\x0e"
+"\x99\x83\xe6\xb0\x39\x70\x0e\x9d\x83\xe7"
+"\xf0\x39\x80\x0e\xa1\x03\x00\x30\x3a\x90"
+"\x0e\xa5\x83\xe9\x70\x3a\xa0\x0e\xa9\x83"
+"\xea\xb0\x3a\xb0\x0e\xad\x83\xeb\xf0\x3a"
+"\xc0\x0e\xb1\x83\xec\x30\x3b\xd0\x0e\xb5"
+"\x83\xed\x70\x3b\xe0\x0e\xb9\x83\xee\xb0"
+"\x3b\xf0\x0e\xbd\x83\xef\xf0\x3b\x00\x0f"
+"\xc1\x83\xf0\x30\x3c\x10\x0f\xc5\x83\xf1"
+"\x70\x3c\x20\x0f\xc9\x83\xf2\xb0\x3c\x30"
+"\x0f\xcd\x83\xf3\x00\x00\x00"
+
+"iso88598\0\0\x0e\x21"
+"\x00\x80\x28\x30\x0a\x90\x02\xa5\x80\x29"
+"\x70\x0a\xa0\x02\xa9\xc0\x35\xb0\x0a\xb0"
+"\x02\xad\x80\x2b\xf0\x0a\xc0\x02\xb1\x80"
+"\x2c\x30\x0b\xd0\x02\xb5\x80\x2d\x70\x0b"
+"\xe0\x02\xb9\xc0\x3d\xb0\x0b\xf0\x02\xbd"
+"\x80\x2f\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x70\x01"
+"\x42\x17\xd1\x85\x74\x31\x5d\x50\x17\xd5"
+"\x85\x75\x71\x5d\x60\x17\xd9\x85\x76\xb1"
+"\x5d\x70\x17\xdd\x85\x77\xf1\x5d\x80\x17"
+"\xe1\x85\x78\x31\x5e\x90\x17\xe5\x85\x79"
+"\x71\x5e\xa0\x17\xe9\x85\x7a\x01\x00\x00"
+"\x00\x0e\xe0\x03\x08\x00\x00"
+
+"iso88599\0\0\x09\x50"
+"\x1e\xa3\x49\x9b\x46\xad\x9a\xb5\x6b\xd8"
+"\xb2\x69\xdb\xc6\x0d\xa6\xd7\x6f\xe0\xc2"
+"\x89\x1b\x47\xae\x9c\xb9\x73\xe8\xd2\xa9"
+"\x5b\xc7\xae\x9d\xbb\x77\x1f\xe3\xc9\x9b"
+"\x47\xaf\x9e\xbd\x7b\xf8\xf2\xe9\xdb\xc7"
+"\x2f\xe6\xd7\x7f"
+
+"iso885910\0\0\x0e\x21"
+"\x04\x81\x44\x20\x12\xa8\x04\x28\x81\x4d"
+"\x70\x0a\xec\x04\x10\x01\x58\x60\x16\xf4"
+"\x05\xad\x80\x5a\xa0\x14\xc0\x02\x05\xc1"
+"\x44\x30\x12\xac\x04\x29\xc1\x4d\x70\x0b"
+"\xf0\x04\x11\x41\x58\x70\x16\xf8\x05\x15"
+"\xe0\x5a\xb0\x14\x00\x04\xc1\x80\x30\x30"
+"\x0c\x10\x03\xc5\x80\x31\xe0\x12\x30\x04"
+"\xc9\x00\x46\xb0\x0c\x58\x04\xcd\x80\x33"
+"\xf0\x0c\x40\x03\x45\x01\x53\x30\x0d\x50"
+"\x03\xd5\x80\x35\x80\x16\x60\x03\x72\x81"
+"\x36\xb0\x0d\x70\x03\xdd\x80\x37\xf0\x0d"
+"\x04\x04\xe1\x80\x38\x30\x0e\x90\x03\xe5"
+"\x80\x39\xf0\x12\x34\x04\xe9\x40\x46\xb0"
+"\x0e\x5c\x04\xed\x80\x3b\xf0\x0e\xc0\x03"
+"\x46\x41\x53\x30\x0f\xd0\x03\xf5\x80\x3d"
+"\x90\x16\xe0\x03\x73\x81\x3e\xb0\x0f\xf0"
+"\x03\xfd\x80\x3f\x80\x13\x00"
+
+"iso885913\0\0\x0e\x21"
+"\x1d\xa0\x28\x30\x0a\x90\x02\x1e\xa0\x29"
+"\x70\x0a\x60\x03\xa9\x80\x55\xb0\x0a\xb0"
+"\x02\xad\x80\x2b\x60\x0c\xc0\x02\xb1\x80"
+"\x2c\x30\x0b\x70\x80\xb5\x80\x2d\x70\x0b"
+"\xe0\x03\xb9\xc0\x55\xb0\x0b\xf0\x02\xbd"
+"\x80\x2f\x60\x0e\x10\x04\x2e\x01\x40\x60"
+"\x10\x10\x03\xc5\x00\x46\x20\x11\x30\x04"
+"\xc9\x40\x5e\x60\x11\x88\x04\x36\x81\x4a"
+"\xb0\x13\x80\x05\x43\x41\x51\x30\x0d\x30"
+"\x05\xd5\x80\x35\x70\x0d\xc8\x05\x41\x81"
+"\x56\xa0\x16\x70\x03\x7b\x41\x5f\xf0\x0d"
+"\x14\x04\x2f\x41\x40\x70\x10\x90\x03\xe5"
+"\x40\x46\x30\x11\x34\x04\xe9\x80\x5e\x70"
+"\x11\x8c\x04\x37\xc1\x4a\xc0\x13\x84\x05"
+"\x44\x81\x51\x30\x0f\x34\x05\xf5\x80\x3d"
+"\x70\x0f\xcc\x05\x42\xc1\x56\xb0\x16\xf0"
+"\x03\x7c\x81\x5f\x90\x01\x02"
+
+"iso885914\0\0\x0d\x21"
+"\x02\x7e\xc0\x8f\x02\x85\xb0\x10\x14\xfc"
+"\x29\x00\xf4\xa9\x40\xd0\x2f\x78\x79\xdf"
+"\x0a\x5c\x01\x5e\xf0\xf0\x1f\x1e\x24\x84"
+"\x04\x20\x1f\xe4\x6d\x81\x95\x0f\xf4\x57"
+"\x7e\xd0\x83\xf9\x79\x4f\xe8\x0b\x7d\x98"
+"\x07\x06\xc1\x40\x18\x0c\x03\x62\x50\x0c"
+"\x8c\xc1\x31\x40\x06\xc9\x40\x19\x2c\x03"
+"\x66\xd0\x0c\x9c\xc1\x33\xa0\x0b\xd1\x40"
+"\x1a\x4c\x03\x6a\x50\x0d\xac\x81\x9a\xc7"
+"\x06\xd9\x40\x1b\x6c\x03\x6e\xd0\x0d\xec"
+"\xc2\x37\x00\x07\xe1\x40\x1c\x8c\x03\x72"
+"\x50\x0e\xcc\xc1\x39\x40\x07\xe9\x40\x1d"
+"\xac\x03\x76\xd0\x0e\xdc\xc1\x3b\xa8\x0b"
+"\xf1\x40\x1e\xcc\x03\x7a\x50\x0f\xec\xc1"
+"\x9a\xc7\x07\xf9\x40\x1f\xec\x03\x7e\xd0"
+"\x0f\xee\xc2\x3f\x00"
+
+"iso885916\0\0\x0e\x21"
+"\x04\x41\x41\x10\x14\xb0\x82\x1e\x20\x58"
+"\x70\x0a\x84\x05\xa9\x00\x86\xb0\x0a\xe4"
+"\x05\xad\x80\x5e\xb0\x17\xc0\x02\xb1\x00"
+"\x43\x20\x14\xf4\x05\x1d\xa0\x2d\x70\x0b"
+"\xf8\x05\x0d\x41\x86\xb0\x0b\x48\x05\x53"
+"\x01\x5e\xc0\x17\x00\x03\xc1\x80\x30\x20"
+"\x10\x10\x03\x06\x81\x31\x70\x0c\x20\x03"
+"\xc9\x80\x32\xb0\x0c\x30\x03\xcd\x80\x33"
+"\xf0\x0c\x40\x04\x43\x81\x34\x30\x0d\x50"
+"\x03\x50\x81\x35\xa0\x15\xc0\x05\xd9\x80"
+"\x36\xb0\x0d\x70\x03\x18\x81\x86\xf0\x0d"
+"\x80\x03\xe1\x80\x38\x30\x10\x90\x03\x07"
+"\x81\x39\x70\x0e\xa0\x03\xe9\x80\x3a\xb0"
+"\x0e\xb0\x03\xed\x80\x3b\xf0\x0e\x44\x04"
+"\x44\x81\x3c\x30\x0f\xd0\x03\x51\x81\x3d"
+"\xb0\x15\xc4\x05\xf9\x80\x3e\xb0\x0f\xf0"
+"\x03\x19\xc1\x86\xf0\x0f\x00"
+
+"windows1252\0\0\x0e\x00"
+"\xac\x20\x00\xa0\x01\x4a\x06\x1e\xa0\x09"
+"\x08\x02\x86\x80\xc6\x02\x0c\x08\x16\xe4"
+"\x80\x52\x01\x00\xd0\x17\x00\x00\x00\x00"
+"\x06\x98\x01\x72\x80\x1d\xa0\x08\x38\x01"
+"\x52\x80\xdc\x82\x48\x18\x16\xe8\x80\x53"
+"\x01\x00\xe0\x17\xe0\x05\xa0\x40\x28\x20"
+"\x0a\x8c\x02\xa4\x40\x29\x60\x0a\x9c\x02"
+"\xa8\x40\x2a\xa0\x0a\xac\x02\xac\x40\x2b"
+"\xe0\x0a\xbc\x02\xb0\x40\x2c\x20\x0b\xcc"
+"\x02\xb4\x40\x2d\x60\x0b\xdc\x02\xb8\x40"
+"\x2e\xa0\x0b\xec\x02\xbc\x40\x2f\xe0\x0b"
+"\xfc\x02\xc0\x40\x30\x20\x0c\x0c\x03\xc4"
+"\x40\x31\x60\x0c\x1c\x03\xc8\x40\x32\xa0"
+"\x0c\x2c\x03\xcc\x40\x33\xe0\x0c\x3c\x03"
+"\xd0\x40\x34\x20\x0d\x4c\x03\xd4\x40\x35"
+"\x60\x0d\x5c\x03\xd8\x40\x36\xa0\x0d\x6c"
+"\x03\xdc\x40\x37\xe0\x0d\x7c\x03\xe0\x40"
+"\x38\x20\x0e\x8c\x03\xe4\x40\x39\x60\x0e"
+"\x9c\x03\xe8\x40\x3a\xa0\x0e\xac\x03\xec"
+"\x40\x3b\xe0\x0e\xbc\x03\xf0\x40\x3c\x20"
+"\x0f\xcc\x03\xf4\x40\x3d\x60\x0f\xdc\x03"
+"\xf8\x40\x3e\xa0\x0f\xec\x03\xfc\x40\x3f"
+"\xe0\x0f\xfc\x03"
+;
+
+
+
+static int fuzzycmp(const char *a, const char *b)
+{
+	for (; *a && *b; a++, b++) {
+		while (*a && (*a|32U)-'a'>26 && *a-'0'>10U) a++;
+		if ((*a|32U) != *b) return 1;
+	}
+	return *a != *b;
+}
+
+static int find_charmap(const char *name)
+{
+	const unsigned char *s;
+	for (s=charmaps; *s; ) {
+		if (!fuzzycmp(name, s)) {
+			for (; *s; s+=strlen(s)+1);
+			return s+1-charmaps;
+		}
+		s += strlen(s)+1;
+		if (!*s) s += ((128-s[2])*s[1]+7)/8 + 3;
+	}
+	return -1;
+}
+
+iconv_t iconv_open(const char *to, const char *from)
+{
+	int f, t;
+
+	if ((t = find_charmap(to)) < 0 || (f = find_charmap(from)) < 0) {
+		errno = EINVAL;
+		return (iconv_t)-1;
+	}
+
+	return (void *)(f<<16 | t);
+}
+
+int iconv_close(iconv_t cd)
+{
+	return 0;
+}
+
+static unsigned get_16(const unsigned char *s, int e)
+{
+	e &= 1;
+	return s[e]<<8 | s[1-e];
+}
+
+static void put_16(unsigned char *s, unsigned c, int e)
+{
+	e &= 1;
+	s[e] = c>>8;
+	s[1-e] = c;
+}
+
+static unsigned get_32(const unsigned char *s, int e)
+{
+	return s[e]+0U<<24 | s[e^1]<<16 | s[e^2]<<8 | s[e^3];
+}
+
+static void put_32(unsigned char *s, unsigned c, int e)
+{
+	s[e^0] = c>>24;
+	s[e^1] = c>>16;
+	s[e^2] = c>>8;
+	s[e^3] = c;
+}
+
+
+
+#define GET_MAPPING(m, i, n) ( (1<<(n))-1 & ( \
+	(m)[(i)*(n)/8] >> ((n)%8*(i)%8) | \
+	(m)[(i)*(n)/8+1] << 8-((n)%8*(i)%8) | \
+	(m)[(i)*(n)/8+2] << 16-((n)%8*(i)%8)     ) )
+
+static unsigned get_mapping(const unsigned char *m, unsigned c, unsigned n)
+{
+	switch (n) {
+	default:
+	case 9:  return m[c*9/8]>>c%8 | m[c*9/8+1]<<8-c%8 & (1<<n)-1;
+	case 10: return m[c*10/8]>>2*c%8 | m[c*10/8+1]<<8-2*c%8 & (1<<n)-1;
+	case 11: return GET_MAPPING(m, c, 11);
+	case 13: return GET_MAPPING(m, c, 13);
+	case 14: return GET_MAPPING(m, c, 14);
+	}
+}
+
+/* Adapt as needed */
+#define mbrtowc_utf8 mbrtowc
+#define wctomb_utf8 wctomb
+
+#include <stdio.h>
+size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb)
+{
+	size_t x=0;
+	unsigned long cd = (unsigned long)cd0;
+	unsigned to = cd & 0xffff;
+	unsigned from = cd >> 16;
+	const unsigned char *map = charmaps+from+2;
+	const unsigned char *tomap = charmaps+to+2;
+	mbstate_t st = {0};
+	wchar_t wc;
+	unsigned c, d;
+	size_t k, l;
+	int err;
+	unsigned elide = map[-1] + 128;
+	unsigned toelide = tomap[-1] + 128;
+	unsigned char type = map[-2];
+	unsigned char totype = tomap[-2];
+
+	if (!in || !*in || !*inb) return 0;
+
+	for (; *inb; *in+=l, *inb-=l) {
+		c = *(unsigned char *)*in;
+		l = 1;
+		if (type < 8 || c >= 0x80) switch (type) {
+		case UTF_8:
+			l = mbrtowc_utf8(&wc, *in, *inb, &st);
+			if (!l) l++;
+			else if (l == (size_t)-1) goto ilseq;
+			else if (l == (size_t)-2) goto starved;
+			c = wc;
+			break;
+		case LATIN_9:
+			if ((unsigned)c - 0xa4 <= 0xbe - 0xa4) {
+				static const unsigned char map[] = {
+					0, 0x60, 0, 0x61, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0x7d, 0, 0, 0, 0x7e, 0, 0, 0,
+					0x52, 0x53, 0x78
+				};
+				if (c == 0xa4) c = 0x20ac;
+				else if (map[c-0xa5]) c = 0x100 | map[c-0xa5];
+			}
+			break;
+		case TIS_620:
+			if (c >= 0xa1) c += 0x0e01-0xa1;
+			break;
+		case JIS_0201:
+			if (c >= 0xa1)
+				if (c <= 0xdf) c += 0xff61-0xa1;
+				else goto ilseq;
+			break;
+		case 9: case 10: case 11: case 13: case 14:
+			if (c < elide) break;
+			c = get_mapping(map, c-elide, type);
+			if (!c) {
+		case US_ASCII:
+				goto ilseq;
+			}
+			break;
+		case WCHAR_T:
+			l = sizeof(wchar_t);
+			if (*inb < l) goto starved;
+			c = *(wchar_t *)*in;
+			if (0) {
+		case UTF_32BE:
+		case UTF_32LE:
+			l = 4;
+			if (*inb < 4) goto starved;
+			c = get_32(*in, type);
+			}
+			if (c-0xd800u < 0x800u || c >= 0x110000u) goto ilseq;
+			break;
+		case UCS2BE:
+		case UCS2LE:
+		case UTF_16BE:
+		case UTF_16LE:
+			l = 2;
+			if (*inb < 2) goto starved;
+			c = get_16(*in, type);
+			if ((unsigned)(c-0xdc00) < 0x400) goto ilseq;
+			if ((unsigned)(c-0xd800) < 0x400) {
+				if (type-UCS2BE < 2U) goto ilseq;
+				l = 4;
+				if (*inb < 4) goto starved;
+				d = get_16(*in + 2, from);
+				if ((unsigned)(c-0xdc00) >= 0x400) goto ilseq;
+				c = ((c-0xd800)<<10) | (d-0xdc00);
+			}
+			break;
+		}
+
+		switch (totype) {
+		case WCHAR_T:
+			if (*outb < sizeof(wchar_t)) goto toobig;
+			*(wchar_t *)*out = c;
+			*out += sizeof(wchar_t);
+			*outb -= sizeof(wchar_t);
+			break;
+		case UTF_8:
+			if (*outb < 4) {
+				char tmp[4];
+				k = wctomb_utf8(tmp, c);
+				if (*outb < k) goto toobig;
+				memcpy(*out, tmp, k);
+			} else k = wctomb_utf8(*out, c);
+			*out += k;
+			*outb -= k;
+			break;
+		case TIS_620:
+			if (c-0xe01u <= 0xff-0xa1)
+				c -= 0xe01-0xa1;
+			else if (c >= 0xa1)
+				goto ascii;
+			goto revout;
+		case JIS_0201:
+			if (c-0xff61u <= 0xdf-0xa1)
+				c -= 0xff61-0xa1;
+			else if (c >= 0xa1)
+				goto ascii;
+			goto revout;
+		case LATIN_9:
+			if (c == 0x20ac) {
+				c=0xa4;
+			} else if (c-0x150u<=0x12 && (1<<c-0x150 & 0x3000c)) {
+				static const unsigned char map[] =
+					{ 0xa6,0xa8,0xbc,0xbd };
+				c = map[c&3];
+			} else if (c-0x178u<=0x7 && (1<<c-0x178 & 0x61)) {
+				static const unsigned char map[] =
+					{ 0xbe,0,0,0,0,0xb4,0xb8 };
+				c = map[c&7];
+			} else if (c>0x100 ||
+				c-0xa5u<=0xbeu-0xa5
+				&& (1<<c-0xa5 & 0x388800a))
+		case US_ASCII: ascii:
+			if (c > 0x7f) x++, c='*';
+		case 9: case 10: case 11: case 13: case 14:
+			if (*outb < 1) goto toobig;
+			if (c < toelide) {
+			revout:
+				*(*out)++ = c;
+				*outb -= 1;
+				break;
+			}
+			for (d=0; d<256-toelide; d++) {
+				if (c == get_mapping(tomap, d, totype)) {
+					c = d + toelide;
+					goto revout;
+				}
+			}
+			x++;
+			c = '*';
+			goto revout;
+		case UCS2BE:
+		case UCS2LE:
+		case UTF_16BE:
+		case UTF_16LE:
+			if (c < 0x10000) {
+				if (*outb < 2) goto toobig;
+				put_16(*out, c, totype);
+				*out += 2;
+				*outb -= 2;
+				break;
+			}
+			if (type-UCS2BE < 2U) goto ilseq;
+			if (*outb < 4) goto toobig;
+			put_16(*out, (c>>10)|0xd800, totype);
+			put_16(*out + 2, (c&0x3ff)|0xdc00, totype);
+			*out += 4;
+			*outb -= 4;
+			break;
+		case UTF_32BE:
+		case UTF_32LE:
+			if (*outb < 4) goto toobig;
+			put_32(*out, c, totype);
+			*out += 4;
+			*outb -= 4;
+			break;
+		}
+	}
+	return x;
+ilseq:
+	err = EILSEQ;
+	x = -1;
+	goto end;
+toobig:
+	err = E2BIG;
+	goto end;
+starved:
+	err = EINVAL;
+end:
+	errno = err;
+	return x;
+}
diff --git a/src/locale/intl.c b/src/locale/intl.c
new file mode 100644
index 00000000..964f7da1
--- /dev/null
+++ b/src/locale/intl.c
@@ -0,0 +1,67 @@
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+
+char *gettext(const char *msgid)
+{
+	return (char *) msgid;
+}
+
+char *dgettext(const char *domainname, const char *msgid)
+{
+	return (char *) msgid;
+}
+
+char *dcgettext(const char *domainname, const char *msgid, int category)
+{
+	return (char *) msgid;
+}
+
+char *ngettext(const char *msgid1, const char *msgid2, unsigned long int n)
+{
+	return (char *) ((n == 1) ? msgid1 : msgid2);
+}
+
+char *dngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n)
+{
+	return (char *) ((n == 1) ? msgid1 : msgid2);
+}
+
+char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category)
+{
+	return (char *) ((n == 1) ? msgid1 : msgid2);
+}
+
+char *textdomain(const char *domainname)
+{
+	static const char default_str[] = "messages";
+
+	if (domainname && *domainname && strcmp(domainname, default_str)) {
+		errno = EINVAL;
+		return NULL;
+	}
+	return (char *) default_str;
+}
+
+char *bindtextdomain(const char *domainname, const char *dirname)
+{
+	static const char dir[] = "/";
+
+	if (!domainname || !*domainname
+		|| (dirname && ((dirname[0] != '/') || dirname[1]))
+		) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	return (char *) dir;
+}
+
+char *bind_textdomain_codeset(const char *domainname, const char *codeset)
+{
+	if (!domainname || !*domainname || (codeset && strcasecmp(codeset, "UTF-8"))) {
+		errno = EINVAL;
+	}
+	return NULL;
+}
diff --git a/src/locale/isalnum_l.c b/src/locale/isalnum_l.c
new file mode 100644
index 00000000..b8a6eef3
--- /dev/null
+++ b/src/locale/isalnum_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isalnum_l(int c, locale_t l)
+{
+	return isalnum(c);
+}
diff --git a/src/locale/isalpha_l.c b/src/locale/isalpha_l.c
new file mode 100644
index 00000000..2e1205c6
--- /dev/null
+++ b/src/locale/isalpha_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isalpha_l(int c, locale_t l)
+{
+	return isalpha(c);
+}
diff --git a/src/locale/isblank_l.c b/src/locale/isblank_l.c
new file mode 100644
index 00000000..27479aa1
--- /dev/null
+++ b/src/locale/isblank_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isblank_l(int c, locale_t l)
+{
+	return isblank(c);
+}
diff --git a/src/locale/iscntrl_l.c b/src/locale/iscntrl_l.c
new file mode 100644
index 00000000..ca596fa9
--- /dev/null
+++ b/src/locale/iscntrl_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int iscntrl_l(int c, locale_t l)
+{
+	return iscntrl(c);
+}
diff --git a/src/locale/isdigit_l.c b/src/locale/isdigit_l.c
new file mode 100644
index 00000000..c8ae7bd3
--- /dev/null
+++ b/src/locale/isdigit_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isdigit_l(int c, locale_t l)
+{
+	return isdigit(c);
+}
diff --git a/src/locale/isgraph_l.c b/src/locale/isgraph_l.c
new file mode 100644
index 00000000..713a86e6
--- /dev/null
+++ b/src/locale/isgraph_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isgraph_l(int c, locale_t l)
+{
+	return isgraph(c);
+}
diff --git a/src/locale/islower_l.c b/src/locale/islower_l.c
new file mode 100644
index 00000000..25ec97a1
--- /dev/null
+++ b/src/locale/islower_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int islower_l(int c, locale_t l)
+{
+	return islower(c);
+}
diff --git a/src/locale/isprint_l.c b/src/locale/isprint_l.c
new file mode 100644
index 00000000..79ef3514
--- /dev/null
+++ b/src/locale/isprint_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isprint_l(int c, locale_t l)
+{
+	return isprint(c);
+}
diff --git a/src/locale/ispunct_l.c b/src/locale/ispunct_l.c
new file mode 100644
index 00000000..1c0bd046
--- /dev/null
+++ b/src/locale/ispunct_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int ispunct_l(int c, locale_t l)
+{
+	return ispunct(c);
+}
diff --git a/src/locale/isspace_l.c b/src/locale/isspace_l.c
new file mode 100644
index 00000000..e1a0efed
--- /dev/null
+++ b/src/locale/isspace_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isspace_l(int c, locale_t l)
+{
+	return isspace(c);
+}
diff --git a/src/locale/isupper_l.c b/src/locale/isupper_l.c
new file mode 100644
index 00000000..11ba7036
--- /dev/null
+++ b/src/locale/isupper_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isupper_l(int c, locale_t l)
+{
+	return isupper(c);
+}
diff --git a/src/locale/isxdigit_l.c b/src/locale/isxdigit_l.c
new file mode 100644
index 00000000..68649d09
--- /dev/null
+++ b/src/locale/isxdigit_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int isxdigit_l(int c, locale_t l)
+{
+	return isxdigit(c);
+}
diff --git a/src/locale/langinfo.c b/src/locale/langinfo.c
new file mode 100644
index 00000000..f7f56012
--- /dev/null
+++ b/src/locale/langinfo.c
@@ -0,0 +1,58 @@
+#include <locale.h>
+#include <langinfo.h>
+
+static const char c_time[] =
+	"Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0"
+	"Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0"
+	"Thursday\0" "Friday\0" "Saturday\0"
+	"Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0"
+	"Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0"
+	"January\0"   "February\0" "March\0"    "April\0"
+	"May\0"       "June\0"     "July\0"     "August\0"
+	"September\0" "October\0"  "November\0" "December\0"
+	"AM\0" "PM\0"
+	"%a %b %e %T %Y\0"
+	"%m/%d/%y\0"
+	"%H:%M:%S\0"
+	"%I:%M:%S %p\0"
+	"\0"
+	"%m/%d/%y\0"
+	"0123456789"
+	"%a %b %e %T %Y\0"
+	"%H:%M:%S";
+
+static const char c_messages[] = "^[yY]\0" "^[nN]";
+static const char c_numeric[] = ".\0" "";
+
+const char *__langinfo(nl_item item)
+{
+	int cat = item >> 16;
+	int idx = item & 65535;
+	const char *str;
+
+	if (item == CODESET) return "UTF-8";
+	
+	switch (cat) {
+	case LC_NUMERIC:
+		if (idx > 1) return NULL;
+		str = c_numeric;
+		break;
+	case LC_TIME:
+		if (idx > 0x31) return NULL;
+		str = c_time;
+		break;
+	case LC_MONETARY:
+		if (idx > 0) return NULL;
+		str = "";
+		break;
+	case LC_MESSAGES:
+		if (idx > 1) return NULL;
+		str = c_messages;
+		break;
+	default:
+		return NULL;
+	}
+
+	for (; idx; idx--, str++) for (; *str; str++);
+	return str;
+}
diff --git a/src/locale/localeconv.c b/src/locale/localeconv.c
new file mode 100644
index 00000000..d79d1c07
--- /dev/null
+++ b/src/locale/localeconv.c
@@ -0,0 +1,22 @@
+#include <locale.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct lconv *localeconv(void)
+{
+	static struct lconv *posix_lconv;
+	if (posix_lconv) return posix_lconv;
+	posix_lconv = malloc(sizeof *posix_lconv);
+	memset(posix_lconv, -1, sizeof *posix_lconv);
+	posix_lconv->decimal_point = ".";
+	posix_lconv->thousands_sep = "";
+	posix_lconv->grouping = "\xff";
+	posix_lconv->int_curr_symbol = ""; //"\xc2\xa4";
+	posix_lconv->currency_symbol = "";
+	posix_lconv->mon_decimal_point = "";
+	posix_lconv->mon_thousands_sep = "";
+	posix_lconv->mon_grouping = "\xff";
+	posix_lconv->positive_sign = ""; // "+";
+	posix_lconv->negative_sign = ""; // "-";
+	return posix_lconv;
+}
diff --git a/src/locale/newlocale.c b/src/locale/newlocale.c
new file mode 100644
index 00000000..986e796f
--- /dev/null
+++ b/src/locale/newlocale.c
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+#include <string.h>
+#include "locale_impl.h"
+
+locale_t newlocale(int mask, const char *name, locale_t base)
+{
+	if (*name && strcmp(name, "C") && strcmp(name, "POSIX"))
+		return 0;
+	if (!base) base = calloc(1, sizeof *base);
+	return base;
+}
diff --git a/src/locale/nl_langinfo.c b/src/locale/nl_langinfo.c
new file mode 100644
index 00000000..bb3a2c46
--- /dev/null
+++ b/src/locale/nl_langinfo.c
@@ -0,0 +1,13 @@
+#include <langinfo.h>
+
+// FIXME: other items
+
+char *nl_langinfo(nl_item item)
+{
+	switch (item) {
+	case CODESET:
+		return "UTF-8";
+	default:
+		return "";
+	}
+}
diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c
new file mode 100644
index 00000000..28f29b80
--- /dev/null
+++ b/src/locale/setlocale.c
@@ -0,0 +1,9 @@
+#include <locale.h>
+
+char *setlocale(int category, const char *locale)
+{
+	/* Note: plain "C" would be better, but puts some broken
+	 * software into legacy 8-bit-codepage mode, ignoring
+	 * the standard library's multibyte encoding */
+	return "C.UTF-8";
+}
diff --git a/src/locale/strcoll.c b/src/locale/strcoll.c
new file mode 100644
index 00000000..30bccd62
--- /dev/null
+++ b/src/locale/strcoll.c
@@ -0,0 +1,6 @@
+#include <string.h>
+
+int strcoll(const char *l, const char *r)
+{
+	return strcmp(l, r);
+}
diff --git a/src/locale/strxfrm.c b/src/locale/strxfrm.c
new file mode 100644
index 00000000..8f123399
--- /dev/null
+++ b/src/locale/strxfrm.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+/* collate only by code points */
+size_t strxfrm(char *dest, const char *src, size_t n)
+{
+	size_t l = strlen(src);
+	if (n > l) strcpy(dest, src);
+	return l;
+}
diff --git a/src/locale/tmp b/src/locale/tmp
new file mode 100644
index 00000000..aa71779f
--- /dev/null
+++ b/src/locale/tmp
@@ -0,0 +1,390 @@
+"iso88591\0\x08\x80"
+"iso88592\0\x0a\x21"
+"\x04\x61\x1b\x14\x29\x3d\x69\x75\x0a\x2a"
+"\x60\x79\x45\x56\x5e\xad\xf4\xb5\x17\x2c"
+"\x05\x6d\x2b\x14\x2d\x3e\x6d\x75\x2c\x2e"
+"\x61\x7d\x55\x96\x5e\xdd\xfa\xc5\x17\x55"
+"\xc1\x08\x23\x10\x31\x39\x19\x74\x0c\x43"
+"\xc9\x60\xb4\x8c\x46\xcd\x38\xe3\x10\x44"
+"\x43\x1d\x35\x0d\x35\x50\x59\x73\x0d\x56"
+"\x6e\x69\x03\x17\x37\xdd\x88\xf5\x4d\x55"
+"\xe1\x88\x33\x10\x39\x3a\x1d\x74\x4e\x43"
+"\xe9\x64\xb4\xce\x46\xed\xb8\xf3\x50\x44"
+"\x44\x21\x35\x0f\x3d\x51\xd9\x73\x4f\x56"
+"\x6f\xe9\x13\x17\x3f\xfd\x8c\x95\x2d"
+"iso88593\0\x0a0x21"
+"\x26\x61\x3b\x0a\x29\x00\x90\x74\x0a\x2a"
+"\x30\x79\xe5\x11\x4d\xad\x00\xb0\x17\x2c"
+"\x27\xc9\x32\x0b\x2d\xb5\x94\x74\x0b\x2e"
+"\x31\x7d\xf5\x51\x4d\xbd\x00\xc0\x17\x30"
+"\xc1\x08\x03\x00\x31\x0a\x21\x74\x0c\x32"
+"\xc9\x28\xb3\x0c\x33\xcd\x38\xf3\x0c\x00"
+"\xd1\x48\x33\x0d\x35\x20\x59\x73\x0d\x47"
+"\xd9\x68\xb3\x0d\x37\x6c\x71\xf5\x0d\x38"
+"\xe1\x88\x03\x00\x39\x0b\x25\x74\x0e\x3a"
+"\xe9\xa8\xb3\x0e\x3b\xed\xb8\xf3\x0e\x00"
+"\xf1\xc8\x33\x0f\x3d\x21\xd9\x73\x4f\x47"
+"\xf9\xe8\xb3\x0f\x3f\x6d\x75\x95\x2d"
+"iso88594\0\x0a\x21"
+"\x04\xe1\x64\x15\x29\x28\xed\x74\x0a\x2a"
+"\x60\x49\x24\x92\x59\xad\xf4\xf5\x0a\x2c"
+"\x05\x6d\x7b\x15\x2d\x29\xf1\x74\x2c\x2e"
+"\x61\x4d\x34\xd2\x59\x4a\xf9\xb5\x14\x40"
+"\xc1\x08\x33\x0c\x31\xc5\x18\xe3\x12\x43"
+"\xc9\x60\xb4\x8c\x45\xcd\x38\xa3\x12\x44"
+"\x45\x31\x65\x13\x35\xd5\x58\x73\x0d\x36"
+"\x72\x69\xb3\x0d\x37\x68\xa9\xf5\x4d\x40"
+"\xe1\x88\x33\x0e\x39\xe5\x98\xf3\x52\x43"
+"\xe9\x64\xb4\xce\x45\xed\xb8\xb3\x52\x44"
+"\x46\x35\x75\x13\x3d\xf5\xd8\x73\x0f\x3e"
+"\x73\xe9\xb3\x0f\x3f\x69\xad\x95\x2d"
+"iso88595\0\x0d\x21"
+"\x01\x84\x00\x30\x40\x10\x10\x05\x84\x01"
+"\x70\x40\x20\x10\x09\x84\x02\xb0\x40\x30"
+"\x10\xad\x80\x03\xf0\x40\x40\x10\x11\x84"
+"\x04\x30\x41\x50\x10\x15\x84\x05\x70\x41"
+"\x60\x10\x19\x84\x06\xb0\x41\x70\x10\x1d"
+"\x84\x07\xf0\x41\x80\x10\x21\x84\x08\x30"
+"\x42\x90\x10\x25\x84\x09\x70\x42\xa0\x10"
+"\x29\x84\x0a\xb0\x42\xb0\x10\x2d\x84\x0b"
+"\xf0\x42\xc0\x10\x31\x84\x0c\x30\x43\xd0"
+"\x10\x35\x84\x0d\x70\x43\xe0\x10\x39\x84"
+"\x0e\xb0\x43\xf0\x10\x3d\x84\x0f\xf0\x43"
+"\x00\x11\x41\x84\x10\x30\x44\x10\x11\x45"
+"\x84\x11\x70\x44\x20\x11\x49\x84\x12\xb0"
+"\x44\x30\x11\x4d\x84\x13\xf0\x44\x58\x84"
+"\x51\x84\x14\x30\x45\x50\x11\x55\x84\x15"
+"\x70\x45\x60\x11\x59\x84\x16\xb0\x45\x70"
+"\x11\xa7\x80\x17\xf0\x45\x00"
+"iso88596\0\x0b\x21"
+"\x00\x00\x00\x00\x48\x01\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x18\xdc\x0a\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\xc0\x86\x00\x00\x00"
+"\x00\x7c\x18\x00\x21\x16\xf1\x88\x48\x5c"
+"\x62\x13\x9c\x18\xc5\x29\x56\xf1\x8a\x58"
+"\xdc\x62\x17\xbc\x18\xc6\x31\x96\xf1\x8c"
+"\x68\x5c\x63\x1b\xdc\x18\xc7\x39\xd6\x31"
+"\x00\x00\x00\x00\x00\x00\x00\xc8\x41\x16"
+"\xf2\x90\x88\x5c\x64\x23\x1c\x19\xc9\x49"
+"\x56\xf2\x92\x98\xdc\x64\x27\x3c\x19\xca"
+"\x51\x96\x32\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00"
+"iso88597\0\x0d\x21"
+"\x18\x60\x06\x30\x0a\xb0\x82\xaf\xa0\x29"
+"\x70\x0a\xa0\x02\xa9\x80\xde\xb0\x0a\xb0"
+"\x02\xad\x00\x00\x50\x01\xc0\x02\xb1\x80"
+"\x2c\x30\x0b\x10\x0e\x85\x83\xe1\x70\x0b"
+"\x20\x0e\x89\x83\xe2\xb0\x0b\x30\x0e\xbd"
+"\x80\xe3\xf0\x38\x40\x0e\x91\x83\xe4\x30"
+"\x39\x50\x0e\x95\x83\xe5\x70\x39\x60\x0e"
+"\x99\x83\xe6\xb0\x39\x70\x0e\x9d\x83\xe7"
+"\xf0\x39\x80\x0e\xa1\x03\x00\x30\x3a\x90"
+"\x0e\xa5\x83\xe9\x70\x3a\xa0\x0e\xa9\x83"
+"\xea\xb0\x3a\xb0\x0e\xad\x83\xeb\xf0\x3a"
+"\xc0\x0e\xb1\x83\xec\x30\x3b\xd0\x0e\xb5"
+"\x83\xed\x70\x3b\xe0\x0e\xb9\x83\xee\xb0"
+"\x3b\xf0\x0e\xbd\x83\xef\xf0\x3b\x00\x0f"
+"\xc1\x83\xf0\x30\x3c\x10\x0f\xc5\x83\xf1"
+"\x70\x3c\x20\x0f\xc9\x83\xf2\xb0\x3c\x30"
+"\x0f\xcd\x83\xf3\x00\x00\x00"
+"iso88598\0\x0d\x21"
+"\x00\x80\x28\x30\x0a\x90\x02\xa5\x80\x29"
+"\x70\x0a\xa0\x02\xa9\xc0\x35\xb0\x0a\xb0"
+"\x02\xad\x80\x2b\xf0\x0a\xc0\x02\xb1\x80"
+"\x2c\x30\x0b\xd0\x02\xb5\x80\x2d\x70\x0b"
+"\xe0\x02\xb9\xc0\x3d\xb0\x0b\xf0\x02\xbd"
+"\x80\x2f\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00\x70\x01"
+"\x40\x17\xd1\x85\x74\x30\x5d\x50\x17\xd5"
+"\x85\x75\x70\x5d\x60\x17\xd9\x85\x76\xb0"
+"\x5d\x70\x17\xdd\x85\x77\xf0\x5d\x80\x17"
+"\xe1\x85\x78\x30\x5e\x90\x17\xe5\x85\x79"
+"\x70\x5e\xa0\x17\xe9\x85\x7a\x00\x00\x00"
+"\x00\x0e\xe0\x03\x00\x00\x00"
+"iso88599\0\x09\x50"
+"\x1e\xa3\x49\x9b\x46\xad\x9a\xb5\x6b\xd8"
+"\xb2\x69\xdb\xc6\x0d\xa6\xd7\x6f\xe0\xc2"
+"\x89\x1b\x47\xae\x9c\xb9\x73\xe8\xd2\xa9"
+"\x5b\xc7\xae\x9d\xbb\x77\x1f\xe3\xc9\x9b"
+"\x47\xaf\x9e\xbd\x7b\xf8\xf2\xe9\xdb\xc7"
+"\x2f\xe6\xd7\x7f"
+"iso885910\0\x0d\x21"
+"\x04\x81\x44\x20\x12\xa8\x04\x28\x81\x4d"
+"\x70\x0a\xec\x04\x10\x01\x58\x60\x16\xf4"
+"\x05\xad\x80\x5a\xa0\x14\xc0\x02\x05\xc1"
+"\x44\x30\x12\xac\x04\x29\xc1\x4d\x70\x0b"
+"\xf0\x04\x11\x41\x58\x70\x16\xf8\x05\x15"
+"\xe0\x5a\xb0\x14\x00\x04\xc1\x80\x30\x30"
+"\x0c\x10\x03\xc5\x80\x31\xe0\x12\x30\x04"
+"\xc9\x00\x46\xb0\x0c\x58\x04\xcd\x80\x33"
+"\xf0\x0c\x40\x03\x45\x01\x53\x30\x0d\x50"
+"\x03\xd5\x80\x35\x80\x16\x60\x03\x72\x81"
+"\x36\xb0\x0d\x70\x03\xdd\x80\x37\xf0\x0d"
+"\x04\x04\xe1\x80\x38\x30\x0e\x90\x03\xe5"
+"\x80\x39\xf0\x12\x34\x04\xe9\x40\x46\xb0"
+"\x0e\x5c\x04\xed\x80\x3b\xf0\x0e\xc0\x03"
+"\x46\x41\x53\x30\x0f\xd0\x03\xf5\x80\x3d"
+"\x90\x16\xe0\x03\x73\x81\x3e\xb0\x0f\xf0"
+"\x03\xfd\x80\x3f\x80\x13\x00"
+"iso885913\0\x0d\x21"
+"\x1d\xa0\x28\x30\x0a\x90\x02\x1e\xa0\x29"
+"\x70\x0a\x60\x03\xa9\x80\x55\xb0\x0a\xb0"
+"\x02\xad\x80\x2b\x60\x0c\xc0\x02\xb1\x80"
+"\x2c\x30\x0b\x70\x80\xb5\x80\x2d\x70\x0b"
+"\xe0\x03\xb9\xc0\x55\xb0\x0b\xf0\x02\xbd"
+"\x80\x2f\x60\x0e\x10\x04\x2e\x01\x40\x60"
+"\x10\x10\x03\xc5\x00\x46\x20\x11\x30\x04"
+"\xc9\x40\x5e\x60\x11\x88\x04\x36\x81\x4a"
+"\xb0\x13\x80\x05\x43\x41\x51\x30\x0d\x30"
+"\x05\xd5\x80\x35\x70\x0d\xc8\x05\x41\x81"
+"\x56\xa0\x16\x70\x03\x7b\x41\x5f\xf0\x0d"
+"\x14\x04\x2f\x41\x40\x70\x10\x90\x03\xe5"
+"\x40\x46\x30\x11\x34\x04\xe9\x80\x5e\x70"
+"\x11\x8c\x04\x37\xc1\x4a\xc0\x13\x84\x05"
+"\x44\x81\x51\x30\x0f\x34\x05\xf5\x80\x3d"
+"\x70\x0f\xcc\x05\x42\xc1\x56\xb0\x16\xf0"
+"\x03\x7c\x81\x5f\x90\x01\x00"
+"iso885914\0\x0c\x21"
+"\x02\x7e\xc0\x8c\x02\x85\xb0\x10\x14\xfc"
+"\x29\x00\xf4\xa9\x40\xd0\x2c\x78\x79\xd0"
+"\x0a\x5c\x01\x5e\xf0\xf0\x1f\x1e\x24\x84"
+"\x04\x20\x10\xe4\x6c\x81\x95\x08\xf4\x57"
+"\x7e\xd0\x80\xf9\x79\x40\xe8\x0a\x7d\x98"
+"\x00\x06\xc1\x40\x18\x0c\x03\x62\x50\x0c"
+"\x8c\xc1\x31\x40\x06\xc9\x40\x19\x2c\x03"
+"\x66\xd0\x0c\x9c\xc1\x33\xa0\x0b\xd1\x40"
+"\x1a\x4c\x03\x6a\x50\x0d\xac\x81\x9a\xc0"
+"\x06\xd9\x40\x1b\x6c\x03\x6e\xd0\x0d\xec"
+"\xc2\x37\x00\x07\xe1\x40\x1c\x8c\x03\x72"
+"\x50\x0e\xcc\xc1\x39\x40\x07\xe9\x40\x1d"
+"\xac\x03\x76\xd0\x0e\xdc\xc1\x3b\xa8\x0b"
+"\xf1\x40\x1e\xcc\x03\x7a\x50\x0f\xec\xc1"
+"\x9a\xc0\x07\xf9\x40\x1f\xec\x03\x7e\xd0"
+"\x0f\xee\xc2\x3f\x00"
+"iso885916\0\x0d\x21"
+"\x04\x41\x41\x10\x14\xb0\x82\x1e\x20\x58"
+"\x70\x0a\x84\x05\xa9\x00\x86\xb0\x0a\xe4"
+"\x05\xad\x80\x5e\xb0\x17\xc0\x02\xb1\x00"
+"\x43\x20\x14\xf4\x05\x1d\xa0\x2d\x70\x0b"
+"\xf8\x05\x0d\x41\x86\xb0\x0b\x48\x05\x53"
+"\x01\x5e\xc0\x17\x00\x03\xc1\x80\x30\x20"
+"\x10\x10\x03\x06\x81\x31\x70\x0c\x20\x03"
+"\xc9\x80\x32\xb0\x0c\x30\x03\xcd\x80\x33"
+"\xf0\x0c\x40\x04\x43\x81\x34\x30\x0d\x50"
+"\x03\x50\x81\x35\xa0\x15\xc0\x05\xd9\x80"
+"\x36\xb0\x0d\x70\x03\x18\x81\x86\xf0\x0d"
+"\x80\x03\xe1\x80\x38\x30\x10\x90\x03\x07"
+"\x81\x39\x70\x0e\xa0\x03\xe9\x80\x3a\xb0"
+"\x0e\xb0\x03\xed\x80\x3b\xf0\x0e\x44\x04"
+"\x44\x81\x3c\x30\x0f\xd0\x03\x51\x81\x3d"
+"\xb0\x15\xc4\x05\xf9\x80\x3e\xb0\x0f\xf0"
+"\x03\x19\xc1\x86\xf0\x0f\x00"
+;
+
+
+'i','s','o','8','8','5','9','1',0,
+8,128,
+'i','s','o','8','8','5','9','2',0,
+10, 33,
+0x04, 0x61, 0x1b, 0x14, 0x29, 0x3d, 0x69, 0x75, 0x0a, 0x2a,
+0x60, 0x79, 0x45, 0x56, 0x5e, 0xad, 0xf4, 0xb5, 0x17, 0x2c,
+0x05, 0x6d, 0x2b, 0x14, 0x2d, 0x3e, 0x6d, 0x75, 0x2c, 0x2e,
+0x61, 0x7d, 0x55, 0x96, 0x5e, 0xdd, 0xfa, 0xc5, 0x17, 0x55,
+0xc1, 0x08, 0x23, 0x10, 0x31, 0x39, 0x19, 0x74, 0x0c, 0x43,
+0xc9, 0x60, 0xb4, 0x8c, 0x46, 0xcd, 0x38, 0xe3, 0x10, 0x44,
+0x43, 0x1d, 0x35, 0x0d, 0x35, 0x50, 0x59, 0x73, 0x0d, 0x56,
+0x6e, 0x69, 0x03, 0x17, 0x37, 0xdd, 0x88, 0xf5, 0x4d, 0x55,
+0xe1, 0x88, 0x33, 0x10, 0x39, 0x3a, 0x1d, 0x74, 0x4e, 0x43,
+0xe9, 0x64, 0xb4, 0xce, 0x46, 0xed, 0xb8, 0xf3, 0x50, 0x44,
+0x44, 0x21, 0x35, 0x0f, 0x3d, 0x51, 0xd9, 0x73, 0x4f, 0x56,
+0x6f, 0xe9, 0x13, 0x17, 0x3f, 0xfd, 0x8c, 0x95, 0x2d,
+'i','s','o','8','8','5','9','3',0,
+10, 33,
+0x26, 0x61, 0x3b, 0x0a, 0x29, 0x00, 0x90, 0x74, 0x0a, 0x2a,
+0x30, 0x79, 0xe5, 0x11, 0x4d, 0xad, 0x00, 0xb0, 0x17, 0x2c,
+0x27, 0xc9, 0x32, 0x0b, 0x2d, 0xb5, 0x94, 0x74, 0x0b, 0x2e,
+0x31, 0x7d, 0xf5, 0x51, 0x4d, 0xbd, 0x00, 0xc0, 0x17, 0x30,
+0xc1, 0x08, 0x03, 0x00, 0x31, 0x0a, 0x21, 0x74, 0x0c, 0x32,
+0xc9, 0x28, 0xb3, 0x0c, 0x33, 0xcd, 0x38, 0xf3, 0x0c, 0x00,
+0xd1, 0x48, 0x33, 0x0d, 0x35, 0x20, 0x59, 0x73, 0x0d, 0x47,
+0xd9, 0x68, 0xb3, 0x0d, 0x37, 0x6c, 0x71, 0xf5, 0x0d, 0x38,
+0xe1, 0x88, 0x03, 0x00, 0x39, 0x0b, 0x25, 0x74, 0x0e, 0x3a,
+0xe9, 0xa8, 0xb3, 0x0e, 0x3b, 0xed, 0xb8, 0xf3, 0x0e, 0x00,
+0xf1, 0xc8, 0x33, 0x0f, 0x3d, 0x21, 0xd9, 0x73, 0x4f, 0x47,
+0xf9, 0xe8, 0xb3, 0x0f, 0x3f, 0x6d, 0x75, 0x95, 0x2d,
+'i','s','o','8','8','5','9','4',0,
+10, 33,
+0x04, 0xe1, 0x64, 0x15, 0x29, 0x28, 0xed, 0x74, 0x0a, 0x2a,
+0x60, 0x49, 0x24, 0x92, 0x59, 0xad, 0xf4, 0xf5, 0x0a, 0x2c,
+0x05, 0x6d, 0x7b, 0x15, 0x2d, 0x29, 0xf1, 0x74, 0x2c, 0x2e,
+0x61, 0x4d, 0x34, 0xd2, 0x59, 0x4a, 0xf9, 0xb5, 0x14, 0x40,
+0xc1, 0x08, 0x33, 0x0c, 0x31, 0xc5, 0x18, 0xe3, 0x12, 0x43,
+0xc9, 0x60, 0xb4, 0x8c, 0x45, 0xcd, 0x38, 0xa3, 0x12, 0x44,
+0x45, 0x31, 0x65, 0x13, 0x35, 0xd5, 0x58, 0x73, 0x0d, 0x36,
+0x72, 0x69, 0xb3, 0x0d, 0x37, 0x68, 0xa9, 0xf5, 0x4d, 0x40,
+0xe1, 0x88, 0x33, 0x0e, 0x39, 0xe5, 0x98, 0xf3, 0x52, 0x43,
+0xe9, 0x64, 0xb4, 0xce, 0x45, 0xed, 0xb8, 0xb3, 0x52, 0x44,
+0x46, 0x35, 0x75, 0x13, 0x3d, 0xf5, 0xd8, 0x73, 0x0f, 0x3e,
+0x73, 0xe9, 0xb3, 0x0f, 0x3f, 0x69, 0xad, 0x95, 0x2d,
+'i','s','o','8','8','5','9','5',0,
+14, 33,
+0x01, 0x84, 0x00, 0x30, 0x40, 0x10, 0x10, 0x05, 0x84, 0x01,
+0x70, 0x40, 0x20, 0x10, 0x09, 0x84, 0x02, 0xb0, 0x40, 0x30,
+0x10, 0xad, 0x80, 0x03, 0xf0, 0x40, 0x40, 0x10, 0x11, 0x84,
+0x04, 0x30, 0x41, 0x50, 0x10, 0x15, 0x84, 0x05, 0x70, 0x41,
+0x60, 0x10, 0x19, 0x84, 0x06, 0xb0, 0x41, 0x70, 0x10, 0x1d,
+0x84, 0x07, 0xf0, 0x41, 0x80, 0x10, 0x21, 0x84, 0x08, 0x30,
+0x42, 0x90, 0x10, 0x25, 0x84, 0x09, 0x70, 0x42, 0xa0, 0x10,
+0x29, 0x84, 0x0a, 0xb0, 0x42, 0xb0, 0x10, 0x2d, 0x84, 0x0b,
+0xf0, 0x42, 0xc0, 0x10, 0x31, 0x84, 0x0c, 0x30, 0x43, 0xd0,
+0x10, 0x35, 0x84, 0x0d, 0x70, 0x43, 0xe0, 0x10, 0x39, 0x84,
+0x0e, 0xb0, 0x43, 0xf0, 0x10, 0x3d, 0x84, 0x0f, 0xf0, 0x43,
+0x00, 0x11, 0x41, 0x84, 0x10, 0x30, 0x44, 0x10, 0x11, 0x45,
+0x84, 0x11, 0x70, 0x44, 0x20, 0x11, 0x49, 0x84, 0x12, 0xb0,
+0x44, 0x30, 0x11, 0x4d, 0x84, 0x13, 0xf0, 0x44, 0x58, 0x84,
+0x51, 0x84, 0x14, 0x30, 0x45, 0x50, 0x11, 0x55, 0x84, 0x15,
+0x70, 0x45, 0x60, 0x11, 0x59, 0x84, 0x16, 0xb0, 0x45, 0x70,
+0x11, 0xa7, 0x80, 0x17, 0xf0, 0x45, 0x00,
+'i','s','o','8','8','5','9','6',0,
+11, 33,
+0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xdc, 0x0a, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x86, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0x18, 0x00, 0x21, 0x16, 0xf1, 0x88, 0x48, 0x5c,
+0x62, 0x13, 0x9c, 0x18, 0xc5, 0x29, 0x56, 0xf1, 0x8a, 0x58,
+0xdc, 0x62, 0x17, 0xbc, 0x18, 0xc6, 0x31, 0x96, 0xf1, 0x8c,
+0x68, 0x5c, 0x63, 0x1b, 0xdc, 0x18, 0xc7, 0x39, 0xd6, 0x31,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x41, 0x16,
+0xf2, 0x90, 0x88, 0x5c, 0x64, 0x23, 0x1c, 0x19, 0xc9, 0x49,
+0x56, 0xf2, 0x92, 0x98, 0xdc, 0x64, 0x27, 0x3c, 0x19, 0xca,
+0x51, 0x96, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00,
+'i','s','o','8','8','5','9','7',0,
+14, 33,
+0x18, 0x60, 0x06, 0x30, 0x0a, 0xb0, 0x82, 0xaf, 0xa0, 0x29,
+0x70, 0x0a, 0xa0, 0x02, 0xa9, 0x80, 0xde, 0xb0, 0x0a, 0xb0,
+0x02, 0xad, 0x00, 0x00, 0x50, 0x01, 0xc0, 0x02, 0xb1, 0x80,
+0x2c, 0x30, 0x0b, 0x10, 0x0e, 0x85, 0x83, 0xe1, 0x70, 0x0b,
+0x20, 0x0e, 0x89, 0x83, 0xe2, 0xb0, 0x0b, 0x30, 0x0e, 0xbd,
+0x80, 0xe3, 0xf0, 0x38, 0x40, 0x0e, 0x91, 0x83, 0xe4, 0x30,
+0x39, 0x50, 0x0e, 0x95, 0x83, 0xe5, 0x70, 0x39, 0x60, 0x0e,
+0x99, 0x83, 0xe6, 0xb0, 0x39, 0x70, 0x0e, 0x9d, 0x83, 0xe7,
+0xf0, 0x39, 0x80, 0x0e, 0xa1, 0x03, 0x00, 0x30, 0x3a, 0x90,
+0x0e, 0xa5, 0x83, 0xe9, 0x70, 0x3a, 0xa0, 0x0e, 0xa9, 0x83,
+0xea, 0xb0, 0x3a, 0xb0, 0x0e, 0xad, 0x83, 0xeb, 0xf0, 0x3a,
+0xc0, 0x0e, 0xb1, 0x83, 0xec, 0x30, 0x3b, 0xd0, 0x0e, 0xb5,
+0x83, 0xed, 0x70, 0x3b, 0xe0, 0x0e, 0xb9, 0x83, 0xee, 0xb0,
+0x3b, 0xf0, 0x0e, 0xbd, 0x83, 0xef, 0xf0, 0x3b, 0x00, 0x0f,
+0xc1, 0x83, 0xf0, 0x30, 0x3c, 0x10, 0x0f, 0xc5, 0x83, 0xf1,
+0x70, 0x3c, 0x20, 0x0f, 0xc9, 0x83, 0xf2, 0xb0, 0x3c, 0x30,
+0x0f, 0xcd, 0x83, 0xf3, 0x00, 0x00, 0x00,
+'i','s','o','8','8','5','9','8',0,
+14, 33,
+0x00, 0x80, 0x28, 0x30, 0x0a, 0x90, 0x02, 0xa5, 0x80, 0x29,
+0x70, 0x0a, 0xa0, 0x02, 0xa9, 0xc0, 0x35, 0xb0, 0x0a, 0xb0,
+0x02, 0xad, 0x80, 0x2b, 0xf0, 0x0a, 0xc0, 0x02, 0xb1, 0x80,
+0x2c, 0x30, 0x0b, 0xd0, 0x02, 0xb5, 0x80, 0x2d, 0x70, 0x0b,
+0xe0, 0x02, 0xb9, 0xc0, 0x3d, 0xb0, 0x0b, 0xf0, 0x02, 0xbd,
+0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01,
+0x40, 0x17, 0xd1, 0x85, 0x74, 0x30, 0x5d, 0x50, 0x17, 0xd5,
+0x85, 0x75, 0x70, 0x5d, 0x60, 0x17, 0xd9, 0x85, 0x76, 0xb0,
+0x5d, 0x70, 0x17, 0xdd, 0x85, 0x77, 0xf0, 0x5d, 0x80, 0x17,
+0xe1, 0x85, 0x78, 0x30, 0x5e, 0x90, 0x17, 0xe5, 0x85, 0x79,
+0x70, 0x5e, 0xa0, 0x17, 0xe9, 0x85, 0x7a, 0x00, 0x00, 0x00,
+0x00, 0x0e, 0xe0, 0x03, 0x00, 0x00, 0x00,
+'i','s','o','8','8','5','9','9',0,
+9, 80,
+0x1e, 0xa3, 0x49, 0x9b, 0x46, 0xad, 0x9a, 0xb5, 0x6b, 0xd8,
+0xb2, 0x69, 0xdb, 0xc6, 0x0d, 0xa6, 0xd7, 0x6f, 0xe0, 0xc2,
+0x89, 0x1b, 0x47, 0xae, 0x9c, 0xb9, 0x73, 0xe8, 0xd2, 0xa9,
+0x5b, 0xc7, 0xae, 0x9d, 0xbb, 0x77, 0x1f, 0xe3, 0xc9, 0x9b,
+0x47, 0xaf, 0x9e, 0xbd, 0x7b, 0xf8, 0xf2, 0xe9, 0xdb, 0xc7,
+0x2f, 0xe6, 0xd7, 0x7f,
+'i','s','o','8','8','5','9','1','0',0,
+14, 33,
+0x04, 0x81, 0x44, 0x20, 0x12, 0xa8, 0x04, 0x28, 0x81, 0x4d,
+0x70, 0x0a, 0xec, 0x04, 0x10, 0x01, 0x58, 0x60, 0x16, 0xf4,
+0x05, 0xad, 0x80, 0x5a, 0xa0, 0x14, 0xc0, 0x02, 0x05, 0xc1,
+0x44, 0x30, 0x12, 0xac, 0x04, 0x29, 0xc1, 0x4d, 0x70, 0x0b,
+0xf0, 0x04, 0x11, 0x41, 0x58, 0x70, 0x16, 0xf8, 0x05, 0x15,
+0xe0, 0x5a, 0xb0, 0x14, 0x00, 0x04, 0xc1, 0x80, 0x30, 0x30,
+0x0c, 0x10, 0x03, 0xc5, 0x80, 0x31, 0xe0, 0x12, 0x30, 0x04,
+0xc9, 0x00, 0x46, 0xb0, 0x0c, 0x58, 0x04, 0xcd, 0x80, 0x33,
+0xf0, 0x0c, 0x40, 0x03, 0x45, 0x01, 0x53, 0x30, 0x0d, 0x50,
+0x03, 0xd5, 0x80, 0x35, 0x80, 0x16, 0x60, 0x03, 0x72, 0x81,
+0x36, 0xb0, 0x0d, 0x70, 0x03, 0xdd, 0x80, 0x37, 0xf0, 0x0d,
+0x04, 0x04, 0xe1, 0x80, 0x38, 0x30, 0x0e, 0x90, 0x03, 0xe5,
+0x80, 0x39, 0xf0, 0x12, 0x34, 0x04, 0xe9, 0x40, 0x46, 0xb0,
+0x0e, 0x5c, 0x04, 0xed, 0x80, 0x3b, 0xf0, 0x0e, 0xc0, 0x03,
+0x46, 0x41, 0x53, 0x30, 0x0f, 0xd0, 0x03, 0xf5, 0x80, 0x3d,
+0x90, 0x16, 0xe0, 0x03, 0x73, 0x81, 0x3e, 0xb0, 0x0f, 0xf0,
+0x03, 0xfd, 0x80, 0x3f, 0x80, 0x13, 0x00,
+'i','s','o','8','8','5','9','1','3',0,
+14, 33,
+0x1d, 0xa0, 0x28, 0x30, 0x0a, 0x90, 0x02, 0x1e, 0xa0, 0x29,
+0x70, 0x0a, 0x60, 0x03, 0xa9, 0x80, 0x55, 0xb0, 0x0a, 0xb0,
+0x02, 0xad, 0x80, 0x2b, 0x60, 0x0c, 0xc0, 0x02, 0xb1, 0x80,
+0x2c, 0x30, 0x0b, 0x70, 0x80, 0xb5, 0x80, 0x2d, 0x70, 0x0b,
+0xe0, 0x03, 0xb9, 0xc0, 0x55, 0xb0, 0x0b, 0xf0, 0x02, 0xbd,
+0x80, 0x2f, 0x60, 0x0e, 0x10, 0x04, 0x2e, 0x01, 0x40, 0x60,
+0x10, 0x10, 0x03, 0xc5, 0x00, 0x46, 0x20, 0x11, 0x30, 0x04,
+0xc9, 0x40, 0x5e, 0x60, 0x11, 0x88, 0x04, 0x36, 0x81, 0x4a,
+0xb0, 0x13, 0x80, 0x05, 0x43, 0x41, 0x51, 0x30, 0x0d, 0x30,
+0x05, 0xd5, 0x80, 0x35, 0x70, 0x0d, 0xc8, 0x05, 0x41, 0x81,
+0x56, 0xa0, 0x16, 0x70, 0x03, 0x7b, 0x41, 0x5f, 0xf0, 0x0d,
+0x14, 0x04, 0x2f, 0x41, 0x40, 0x70, 0x10, 0x90, 0x03, 0xe5,
+0x40, 0x46, 0x30, 0x11, 0x34, 0x04, 0xe9, 0x80, 0x5e, 0x70,
+0x11, 0x8c, 0x04, 0x37, 0xc1, 0x4a, 0xc0, 0x13, 0x84, 0x05,
+0x44, 0x81, 0x51, 0x30, 0x0f, 0x34, 0x05, 0xf5, 0x80, 0x3d,
+0x70, 0x0f, 0xcc, 0x05, 0x42, 0xc1, 0x56, 0xb0, 0x16, 0xf0,
+0x03, 0x7c, 0x81, 0x5f, 0x90, 0x01, 0x00,
+'i','s','o','8','8','5','9','1','4',0,
+13, 33,
+0x02, 0x7e, 0xc0, 0x8c, 0x02, 0x85, 0xb0, 0x10, 0x14, 0xfc,
+0x29, 0x00, 0xf4, 0xa9, 0x40, 0xd0, 0x2c, 0x78, 0x79, 0xd0,
+0x0a, 0x5c, 0x01, 0x5e, 0xf0, 0xf0, 0x1f, 0x1e, 0x24, 0x84,
+0x04, 0x20, 0x10, 0xe4, 0x6c, 0x81, 0x95, 0x08, 0xf4, 0x57,
+0x7e, 0xd0, 0x80, 0xf9, 0x79, 0x40, 0xe8, 0x0a, 0x7d, 0x98,
+0x00, 0x06, 0xc1, 0x40, 0x18, 0x0c, 0x03, 0x62, 0x50, 0x0c,
+0x8c, 0xc1, 0x31, 0x40, 0x06, 0xc9, 0x40, 0x19, 0x2c, 0x03,
+0x66, 0xd0, 0x0c, 0x9c, 0xc1, 0x33, 0xa0, 0x0b, 0xd1, 0x40,
+0x1a, 0x4c, 0x03, 0x6a, 0x50, 0x0d, 0xac, 0x81, 0x9a, 0xc0,
+0x06, 0xd9, 0x40, 0x1b, 0x6c, 0x03, 0x6e, 0xd0, 0x0d, 0xec,
+0xc2, 0x37, 0x00, 0x07, 0xe1, 0x40, 0x1c, 0x8c, 0x03, 0x72,
+0x50, 0x0e, 0xcc, 0xc1, 0x39, 0x40, 0x07, 0xe9, 0x40, 0x1d,
+0xac, 0x03, 0x76, 0xd0, 0x0e, 0xdc, 0xc1, 0x3b, 0xa8, 0x0b,
+0xf1, 0x40, 0x1e, 0xcc, 0x03, 0x7a, 0x50, 0x0f, 0xec, 0xc1,
+0x9a, 0xc0, 0x07, 0xf9, 0x40, 0x1f, 0xec, 0x03, 0x7e, 0xd0,
+0x0f, 0xee, 0xc2, 0x3f, 0x00,
+'i','s','o','8','8','5','9','1','6',0,
+14, 33,
+0x04, 0x41, 0x41, 0x10, 0x14, 0xb0, 0x82, 0x1e, 0x20, 0x58,
+0x70, 0x0a, 0x84, 0x05, 0xa9, 0x00, 0x86, 0xb0, 0x0a, 0xe4,
+0x05, 0xad, 0x80, 0x5e, 0xb0, 0x17, 0xc0, 0x02, 0xb1, 0x00,
+0x43, 0x20, 0x14, 0xf4, 0x05, 0x1d, 0xa0, 0x2d, 0x70, 0x0b,
+0xf8, 0x05, 0x0d, 0x41, 0x86, 0xb0, 0x0b, 0x48, 0x05, 0x53,
+0x01, 0x5e, 0xc0, 0x17, 0x00, 0x03, 0xc1, 0x80, 0x30, 0x20,
+0x10, 0x10, 0x03, 0x06, 0x81, 0x31, 0x70, 0x0c, 0x20, 0x03,
+0xc9, 0x80, 0x32, 0xb0, 0x0c, 0x30, 0x03, 0xcd, 0x80, 0x33,
+0xf0, 0x0c, 0x40, 0x04, 0x43, 0x81, 0x34, 0x30, 0x0d, 0x50,
+0x03, 0x50, 0x81, 0x35, 0xa0, 0x15, 0xc0, 0x05, 0xd9, 0x80,
+0x36, 0xb0, 0x0d, 0x70, 0x03, 0x18, 0x81, 0x86, 0xf0, 0x0d,
+0x80, 0x03, 0xe1, 0x80, 0x38, 0x30, 0x10, 0x90, 0x03, 0x07,
+0x81, 0x39, 0x70, 0x0e, 0xa0, 0x03, 0xe9, 0x80, 0x3a, 0xb0,
+0x0e, 0xb0, 0x03, 0xed, 0x80, 0x3b, 0xf0, 0x0e, 0x44, 0x04,
+0x44, 0x81, 0x3c, 0x30, 0x0f, 0xd0, 0x03, 0x51, 0x81, 0x3d,
+0xb0, 0x15, 0xc4, 0x05, 0xf9, 0x80, 0x3e, 0xb0, 0x0f, 0xf0,
+0x03, 0x19, 0xc1, 0x86, 0xf0, 0x0f, 0x00,
diff --git a/src/locale/tolower_l.c b/src/locale/tolower_l.c
new file mode 100644
index 00000000..ba277919
--- /dev/null
+++ b/src/locale/tolower_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int tolower_l(int c, locale_t l)
+{
+	return tolower(c);
+}
diff --git a/src/locale/toupper_l.c b/src/locale/toupper_l.c
new file mode 100644
index 00000000..73f2f39b
--- /dev/null
+++ b/src/locale/toupper_l.c
@@ -0,0 +1,6 @@
+#include <ctype.h>
+
+int toupper_l(int c, locale_t l)
+{
+	return toupper(c);
+}
diff --git a/src/locale/wcscoll.c b/src/locale/wcscoll.c
new file mode 100644
index 00000000..cdbce1c2
--- /dev/null
+++ b/src/locale/wcscoll.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+/* FIXME: stub */
+int wcscoll(const wchar_t *l, const wchar_t *r)
+{
+	return wcscmp(l, r);
+}
diff --git a/src/locale/wcsxfrm.c b/src/locale/wcsxfrm.c
new file mode 100644
index 00000000..5f76e5a7
--- /dev/null
+++ b/src/locale/wcsxfrm.c
@@ -0,0 +1,12 @@
+#include <wchar.h>
+
+/* collate only by code points */
+size_t wcsxfrm(wchar_t *dest, const wchar_t *src, size_t n)
+{
+	size_t l = wcslen(src);
+	if (l >= n) {
+		wmemcpy(dest, src, n-1);
+		dest[n-1] = 0;
+	} else wcscpy(dest, src);
+	return l;
+}
diff --git a/src/malloc/DESIGN b/src/malloc/DESIGN
new file mode 100644
index 00000000..58b0523f
--- /dev/null
+++ b/src/malloc/DESIGN
@@ -0,0 +1,22 @@
+
+
+In principle, this memory allocator is roughly equivalent to Doug
+Lea's dlmalloc with fine-grained locking.
+
+
+
+malloc:
+
+Uses a freelist binned by chunk size, with a bitmap to optimize
+searching for the smallest non-empty bin which can satisfy an
+allocation. If no free chunks are available, it creates a new chunk of
+the requested size and attempts to merge it with any existing free
+chunk immediately below the newly created chunk.
+
+Whether the chunk was obtained from a bin or newly created, it's
+likely to be larger than the requested allocation. malloc always
+finishes its work by passing the new chunk to realloc, which will
+split it into two chunks and free the tail portion.
+
+
+
diff --git a/src/malloc/__brk.c b/src/malloc/__brk.c
new file mode 100644
index 00000000..e3b3af31
--- /dev/null
+++ b/src/malloc/__brk.c
@@ -0,0 +1,7 @@
+#include <stdint.h>
+#include "syscall.h"
+
+uintptr_t __brk(uintptr_t newbrk)
+{
+	return syscall1(__NR_brk, newbrk);
+}
diff --git a/src/malloc/__simple_malloc.c b/src/malloc/__simple_malloc.c
new file mode 100644
index 00000000..49b74c8e
--- /dev/null
+++ b/src/malloc/__simple_malloc.c
@@ -0,0 +1,44 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <errno.h>
+#include "libc.h"
+
+uintptr_t __brk(uintptr_t);
+
+#define ALIGN 16
+
+void *__simple_malloc(size_t n)
+{
+	static uintptr_t cur, brk;
+	uintptr_t base, new;
+	static int lock;
+	size_t align=1;
+
+	if (n < SIZE_MAX - ALIGN)
+		while (align<n && align<ALIGN)
+			align += align;
+	n = n + align - 1 & -align;
+
+	LOCK(&lock);
+	if (!cur) cur = brk = __brk(0)+16;
+	if (n > SIZE_MAX - brk) goto fail;
+
+	base = cur + align-1 & -align;
+	if (base+n > brk) {
+		new = base+n + PAGE_SIZE-1 & -PAGE_SIZE;
+		if (__brk(new) != new) goto fail;
+		brk = new;
+	}
+	cur = base+n;
+	UNLOCK(&lock);
+
+	return (void *)base;
+
+fail:
+	UNLOCK(&lock);
+	errno = ENOMEM;
+	return 0;
+}
+
+weak_alias(__simple_malloc, malloc);
diff --git a/src/malloc/calloc.c b/src/malloc/calloc.c
new file mode 100644
index 00000000..9d574562
--- /dev/null
+++ b/src/malloc/calloc.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+void *calloc(size_t m, size_t n)
+{
+	void *p;
+	size_t *z;
+	if (n && m > (size_t)-1/n) {
+		errno = ENOMEM;
+		return 0;
+	}
+	n *= m;
+	p = malloc(n);
+	if (!p) return 0;
+	/* Only do this for non-mmapped chunks */
+	if (((size_t *)p)[-1] & 7) {
+		/* Only write words that are not already zero */
+		m = (n + sizeof *z - 1)/sizeof *z;
+		for (z=p; m; m--, z++) if (*z) *z=0;
+	}
+	return p;
+}
diff --git a/src/malloc/malloc.c b/src/malloc/malloc.c
new file mode 100644
index 00000000..d9a30fe4
--- /dev/null
+++ b/src/malloc/malloc.c
@@ -0,0 +1,515 @@
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include "libc.h"
+#include "atomic.h"
+#include "pthread_impl.h"
+
+uintptr_t __brk(uintptr_t);
+void *__mmap(void *, size_t, int, int, int, off_t);
+int __munmap(void *, size_t);
+void *__mremap(void *, size_t, size_t, int, ...);
+int __madvise(void *, size_t, int);
+
+struct chunk {
+	size_t data[1];
+	struct chunk *next;
+	struct chunk *prev;
+};
+
+struct bin {
+	int lock[2];
+	struct chunk *head;
+	struct chunk *tail;
+};
+
+static struct {
+	uintptr_t brk;
+	size_t *heap;
+	uint64_t binmap;
+	struct bin bins[64];
+	int brk_lock[2];
+	int free_lock[2];
+} mal;
+
+
+#define SIZE_ALIGN (4*sizeof(size_t))
+#define SIZE_MASK (-SIZE_ALIGN)
+#define OVERHEAD (2*sizeof(size_t))
+#define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN)
+#define DONTCARE 16
+#define RECLAIM 163840
+
+#define CHUNK_SIZE(c) ((c)->data[0] & SIZE_MASK)
+#define CHUNK_PSIZE(c) ((c)->data[-1] & SIZE_MASK)
+#define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c)))
+#define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c)))
+#define MEM_TO_CHUNK(p) (struct chunk *)((size_t *)p - 1)
+#define CHUNK_TO_MEM(c) (void *)((c)->data+1)
+#define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head))
+
+#define C_INUSE  ((size_t)1)
+#define C_FLAGS  ((size_t)3)
+#define C_SIZE   SIZE_MASK
+
+#define IS_MMAPPED(c) !((c)->data[0] & (C_INUSE))
+
+
+/* Synchronization tools */
+
+static void lock(volatile int *lk)
+{
+	if (!libc.threads_minus_1) return;
+	while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1);
+}
+
+static void unlock(volatile int *lk)
+{
+	if (!libc.threads_minus_1) return;
+	a_store(lk, 0);
+	if (lk[1]) __wake(lk, 1, 1);
+}
+
+static void lock_bin(int i)
+{
+	if (libc.threads_minus_1)
+		lock(mal.bins[i].lock);
+	if (!mal.bins[i].head)
+		mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i);
+}
+
+static void unlock_bin(int i)
+{
+	if (!libc.threads_minus_1) return;
+	unlock(mal.bins[i].lock);
+}
+
+static int first_set(uint64_t x)
+{
+#if 1
+	return a_ctz_64(x);
+#else
+	static const char debruijn64[64] = {
+		0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
+		62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
+		63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
+		51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
+	};
+	static const char debruijn32[32] = {
+		0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13,
+		31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14
+	};
+	if (sizeof(long) < 8) {
+		uint32_t y = x;
+		if (!y) {
+			y = x>>32;
+			return 32 + debruijn32[(y&-y)*0x076be629 >> 27];
+		}
+		return debruijn32[(y&-y)*0x076be629 >> 27];
+	}
+	return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58];
+#endif
+}
+
+static int bin_index(size_t x)
+{
+	x = x / SIZE_ALIGN - 1;
+	if (x <= 32) return x;
+	if (x > 0x1c00) return 63;
+	return ((union { float v; uint32_t r; }){ x }.r>>21) - 496;
+}
+
+static int bin_index_up(size_t x)
+{
+	x = x / SIZE_ALIGN - 1;
+	if (x <= 32) return x;
+	return ((union { float v; uint32_t r; }){ x }.r+0x1fffff>>21) - 496;
+}
+
+#if 0
+void __dump_heap(int x)
+{
+	struct chunk *c;
+	int i;
+	for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c))
+		fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n",
+			c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)),
+			c->data[0] & 15,
+			NEXT_CHUNK(c)->data[-1] & 15);
+	for (i=0; i<64; i++) {
+		if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) {
+			fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head);
+			if (!(mal.binmap & 1ULL<<i))
+				fprintf(stderr, "missing from binmap!\n");
+		} else if (mal.binmap & 1ULL<<i)
+			fprintf(stderr, "binmap wrongly contains %d!\n", i);
+	}
+}
+#endif
+
+static struct chunk *expand_heap(size_t n)
+{
+	struct chunk *w;
+	uintptr_t new;
+
+	lock(mal.brk_lock);
+
+	if (n > SIZE_MAX - mal.brk - 2*PAGE_SIZE) goto fail;
+	new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE;
+	n = new - mal.brk;
+
+	if (__brk(new) != new) goto fail;
+
+	w = MEM_TO_CHUNK(new);
+	w->data[-1] = n | C_INUSE;
+	w->data[0] = 0 | C_INUSE;
+
+	w = MEM_TO_CHUNK(mal.brk);
+	w->data[0] = n | C_INUSE;
+	mal.brk = new;
+	
+	unlock(mal.brk_lock);
+
+	return w;
+fail:
+	unlock(mal.brk_lock);
+	return 0;
+}
+
+static int init_malloc()
+{
+	static int init, waiters;
+	int state;
+	struct chunk *c;
+
+	if (init == 2) return 0;
+
+	while ((state=a_swap(&init, 1)) == 1)
+		__wait(&init, &waiters, 1, 1);
+	if (state) {
+		a_store(&init, 2);
+		return 0;
+	}
+
+	mal.brk = __brk(0) + 2*SIZE_ALIGN-1 & -SIZE_ALIGN;
+
+	c = expand_heap(1);
+
+	if (!c) {
+		a_store(&init, 0);
+		if (waiters) __wake(&init, 1, 1);
+		return -1;
+	}
+
+	mal.heap = (void *)c;
+	c->data[-1] = 0 | C_INUSE;
+	free(CHUNK_TO_MEM(c));
+
+	a_store(&init, 2);
+	if (waiters) __wake(&init, -1, 1);
+	return 0;
+}
+
+static int adjust_size(size_t *n)
+{
+	/* Result of pointer difference must fit in ptrdiff_t. */
+	if (*n > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) {
+		errno = ENOMEM;
+		return -1;
+	}
+	*n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
+	return 0;
+}
+
+static void unbin(struct chunk *c, int i)
+{
+	if (c->prev == c->next)
+		a_and_64(&mal.binmap, ~(1ULL<<i));
+	c->prev->next = c->next;
+	c->next->prev = c->prev;
+	c->data[0] |= C_INUSE;
+	NEXT_CHUNK(c)->data[-1] |= C_INUSE;
+}
+
+static int alloc_fwd(struct chunk *c)
+{
+	int i;
+	size_t k;
+	while (!((k=c->data[0]) & C_INUSE)) {
+		i = bin_index(k);
+		lock_bin(i);
+		if (c->data[0] == k) {
+			unbin(c, i);
+			unlock_bin(i);
+			return 1;
+		}
+		unlock_bin(i);
+	}
+	return 0;
+}
+
+static int alloc_rev(struct chunk *c)
+{
+	int i;
+	size_t k;
+	while (!((k=c->data[-1]) & C_INUSE)) {
+		i = bin_index(k);
+		lock_bin(i);
+		if (c->data[-1] == k) {
+			unbin(PREV_CHUNK(c), i);
+			unlock_bin(i);
+			return 1;
+		}
+		unlock_bin(i);
+	}
+	return 0;
+}
+
+
+/* pretrim - trims a chunk _prior_ to removing it from its bin.
+ * Must be called with i as the ideal bin for size n, j the bin
+ * for the _free_ chunk self, and bin j locked. */
+static int pretrim(struct chunk *self, size_t n, int i, int j)
+{
+	size_t n1;
+	struct chunk *next, *split;
+
+	/* We cannot pretrim if it would require re-binning. */
+	if (j < 40) return 0;
+	if (j < i+3) {
+		if (j != 63) return 0;
+		n1 = CHUNK_SIZE(self);
+		if (n1-n <= MMAP_THRESHOLD) return 0;
+	} else {
+		n1 = CHUNK_SIZE(self);
+	}
+	if (bin_index(n1-n) != j) return 0;
+
+	next = NEXT_CHUNK(self);
+	split = (void *)((char *)self + n);
+
+	split->prev = self->prev;
+	split->next = self->next;
+	split->prev->next = split;
+	split->next->prev = split;
+	split->data[-1] = n | C_INUSE;
+	split->data[0] = n1-n;
+	next->data[-1] = n1-n;
+	self->data[0] = n | C_INUSE;
+	return 1;
+}
+
+static void trim(struct chunk *self, size_t n)
+{
+	size_t n1 = CHUNK_SIZE(self);
+	struct chunk *next, *split;
+
+	if (n >= n1 - DONTCARE) return;
+
+	next = NEXT_CHUNK(self);
+	split = (void *)((char *)self + n);
+
+	split->data[-1] = n | C_INUSE;
+	split->data[0] = n1-n | C_INUSE;
+	next->data[-1] = n1-n | C_INUSE;
+	self->data[0] = n | C_INUSE;
+
+	free(CHUNK_TO_MEM(split));
+}
+
+void *malloc(size_t n)
+{
+	struct chunk *c;
+	int i, j;
+
+	if (!n || adjust_size(&n) < 0) return 0;
+
+	if (n > MMAP_THRESHOLD) {
+		size_t len = n + PAGE_SIZE - 1 & -PAGE_SIZE;
+		char *base = __mmap(0, len, PROT_READ|PROT_WRITE,
+			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+		if (base == (void *)-1) return 0;
+		c = (void *)(base + SIZE_ALIGN - sizeof(size_t));
+		c->data[0] = len - (SIZE_ALIGN - sizeof(size_t));
+		c->data[-1] = SIZE_ALIGN - sizeof(size_t);
+		return CHUNK_TO_MEM(c);
+	}
+
+	i = bin_index_up(n);
+	for (;;) {
+		uint64_t mask = mal.binmap & -(1ULL<<i);
+		if (!mask) {
+			init_malloc();
+			c = expand_heap(n);
+			if (!c) return 0;
+			if (alloc_rev(c)) {
+				struct chunk *x = c;
+				c = PREV_CHUNK(c);
+				NEXT_CHUNK(x)->data[-1] = c->data[0] =
+					x->data[0] + CHUNK_SIZE(c);
+			}
+			break;
+		}
+		j = first_set(mask);
+		lock_bin(j);
+		c = mal.bins[j].head;
+		if (c != BIN_TO_CHUNK(j) && j == bin_index(c->data[0])) {
+			if (!pretrim(c, n, i, j)) unbin(c, j);
+			unlock_bin(j);
+			break;
+		}
+		unlock_bin(j);
+	}
+
+	/* Now patch up in case we over-allocated */
+	trim(c, n);
+
+	return CHUNK_TO_MEM(c);
+}
+
+void *realloc(void *p, size_t n)
+{
+	struct chunk *self, *next;
+	size_t n0, n1;
+	void *new;
+
+	if (!p) return malloc(n);
+	else if (!n) return free(p), (void *)0;
+
+	if (adjust_size(&n) < 0) return 0;
+
+	self = MEM_TO_CHUNK(p);
+	n1 = n0 = CHUNK_SIZE(self);
+
+	if (IS_MMAPPED(self)) {
+		size_t extra = self->data[-1];
+		char *base = (char *)self - extra;
+		size_t oldlen = n0 + extra;
+		size_t newlen = n + extra;
+		if (newlen < PAGE_SIZE && (new = malloc(n))) {
+			memcpy(new, p, n-OVERHEAD);
+			free(p);
+			return new;
+		}
+		newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE;
+		if (oldlen == newlen) return p;
+		base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE);
+		if (base == (void *)-1)
+			return newlen < oldlen ? p : 0;
+		self = (void *)(base + extra);
+		self->data[0] = newlen - extra;
+		return CHUNK_TO_MEM(self);
+	}
+
+	next = NEXT_CHUNK(self);
+
+	/* Merge adjacent chunks if we need more space. This is not
+	 * a waste of time even if we fail to get enough space, because our
+	 * subsequent call to free would otherwise have to do the merge. */
+	if (n > n1 && alloc_fwd(next)) {
+		n1 += CHUNK_SIZE(next);
+		next = NEXT_CHUNK(next);
+	}
+	/* FIXME: find what's wrong here and reenable it..? */
+	if (0 && n > n1 && alloc_rev(self)) {
+		self = PREV_CHUNK(self);
+		n1 += CHUNK_SIZE(self);
+	}
+	self->data[0] = n1 | C_INUSE;
+	next->data[-1] = n1 | C_INUSE;
+
+	/* If we got enough space, split off the excess and return */
+	if (n <= n1) {
+		//memmove(CHUNK_TO_MEM(self), p, n0-OVERHEAD);
+		trim(self, n);
+		return CHUNK_TO_MEM(self);
+	}
+
+	/* As a last resort, allocate a new chunk and copy to it. */
+	new = malloc(n-OVERHEAD);
+	if (!new) return 0;
+	memcpy(new, p, n0-OVERHEAD);
+	free(CHUNK_TO_MEM(self));
+	return new;
+}
+
+void free(void *p)
+{
+	struct chunk *self = MEM_TO_CHUNK(p);
+	struct chunk *next;
+	size_t final_size, new_size, size;
+	int reclaim=0;
+	int i;
+
+	if (!p) return;
+
+	if (IS_MMAPPED(self)) {
+		size_t extra = self->data[-1];
+		char *base = (char *)self - extra;
+		size_t len = CHUNK_SIZE(self) + extra;
+		__munmap(base, len);
+		return;
+	}
+
+	final_size = new_size = CHUNK_SIZE(self);
+	next = NEXT_CHUNK(self);
+
+	for (;;) {
+		/* Replace middle of large chunks with fresh zero pages */
+		if (reclaim && (self->data[-1] & next->data[0] & C_INUSE)) {
+			uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE;
+			uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE;
+#if 1
+			__madvise((void *)a, b-a, MADV_DONTNEED);
+#else
+			__mmap((void *)a, b-a, PROT_READ|PROT_WRITE,
+				MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
+#endif
+		}
+
+		if (self->data[-1] & next->data[0] & C_INUSE) {
+			self->data[0] = final_size | C_INUSE;
+			next->data[-1] = final_size | C_INUSE;
+			i = bin_index(final_size);
+			lock_bin(i);
+			lock(mal.free_lock);
+			if (self->data[-1] & next->data[0] & C_INUSE)
+				break;
+			unlock(mal.free_lock);
+			unlock_bin(i);
+		}
+
+		if (alloc_rev(self)) {
+			self = PREV_CHUNK(self);
+			size = CHUNK_SIZE(self);
+			final_size += size;
+			if (new_size+size > RECLAIM && (new_size+size^size) > size)
+				reclaim = 1;
+		}
+
+		if (alloc_fwd(next)) {
+			size = CHUNK_SIZE(next);
+			final_size += size;
+			if (new_size+size > RECLAIM && (new_size+size^size) > size)
+				reclaim = 1;
+			next = NEXT_CHUNK(next);
+		}
+	}
+
+	self->data[0] = final_size;
+	next->data[-1] = final_size;
+	unlock(mal.free_lock);
+
+	self->next = BIN_TO_CHUNK(i);
+	self->prev = mal.bins[i].tail;
+	self->next->prev = self;
+	self->prev->next = self;
+
+	if (!(mal.binmap & 1ULL<<i))
+		a_or_64(&mal.binmap, 1ULL<<i);
+
+	unlock_bin(i);
+}
diff --git a/src/malloc/memalign.c b/src/malloc/memalign.c
new file mode 100644
index 00000000..61f456e4
--- /dev/null
+++ b/src/malloc/memalign.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+#include <errno.h>
+
+void *memalign(size_t align, size_t len)
+{
+	void *mem;
+	int ret;
+	if ((ret = posix_memalign(&mem, align, len))) {
+		errno = ret;
+		return 0;
+	}
+	return mem;
+}
diff --git a/src/malloc/posix_memalign.c b/src/malloc/posix_memalign.c
new file mode 100644
index 00000000..ef86260d
--- /dev/null
+++ b/src/malloc/posix_memalign.c
@@ -0,0 +1,47 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+/* This function should work with most dlmalloc-like chunk bookkeeping
+ * systems, but it's only guaranteed to work with the native implementation
+ * used in this library. */
+
+int posix_memalign(void **res, size_t align, size_t len)
+{
+	unsigned char *mem, *new, *end;
+	size_t header, footer;
+
+	if ((align & -align) != align) return EINVAL;
+	if (len > SIZE_MAX - align) return ENOMEM;
+
+	if (align <= 4*sizeof(size_t)) {
+		if (!(mem = malloc(len)))
+			return errno;
+		*res = mem;
+		return 0;
+	}
+
+	if (!(mem = malloc(len + align-1)))
+		return errno;
+
+	header = ((size_t *)mem)[-1];
+	end = mem + (header & -8);
+	footer = ((size_t *)end)[-2];
+	new = (void *)((uintptr_t)mem + align-1 & -align);
+
+	if (!(header & 7)) {
+		((size_t *)new)[-2] = ((size_t *)mem)[-2] + (new-mem);
+		((size_t *)new)[-1] = ((size_t *)mem)[-1] - (new-mem);
+		*res = new;
+		return 0;
+	}
+
+	((size_t *)mem)[-1] = header&7 | new-mem;
+	((size_t *)new)[-2] = footer&7 | new-mem;
+	((size_t *)new)[-1] = header&7 | end-new;
+	((size_t *)end)[-2] = footer&7 | end-new;
+
+	if (new != mem) free(mem);
+	*res = new;
+	return 0;
+}
diff --git a/src/math/__fpclassify.c b/src/math/__fpclassify.c
new file mode 100644
index 00000000..16051100
--- /dev/null
+++ b/src/math/__fpclassify.c
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <math.h>
+
+int __fpclassify(double __x)
+{
+	union {
+		double __d;
+		__uint64_t __i;
+	} __y = { __x };
+	int __ee = __y.__i>>52 & 0x7ff;
+	if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO;
+	if (__ee==0x7ff) return __y.__i<<12 ? FP_NAN : FP_INFINITE;
+	return FP_NORMAL;
+}
diff --git a/src/math/__fpclassifyf.c b/src/math/__fpclassifyf.c
new file mode 100644
index 00000000..bf59d0d4
--- /dev/null
+++ b/src/math/__fpclassifyf.c
@@ -0,0 +1,14 @@
+#include <stdint.h>
+#include <math.h>
+
+int __fpclassifyf(float __x)
+{
+	union {
+		float __f;
+		__uint32_t __i;
+	} __y = { __x };
+	int __ee = __y.__i>>23 & 0xff;
+	if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO;
+	if (__ee==0xff) return __y.__i<<9 ? FP_NAN : FP_INFINITE;
+	return FP_NORMAL;
+}
diff --git a/src/math/__fpclassifyl.c b/src/math/__fpclassifyl.c
new file mode 100644
index 00000000..4f93bef1
--- /dev/null
+++ b/src/math/__fpclassifyl.c
@@ -0,0 +1,16 @@
+#include <stdint.h>
+#include <math.h>
+
+/* FIXME: move this to arch-specific file */
+int __fpclassifyl(long double __x)
+{
+	union {
+		long double __ld;
+		__uint16_t __hw[5];
+		__uint64_t __m;
+	} __y = { __x };
+	int __ee = __y.__hw[4]&0x7fff;
+	if (!__ee) return __y.__m ? FP_SUBNORMAL : FP_ZERO;
+	if (__ee==0x7fff) return __y.__m ? FP_NAN : FP_INFINITE;
+	return FP_NORMAL;
+}
diff --git a/src/math/e_acos.c b/src/math/e_acos.c
new file mode 100644
index 00000000..e0236391
--- /dev/null
+++ b/src/math/e_acos.c
@@ -0,0 +1,99 @@
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* acos(x)
+ * Method :                  
+ *      acos(x)  = pi/2 - asin(x)
+ *      acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ *      acos(x) = pi/2 - (x + x*x^2*R(x^2))     (see asin.c)
+ * For x>0.5
+ *      acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ *              = 2asin(sqrt((1-x)/2))  
+ *              = 2s + 2s*z*R(z)        ...z=(1-x)/2, s=sqrt(z)
+ *              = 2f + (2c + 2s*z*R(z))
+ *     where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ *     for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ *      acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ *              = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ *      if x is NaN, return x itself;
+ *      if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one=  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+double
+acos(double x)
+{
+        double z,p,q,r,w,s,c,df;
+        int32_t hx,ix;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x3ff00000) {    /* |x| >= 1 */
+            uint32_t lx;
+            GET_LOW_WORD(lx,x);
+            if(((ix-0x3ff00000)|lx)==0) {       /* |x|==1 */
+                if(hx>0) return 0.0;            /* acos(1) = 0  */
+                else return pi+2.0*pio2_lo;     /* acos(-1)= pi */
+            }
+            return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+        }
+        if(ix<0x3fe00000) {     /* |x| < 0.5 */
+            if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+            z = x*x;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            return pio2_hi - (x - (pio2_lo-x*r));
+        } else  if (hx<0) {             /* x < -0.5 */
+            z = (one+x)*0.5;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            s = sqrt(z);
+            r = p/q;
+            w = r*s-pio2_lo;
+            return pi - 2.0*(s+w);
+        } else {                        /* x > 0.5 */
+            z = (one-x)*0.5;
+            s = sqrt(z);
+            df = s;
+            SET_LOW_WORD(df,0);
+            c  = (z-df*df)/(s+df);
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            w = r*s+c;
+            return 2.0*(df+w);
+        }
+}
diff --git a/src/math/e_acosf.c b/src/math/e_acosf.c
new file mode 100644
index 00000000..4c59781b
--- /dev/null
+++ b/src/math/e_acosf.c
@@ -0,0 +1,77 @@
+/* e_acosf.c -- float version of e_acos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+pi =  3.1415925026e+00, /* 0x40490fda */
+pio2_hi =  1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo =  7.5497894159e-08, /* 0x33a22168 */
+pS0 =  1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 =  2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 =  7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 =  3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 =  2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 =  7.7038154006e-02; /* 0x3d9dc62e */
+
+float
+acosf(float x)
+{
+        float z,p,q,r,w,s,c,df;
+        int32_t hx,ix;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix==0x3f800000) {            /* |x|==1 */
+            if(hx>0) return 0.0;        /* acos(1) = 0  */
+            else return pi+(float)2.0*pio2_lo;  /* acos(-1)= pi */
+        } else if(ix>0x3f800000) {      /* |x| >= 1 */
+            return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+        }
+        if(ix<0x3f000000) {     /* |x| < 0.5 */
+            if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+            z = x*x;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            return pio2_hi - (x - (pio2_lo-x*r));
+        } else  if (hx<0) {             /* x < -0.5 */
+            z = (one+x)*(float)0.5;
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            s = sqrtf(z);
+            r = p/q;
+            w = r*s-pio2_lo;
+            return pi - (float)2.0*(s+w);
+        } else {                        /* x > 0.5 */
+            int32_t idf;
+            z = (one-x)*(float)0.5;
+            s = sqrtf(z);
+            df = s;
+            GET_FLOAT_WORD(idf,df);
+            SET_FLOAT_WORD(df,idf&0xfffff000);
+            c  = (z-df*df)/(s+df);
+            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+            r = p/q;
+            w = r*s+c;
+            return (float)2.0*(df+w);
+        }
+}
diff --git a/src/math/e_acosh.c b/src/math/e_acosh.c
new file mode 100644
index 00000000..8b454e75
--- /dev/null
+++ b/src/math/e_acosh.c
@@ -0,0 +1,59 @@
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* acosh(x)
+ * Method :
+ *      Based on 
+ *              acosh(x) = log [ x + sqrt(x*x-1) ]
+ *      we have
+ *              acosh(x) := log(x)+ln2, if x is large; else
+ *              acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ *              acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ *      acosh(x) is NaN with signal if x<1.
+ *      acosh(NaN) is NaN without signal.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one     = 1.0,
+ln2     = 6.93147180559945286227e-01;  /* 0x3FE62E42, 0xFEFA39EF */
+
+double
+acosh(double x)
+{
+        double t;
+        int32_t hx;
+        uint32_t lx;
+        EXTRACT_WORDS(hx,lx,x);
+        if(hx<0x3ff00000) {             /* x < 1 */
+            return (x-x)/(x-x);
+        } else if(hx >=0x41b00000) {    /* x > 2**28 */
+            if(hx >=0x7ff00000) {       /* x is inf of NaN */
+                return x+x;
+            } else 
+                return log(x)+ln2;    /* acosh(huge)=log(2x) */
+        } else if(((hx-0x3ff00000)|lx)==0) {
+            return 0.0;                 /* acosh(1) = 0 */
+        } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */
+            t=x*x;
+            return log(2.0*x-one/(x+sqrt(t-one)));
+        } else {                        /* 1<x<2 */
+            t = x-one;
+            return log1p(t+sqrt(2.0*t+t*t));
+        }
+}
diff --git a/src/math/e_acoshf.c b/src/math/e_acoshf.c
new file mode 100644
index 00000000..b7f1df69
--- /dev/null
+++ b/src/math/e_acoshf.c
@@ -0,0 +1,45 @@
+/* e_acoshf.c -- float version of e_acosh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+one     = 1.0,
+ln2     = 6.9314718246e-01;  /* 0x3f317218 */
+
+float
+acoshf(float x)
+{
+        float t;
+        int32_t hx;
+        GET_FLOAT_WORD(hx,x);
+        if(hx<0x3f800000) {             /* x < 1 */
+            return (x-x)/(x-x);
+        } else if(hx >=0x4d800000) {    /* x > 2**28 */
+            if(hx >=0x7f800000) {       /* x is inf of NaN */
+                return x+x;
+            } else
+                return logf(x)+ln2;     /* acosh(huge)=log(2x) */
+        } else if (hx==0x3f800000) {
+            return 0.0;                 /* acosh(1) = 0 */
+        } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */
+            t=x*x;
+            return logf((float)2.0*x-one/(x+sqrtf(t-one)));
+        } else {                        /* 1<x<2 */
+            t = x-one;
+            return log1pf(t+sqrtf((float)2.0*t+t*t));
+        }
+}
diff --git a/src/math/e_asin.c b/src/math/e_asin.c
new file mode 100644
index 00000000..4bf162a1
--- /dev/null
+++ b/src/math/e_asin.c
@@ -0,0 +1,109 @@
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* asin(x)
+ * Method :                  
+ *      Since  asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ *      we approximate asin(x) on [0,0.5] by
+ *              asin(x) = x + x*x^2*R(x^2)
+ *      where
+ *              R(x^2) is a rational approximation of (asin(x)-x)/x^3 
+ *      and its remez error is bounded by
+ *              |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ *      For x in [0.5,1]
+ *              asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ *      Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ *      then for x>0.98
+ *              asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *                      = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ *      For x<=0.98, let pio4_hi = pio2_hi/2, then
+ *              f = hi part of s;
+ *              c = sqrt(z) - f = (z-f*f)/(s+f)         ...f+c=sqrt(z)
+ *      and
+ *              asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *                      = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ *                      = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ *      if x is NaN, return x itself;
+ *      if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+huge =  1.000e+300,
+pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi =  7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+        /* coefficient for R(x^2) */
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+double
+asin(double x)
+{
+        double t=0.0,w,p,q,c,r,s;
+        int32_t hx,ix;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>= 0x3ff00000) {           /* |x|>= 1 */
+            uint32_t lx;
+            GET_LOW_WORD(lx,x);
+            if(((ix-0x3ff00000)|lx)==0)
+                    /* asin(1)=+-pi/2 with inexact */
+                return x*pio2_hi+x*pio2_lo;     
+            return (x-x)/(x-x);         /* asin(|x|>1) is NaN */   
+        } else if (ix<0x3fe00000) {     /* |x|<0.5 */
+            if(ix<0x3e400000) {         /* if |x| < 2**-27 */
+                if(huge+x>one) return x;/* return x with inexact if x!=0*/
+            } else 
+                t = x*x;
+                p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+                q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+                w = p/q;
+                return x+x*w;
+        }
+        /* 1> |x|>= 0.5 */
+        w = one-fabs(x);
+        t = w*0.5;
+        p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+        q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+        s = sqrt(t);
+        if(ix>=0x3FEF3333) {    /* if |x| > 0.975 */
+            w = p/q;
+            t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+        } else {
+            w  = s;
+            SET_LOW_WORD(w,0);
+            c  = (t-w*w)/(s+w);
+            r  = p/q;
+            p  = 2.0*s*r-(pio2_lo-2.0*c);
+            q  = pio4_hi-2.0*w;
+            t  = pio4_hi-(p-q);
+        }    
+        if(hx>0) return t; else return -t;    
+}
diff --git a/src/math/e_asinf.c b/src/math/e_asinf.c
new file mode 100644
index 00000000..9c693970
--- /dev/null
+++ b/src/math/e_asinf.c
@@ -0,0 +1,80 @@
+/* e_asinf.c -- float version of e_asin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+huge =  1.000e+30,
+pio2_hi =  1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo =  7.5497894159e-08, /* 0x33a22168 */
+pio4_hi =  7.8539818525e-01, /* 0x3f490fdb */
+	/* coefficient for R(x^2) */
+pS0 =  1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 =  2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 =  7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 =  3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 =  2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 =  7.7038154006e-02; /* 0x3d9dc62e */
+
+float
+asinf(float x)
+{
+	float t=0.0,w,p,q,c,r,s;
+	int32_t hx,ix;
+	GET_FLOAT_WORD(hx,x);
+	ix = hx&0x7fffffff;
+	if(ix==0x3f800000) {
+		/* asin(1)=+-pi/2 with inexact */
+	    return x*pio2_hi+x*pio2_lo;
+	} else if(ix> 0x3f800000) {	/* |x|>= 1 */
+	    return (x-x)/(x-x);		/* asin(|x|>1) is NaN */
+	} else if (ix<0x3f000000) {	/* |x|<0.5 */
+	    if(ix<0x32000000) {		/* if |x| < 2**-27 */
+		if(huge+x>one) return x;/* return x with inexact if x!=0*/
+	    } else
+		t = x*x;
+		p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+		q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+		w = p/q;
+		return x+x*w;
+	}
+	/* 1> |x|>= 0.5 */
+	w = one-fabsf(x);
+	t = w*(float)0.5;
+	p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+	q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+	s = sqrtf(t);
+	if(ix>=0x3F79999A) { 	/* if |x| > 0.975 */
+	    w = p/q;
+	    t = pio2_hi-((float)2.0*(s+s*w)-pio2_lo);
+	} else {
+	    int32_t iw;
+	    w  = s;
+	    GET_FLOAT_WORD(iw,w);
+	    SET_FLOAT_WORD(w,iw&0xfffff000);
+	    c  = (t-w*w)/(s+w);
+	    r  = p/q;
+	    p  = (float)2.0*s*r-(pio2_lo-(float)2.0*c);
+	    q  = pio4_hi-(float)2.0*w;
+	    t  = pio4_hi-(p-q);
+	}
+	if(hx>0) return t; else return -t;
+}
diff --git a/src/math/e_atan2.c b/src/math/e_atan2.c
new file mode 100644
index 00000000..dd021164
--- /dev/null
+++ b/src/math/e_atan2.c
@@ -0,0 +1,120 @@
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atan2(y,x)
+ * Method :
+ *      1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ *      2. Reduce x to positive by (if x and y are unexceptional): 
+ *              ARG (x+iy) = arctan(y/x)           ... if x > 0,
+ *              ARG (x+iy) = pi - arctan[y/(-x)]   ... if x < 0,
+ *
+ * Special cases:
+ *
+ *      ATAN2((anything), NaN ) is NaN;
+ *      ATAN2(NAN , (anything) ) is NaN;
+ *      ATAN2(+-0, +(anything but NaN)) is +-0  ;
+ *      ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ *      ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ *      ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ *      ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ *      ATAN2(+-INF,+INF ) is +-pi/4 ;
+ *      ATAN2(+-INF,-INF ) is +-3pi/4;
+ *      ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+tiny  = 1.0e-300,
+zero  = 0.0,
+pi_o_4  = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2  = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi      = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo   = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+double
+atan2(double y, double x)
+{
+        double z;
+        int32_t k,m,hx,hy,ix,iy;
+        uint32_t lx,ly;
+
+        EXTRACT_WORDS(hx,lx,x);
+        ix = hx&0x7fffffff;
+        EXTRACT_WORDS(hy,ly,y);
+        iy = hy&0x7fffffff;
+        if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+           ((iy|((ly|-ly)>>31))>0x7ff00000))    /* x or y is NaN */
+           return x+y;
+        if(((hx-0x3ff00000)|lx)==0) return atan(y);   /* x=1.0 */
+        m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+        if((iy|ly)==0) {
+            switch(m) {
+                case 0: 
+                case 1: return y;       /* atan(+-0,+anything)=+-0 */
+                case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+                case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+            }
+        }
+    /* when x = 0 */
+        if((ix|lx)==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;
+            
+    /* when x is INF */
+        if(ix==0x7ff00000) {
+            if(iy==0x7ff00000) {
+                switch(m) {
+                    case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */
+                    case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+                    case 2: return  3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+                    case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+                }
+            } else {
+                switch(m) {
+                    case 0: return  zero  ;     /* atan(+...,+INF) */
+                    case 1: return -zero  ;     /* atan(-...,+INF) */
+                    case 2: return  pi+tiny  ;  /* atan(+...,-INF) */
+                    case 3: return -pi-tiny  ;  /* atan(-...,-INF) */
+                }
+            }
+        }
+    /* when y is INF */
+        if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* compute y/x */
+        k = (iy-ix)>>20;
+        if(k > 60) z=pi_o_2+0.5*pi_lo;  /* |y/x| >  2**60 */
+        else if(hx<0&&k<-60) z=0.0;     /* |y|/x < -2**60 */
+        else z=atan(fabs(y/x));         /* safe to do y/x */
+        switch (m) {
+            case 0: return       z  ;   /* atan(+,+) */
+            case 1: {
+                      uint32_t zh;
+                      GET_HIGH_WORD(zh,z);
+                      SET_HIGH_WORD(z,zh ^ 0x80000000);
+                    }
+                    return       z  ;   /* atan(-,+) */
+            case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+            default: /* case 3 */
+                    return  (z-pi_lo)-pi;/* atan(-,-) */
+        }
+}
diff --git a/src/math/e_atan2f.c b/src/math/e_atan2f.c
new file mode 100644
index 00000000..535e10a0
--- /dev/null
+++ b/src/math/e_atan2f.c
@@ -0,0 +1,93 @@
+/* e_atan2f.c -- float version of e_atan2.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+tiny  = 1.0e-30,
+zero  = 0.0,
+pi_o_4  = 7.8539818525e-01, /* 0x3f490fdb */
+pi_o_2  = 1.5707963705e+00, /* 0x3fc90fdb */
+pi      = 3.1415927410e+00, /* 0x40490fdb */
+pi_lo   = -8.7422776573e-08; /* 0xb3bbbd2e */
+
+float
+atan2f(float y, float x)
+{
+        float z;
+        int32_t k,m,hx,hy,ix,iy;
+
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        GET_FLOAT_WORD(hy,y);
+        iy = hy&0x7fffffff;
+        if((ix>0x7f800000)||
+           (iy>0x7f800000))     /* x or y is NaN */
+           return x+y;
+        if(hx==0x3f800000) return atanf(y);   /* x=1.0 */
+        m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+        if(iy==0) {
+            switch(m) {
+                case 0:
+                case 1: return y;       /* atan(+-0,+anything)=+-0 */
+                case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+                case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+            }
+        }
+    /* when x = 0 */
+        if(ix==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* when x is INF */
+        if(ix==0x7f800000) {
+            if(iy==0x7f800000) {
+                switch(m) {
+                    case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */
+                    case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+                    case 2: return  (float)3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+                    case 3: return (float)-3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+                }
+            } else {
+                switch(m) {
+                    case 0: return  zero  ;     /* atan(+...,+INF) */
+                    case 1: return -zero  ;     /* atan(-...,+INF) */
+                    case 2: return  pi+tiny  ;  /* atan(+...,-INF) */
+                    case 3: return -pi-tiny  ;  /* atan(-...,-INF) */
+                }
+            }
+        }
+    /* when y is INF */
+        if(iy==0x7f800000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* compute y/x */
+        k = (iy-ix)>>23;
+        if(k > 60) z=pi_o_2+(float)0.5*pi_lo;   /* |y/x| >  2**60 */
+        else if(hx<0&&k<-60) z=0.0;     /* |y|/x < -2**60 */
+        else z=atanf(fabsf(y/x));       /* safe to do y/x */
+        switch (m) {
+            case 0: return       z  ;   /* atan(+,+) */
+            case 1: {
+                      uint32_t zh;
+                      GET_FLOAT_WORD(zh,z);
+                      SET_FLOAT_WORD(z,zh ^ 0x80000000);
+                    }
+                    return       z  ;   /* atan(-,+) */
+            case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+            default: /* case 3 */
+                    return  (z-pi_lo)-pi;/* atan(-,-) */
+        }
+}
diff --git a/src/math/e_atanh.c b/src/math/e_atanh.c
new file mode 100644
index 00000000..45f1c966
--- /dev/null
+++ b/src/math/e_atanh.c
@@ -0,0 +1,59 @@
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atanh(x)
+ * Method :
+ *    1.Reduced x to positive by atanh(-x) = -atanh(x)
+ *    2.For x>=0.5
+ *                  1              2x                          x
+ *      atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ *                  2             1 - x                      1 - x
+ *      
+ *      For x<0.5
+ *      atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ *      atanh(x) is NaN if |x| > 1 with signal;
+ *      atanh(NaN) is that NaN with no signal;
+ *      atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, huge = 1e300;
+static const double zero = 0.0;
+
+double
+atanh(double x)
+{
+        double t;
+        int32_t hx,ix;
+        uint32_t lx;
+        EXTRACT_WORDS(hx,lx,x);
+        ix = hx&0x7fffffff;
+        if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+            return (x-x)/(x-x);
+        if(ix==0x3ff00000) 
+            return x/zero;
+        if(ix<0x3e300000&&(huge+x)>zero) return x;      /* x<2**-28 */
+        SET_HIGH_WORD(x,ix);
+        if(ix<0x3fe00000) {             /* x < 0.5 */
+            t = x+x;
+            t = 0.5*log1p(t+t*x/(one-x));
+        } else 
+            t = 0.5*log1p((x+x)/(one-x));
+        if(hx>=0) return t; else return -t;
+}
diff --git a/src/math/e_atanhf.c b/src/math/e_atanhf.c
new file mode 100644
index 00000000..7356cfc9
--- /dev/null
+++ b/src/math/e_atanhf.c
@@ -0,0 +1,42 @@
+/* e_atanhf.c -- float version of e_atanh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, huge = 1e30;
+
+static const float zero = 0.0;
+
+float
+atanhf(float x)
+{
+        float t;
+        int32_t hx,ix;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if (ix>0x3f800000)              /* |x|>1 */
+            return (x-x)/(x-x);
+        if(ix==0x3f800000)
+            return x/zero;
+        if(ix<0x31800000&&(huge+x)>zero) return x;      /* x<2**-28 */
+        SET_FLOAT_WORD(x,ix);
+        if(ix<0x3f000000) {             /* x < 0.5 */
+            t = x+x;
+            t = (float)0.5*log1pf(t+t*x/(one-x));
+        } else
+            t = (float)0.5*log1pf((x+x)/(one-x));
+        if(hx>=0) return t; else return -t;
+}
diff --git a/src/math/e_cosh.c b/src/math/e_cosh.c
new file mode 100644
index 00000000..ad425bd3
--- /dev/null
+++ b/src/math/e_cosh.c
@@ -0,0 +1,82 @@
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* cosh(x)
+ * Method : 
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ *      1. Replace x by |x| (cosh(x) = cosh(-x)). 
+ *      2. 
+ *                                                      [ exp(x) - 1 ]^2 
+ *          0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
+ *                                                         2*exp(x)
+ *
+ *                                                exp(x) +  1/exp(x)
+ *          ln2/2    <= x <= 22     :  cosh(x) := -------------------
+ *                                                        2
+ *          22       <= x <= lnovft :  cosh(x) := exp(x)/2 
+ *          lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
+ *          ln2ovft  <  x           :  cosh(x) := huge*huge (overflow)
+ *
+ * Special cases:
+ *      cosh(x) is |x| if x is +INF, -INF, or NaN.
+ *      only cosh(0)=1 is exact for finite x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, half=0.5, huge = 1.0e300;
+
+double
+cosh(double x)
+{
+        double t,w;
+        int32_t ix;
+        uint32_t lx;
+
+    /* High word of |x|. */
+        GET_HIGH_WORD(ix,x);
+        ix &= 0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7ff00000) return x*x;  
+
+    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+        if(ix<0x3fd62e43) {
+            t = expm1(fabs(x));
+            w = one+t;
+            if (ix<0x3c800000) return w;        /* cosh(tiny) = 1 */
+            return one+(t*t)/(w+w);
+        }
+
+    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+        if (ix < 0x40360000) {
+                t = exp(fabs(x));
+                return half*t+half/t;
+        }
+
+    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+        if (ix < 0x40862E42)  return half*exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        GET_LOW_WORD(lx,x);
+        if (ix<0x408633CE ||
+              ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) {
+            w = exp(half*fabs(x));
+            t = half*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, cosh(x) overflow */
+        return huge*huge;
+}
diff --git a/src/math/e_coshf.c b/src/math/e_coshf.c
new file mode 100644
index 00000000..6db10885
--- /dev/null
+++ b/src/math/e_coshf.c
@@ -0,0 +1,59 @@
+/* e_coshf.c -- float version of e_cosh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, half=0.5, huge = 1.0e30;
+
+float
+coshf(float x)
+{
+        float t,w;
+        int32_t ix;
+
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7f800000) return x*x;
+
+    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+        if(ix<0x3eb17218) {
+            t = expm1f(fabsf(x));
+            w = one+t;
+            if (ix<0x24000000) return w;        /* cosh(tiny) = 1 */
+            return one+(t*t)/(w+w);
+        }
+
+    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+        if (ix < 0x41b00000) {
+                t = expf(fabsf(x));
+                return half*t+half/t;
+        }
+
+    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+        if (ix < 0x42b17180)  return half*expf(fabsf(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        if (ix<=0x42b2d4fc) {
+            w = expf(half*fabsf(x));
+            t = half*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, cosh(x) overflow */
+        return huge*huge;
+}
diff --git a/src/math/e_exp.c b/src/math/e_exp.c
new file mode 100644
index 00000000..66107b95
--- /dev/null
+++ b/src/math/e_exp.c
@@ -0,0 +1,155 @@
+
+/* @(#)e_exp.c 1.6 04/04/22 */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ *   1. Argument reduction:
+ *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ *      Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2.  
+ *
+ *      Here r will be represented as r = hi-lo for better 
+ *      accuracy.
+ *
+ *   2. Approximation of exp(r) by a special rational function on
+ *      the interval [0,0.34658]:
+ *      Write
+ *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ *      We use a special Remes algorithm on [0,0.34658] to generate 
+ *      a polynomial of degree 5 to approximate R. The maximum error 
+ *      of this polynomial approximation is bounded by 2**-59. In
+ *      other words,
+ *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ *      (where z=r*r, and the values of P1 to P5 are listed below)
+ *      and
+ *          |                  5          |     -59
+ *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2 
+ *          |                             |
+ *      The computation of exp(r) thus becomes
+ *                             2*r
+ *              exp(r) = 1 + -------
+ *                            R - r
+ *                                 r*R1(r)      
+ *                     = 1 + r + ----------- (for better accuracy)
+ *                                2 - R1(r)
+ *      where
+ *                               2       4             10
+ *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+ *      
+ *   3. Scale back to obtain exp(x):
+ *      From step 1, we have
+ *         exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ *      exp(INF) is INF, exp(NaN) is NaN;
+ *      exp(-INF) is 0, and
+ *      for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *      For IEEE double 
+ *          if x >  7.09782712893383973096e+02 then exp(x) overflow
+ *          if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one     = 1.0,
+halF[2] = {0.5,-0.5,},
+huge    = 1.0e+300,
+twom1000= 9.33263618503218878990e-302,     /* 2**-1000=0x01700000,0*/
+o_threshold=  7.09782712893383973096e+02,  /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02,  /* 0xc0874910, 0xD52D3051 */
+ln2HI[2]   ={ 6.93147180369123816490e-01,  /* 0x3fe62e42, 0xfee00000 */
+             -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2]   ={ 1.90821492927058770002e-10,  /* 0x3dea39ef, 0x35793c76 */
+             -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 =  1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+double
+exp(double x) /* default IEEE double exp */
+{
+        double y,hi=0.0,lo=0.0,c,t;
+        int32_t k=0,xsb;
+        uint32_t hx;
+
+        GET_HIGH_WORD(hx,x);
+        xsb = (hx>>31)&1;               /* sign bit of x */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out non-finite argument */
+        if(hx >= 0x40862E42) {                  /* if |x|>=709.78... */
+            if(hx>=0x7ff00000) {
+                uint32_t lx;
+                GET_LOW_WORD(lx,x);
+                if(((hx&0xfffff)|lx)!=0)
+                     return x+x;                /* NaN */
+                else return (xsb==0)? x:0.0;    /* exp(+-inf)={inf,0} */
+            }
+            if(x > o_threshold) return huge*huge; /* overflow */
+            if(x < u_threshold) return twom1000*twom1000; /* underflow */
+        }
+
+    /* argument reduction */
+        if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */ 
+            if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+            } else {
+                k  = (int)(invln2*x+halF[xsb]);
+                t  = k;
+                hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                lo = t*ln2LO[0];
+            }
+            x  = hi - lo;
+        } 
+        else if(hx < 0x3e300000)  {     /* when |x|<2**-28 */
+            if(huge+x>one) return one+x;/* trigger inexact */
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        t  = x*x;
+        c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        if(k==0)        return one-((x*c)/(c-2.0)-x); 
+        else            y = one-((lo-(x*c)/(2.0-c))-hi);
+        if(k >= -1021) {
+            uint32_t hy;
+            GET_HIGH_WORD(hy,y);
+            SET_HIGH_WORD(y,hy+(k<<20));        /* add k to y's exponent */
+            return y;
+        } else {
+            uint32_t hy;
+            GET_HIGH_WORD(hy,y);
+            SET_HIGH_WORD(y,hy+((k+1000)<<20)); /* add k to y's exponent */
+            return y*twom1000;
+        }
+}
diff --git a/src/math/e_expf.c b/src/math/e_expf.c
new file mode 100644
index 00000000..99818edc
--- /dev/null
+++ b/src/math/e_expf.c
@@ -0,0 +1,91 @@
+/* e_expf.c -- float version of e_exp.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+one     = 1.0,
+halF[2] = {0.5,-0.5,},
+huge    = 1.0e+30,
+twom100 = 7.8886090522e-31,      /* 2**-100=0x0d800000 */
+o_threshold=  8.8721679688e+01,  /* 0x42b17180 */
+u_threshold= -1.0397208405e+02,  /* 0xc2cff1b5 */
+ln2HI[2]   ={ 6.9313812256e-01,         /* 0x3f317180 */
+             -6.9313812256e-01,},       /* 0xbf317180 */
+ln2LO[2]   ={ 9.0580006145e-06,         /* 0x3717f7d1 */
+             -9.0580006145e-06,},       /* 0xb717f7d1 */
+invln2 =  1.4426950216e+00,             /* 0x3fb8aa3b */
+P1   =  1.6666667163e-01, /* 0x3e2aaaab */
+P2   = -2.7777778450e-03, /* 0xbb360b61 */
+P3   =  6.6137559770e-05, /* 0x388ab355 */
+P4   = -1.6533901999e-06, /* 0xb5ddea0e */
+P5   =  4.1381369442e-08; /* 0x3331bb4c */
+
+float
+expf(float x) /* default IEEE double exp */
+{
+        float y,hi=0.0,lo=0.0,c,t;
+        int32_t k=0,xsb;
+        uint32_t hx;
+
+        GET_FLOAT_WORD(hx,x);
+        xsb = (hx>>31)&1;               /* sign bit of x */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out non-finite argument */
+        if(hx >= 0x42b17218) {                  /* if |x|>=88.721... */
+            if(hx>0x7f800000)
+                 return x+x;                    /* NaN */
+            if(hx==0x7f800000)
+                return (xsb==0)? x:0.0;         /* exp(+-inf)={inf,0} */
+            if(x > o_threshold) return huge*huge; /* overflow */
+            if(x < u_threshold) return twom100*twom100; /* underflow */
+        }
+
+    /* argument reduction */
+        if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */
+            if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */
+                hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+            } else {
+                k  = invln2*x+halF[xsb];
+                t  = k;
+                hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                lo = t*ln2LO[0];
+            }
+            x  = hi - lo;
+        }
+        else if(hx < 0x31800000)  {     /* when |x|<2**-28 */
+            if(huge+x>one) return one+x;/* trigger inexact */
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        t  = x*x;
+        c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        if(k==0)        return one-((x*c)/(c-(float)2.0)-x);
+        else            y = one-((lo-(x*c)/((float)2.0-c))-hi);
+        if(k >= -125) {
+            uint32_t hy;
+            GET_FLOAT_WORD(hy,y);
+            SET_FLOAT_WORD(y,hy+(k<<23));       /* add k to y's exponent */
+            return y;
+        } else {
+            uint32_t hy;
+            GET_FLOAT_WORD(hy,y);
+            SET_FLOAT_WORD(y,hy+((k+100)<<23)); /* add k to y's exponent */
+            return y*twom100;
+        }
+}
diff --git a/src/math/e_fmod.c b/src/math/e_fmod.c
new file mode 100644
index 00000000..99afe489
--- /dev/null
+++ b/src/math/e_fmod.c
@@ -0,0 +1,129 @@
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* 
+ * fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+
+double
+fmod(double x, double y)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+        uint32_t lx,ly,lz;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */
+          ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */
+            return (x*y)/(x*y);
+        if(hx<=hy) {
+            if((hx<hy)||(lx<ly)) return x;      /* |x|<|y| return x */
+            if(lx==ly) 
+                return Zero[(uint32_t)sx>>31]; /* |x|=|y| return x*0*/
+        }
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00100000) {     /* subnormal x */
+            if(hx==0) {
+                for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+            } else {
+                for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+            }
+        } else ix = (hx>>20)-1023;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00100000) {     /* subnormal y */
+            if(hy==0) {
+                for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+            } else {
+                for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+            }
+        } else iy = (hy>>20)-1023;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -1022) 
+            hx = 0x00100000|(0x000fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -1022-ix;
+            if(n<=31) {
+                hx = (hx<<n)|(lx>>(32-n));
+                lx <<= n;
+            } else {
+                hx = lx<<(n-32);
+                lx = 0;
+            }
+        }
+        if(iy >= -1022) 
+            hy = 0x00100000|(0x000fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -1022-iy;
+            if(n<=31) {
+                hy = (hy<<n)|(ly>>(32-n));
+                ly <<= n;
+            } else {
+                hy = ly<<(n-32);
+                ly = 0;
+            }
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        while(n--) {
+            hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+            if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+            else {
+                if((hz|lz)==0)          /* return sign(x)*0 */
+                    return Zero[(uint32_t)sx>>31];
+                hx = hz+hz+(lz>>31); lx = lz+lz;
+            }
+        }
+        hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+        if(hz>=0) {hx=hz;lx=lz;}
+
+    /* convert back to floating value and restore the sign */
+        if((hx|lx)==0)                  /* return sign(x)*0 */
+            return Zero[(uint32_t)sx>>31];
+        while(hx<0x00100000) {          /* normalize x */
+            hx = hx+hx+(lx>>31); lx = lx+lx;
+            iy -= 1;
+        }
+        if(iy>= -1022) {        /* normalize output */
+            hx = ((hx-0x00100000)|((iy+1023)<<20));
+            INSERT_WORDS(x,hx|sx,lx);
+        } else {                /* subnormal output */
+            n = -1022 - iy;
+            if(n<=20) {
+                lx = (lx>>n)|((uint32_t)hx<<(32-n));
+                hx >>= n;
+            } else if (n<=31) {
+                lx = (hx<<(32-n))|(lx>>n); hx = sx;
+            } else {
+                lx = hx>>(n-32); hx = sx;
+            }
+            INSERT_WORDS(x,hx|sx,lx);
+            x *= one;           /* create necessary signal */
+        }
+        return x;               /* exact output */
+}
diff --git a/src/math/e_fmodf.c b/src/math/e_fmodf.c
new file mode 100644
index 00000000..fe86cb04
--- /dev/null
+++ b/src/math/e_fmodf.c
@@ -0,0 +1,101 @@
+/* e_fmodf.c -- float version of e_fmod.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fmodf(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, Zero[] = {0.0, -0.0,};
+
+float
+fmodf(float x, float y)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if(hy==0||(hx>=0x7f800000)||            /* y=0,or x not finite */
+           (hy>0x7f800000))                     /* or y is NaN */
+            return (x*y)/(x*y);
+        if(hx<hy) return x;                     /* |x|<|y| return x */
+        if(hx==hy)
+            return Zero[(uint32_t)sx>>31];     /* |x|=|y| return x*0*/
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00800000) {     /* subnormal x */
+            for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+        } else ix = (hx>>23)-127;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00800000) {     /* subnormal y */
+            for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1;
+        } else iy = (hy>>23)-127;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -126)
+            hx = 0x00800000|(0x007fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -126-ix;
+            hx = hx<<n;
+        }
+        if(iy >= -126)
+            hy = 0x00800000|(0x007fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -126-iy;
+            hy = hy<<n;
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        while(n--) {
+            hz=hx-hy;
+            if(hz<0){hx = hx+hx;}
+            else {
+                if(hz==0)               /* return sign(x)*0 */
+                    return Zero[(uint32_t)sx>>31];
+                hx = hz+hz;
+            }
+        }
+        hz=hx-hy;
+        if(hz>=0) {hx=hz;}
+
+    /* convert back to floating value and restore the sign */
+        if(hx==0)                       /* return sign(x)*0 */
+            return Zero[(uint32_t)sx>>31];
+        while(hx<0x00800000) {          /* normalize x */
+            hx = hx+hx;
+            iy -= 1;
+        }
+        if(iy>= -126) {         /* normalize output */
+            hx = ((hx-0x00800000)|((iy+127)<<23));
+            SET_FLOAT_WORD(x,hx|sx);
+        } else {                /* subnormal output */
+            n = -126 - iy;
+            hx >>= n;
+            SET_FLOAT_WORD(x,hx|sx);
+            x *= one;           /* create necessary signal */
+        }
+        return x;               /* exact output */
+}
diff --git a/src/math/e_hypot.c b/src/math/e_hypot.c
new file mode 100644
index 00000000..e925adc3
--- /dev/null
+++ b/src/math/e_hypot.c
@@ -0,0 +1,121 @@
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* hypot(x,y)
+ *
+ * Method :                  
+ *      If (assume round-to-nearest) z=x*x+y*y 
+ *      has error less than sqrt(2)/2 ulp, than 
+ *      sqrt(z) has error less than 1 ulp (exercise).
+ *
+ *      So, compute sqrt(x*x+y*y) with some care as 
+ *      follows to get the error below 1 ulp:
+ *
+ *      Assume x>y>0;
+ *      (if possible, set rounding to round-to-nearest)
+ *      1. if x > 2y  use
+ *              x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ *      where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ *      2. if x <= 2y use
+ *              t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ *      where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, 
+ *      y1= y with lower 32 bits chopped, y2 = y-y1.
+ *              
+ *      NOTE: scaling may be necessary if some argument is too 
+ *            large or too tiny
+ *
+ * Special cases:
+ *      hypot(x,y) is INF if x or y is +INF or -INF; else
+ *      hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ *      hypot(x,y) returns sqrt(x^2+y^2) with error less 
+ *      than 1 ulps (units in the last place) 
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+hypot(double x, double y)
+{
+        double a=x,b=y,t1,t2,y1,y2,w;
+        int32_t j,k,ha,hb;
+
+        GET_HIGH_WORD(ha,x);
+        ha &= 0x7fffffff;
+        GET_HIGH_WORD(hb,y);
+        hb &= 0x7fffffff;
+        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+        SET_HIGH_WORD(a,ha);    /* a <- |a| */
+        SET_HIGH_WORD(b,hb);    /* b <- |b| */
+        if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+        k=0;
+        if(ha > 0x5f300000) {   /* a>2**500 */
+           if(ha >= 0x7ff00000) {       /* Inf or NaN */
+               uint32_t low;
+               w = a+b;                 /* for sNaN */
+               GET_LOW_WORD(low,a);
+               if(((ha&0xfffff)|low)==0) w = a;
+               GET_LOW_WORD(low,b);
+               if(((hb^0x7ff00000)|low)==0) w = b;
+               return w;
+           }
+           /* scale a and b by 2**-600 */
+           ha -= 0x25800000; hb -= 0x25800000;  k += 600;
+           SET_HIGH_WORD(a,ha);
+           SET_HIGH_WORD(b,hb);
+        }
+        if(hb < 0x20b00000) {   /* b < 2**-500 */
+            if(hb <= 0x000fffff) {      /* subnormal b or 0 */
+                uint32_t low;
+                GET_LOW_WORD(low,b);
+                if((hb|low)==0) return a;
+                t1=0;
+                SET_HIGH_WORD(t1,0x7fd00000);   /* t1=2^1022 */
+                b *= t1;
+                a *= t1;
+                k -= 1022;
+            } else {            /* scale a and b by 2^600 */
+                ha += 0x25800000;       /* a *= 2^600 */
+                hb += 0x25800000;       /* b *= 2^600 */
+                k -= 600;
+                SET_HIGH_WORD(a,ha);
+                SET_HIGH_WORD(b,hb);
+            }
+        }
+    /* medium size a and b */
+        w = a-b;
+        if (w>b) {
+            t1 = 0;
+            SET_HIGH_WORD(t1,ha);
+            t2 = a-t1;
+            w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+        } else {
+            a  = a+a;
+            y1 = 0;
+            SET_HIGH_WORD(y1,hb);
+            y2 = b - y1;
+            t1 = 0;
+            SET_HIGH_WORD(t1,ha+0x00100000);
+            t2 = a - t1;
+            w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+        }
+        if(k!=0) {
+            uint32_t high;
+            t1 = 1.0;
+            GET_HIGH_WORD(high,t1);
+            SET_HIGH_WORD(t1,high+(k<<20));
+            return t1*w;
+        } else return w;
+}
diff --git a/src/math/e_hypotf.c b/src/math/e_hypotf.c
new file mode 100644
index 00000000..13773554
--- /dev/null
+++ b/src/math/e_hypotf.c
@@ -0,0 +1,79 @@
+/* e_hypotf.c -- float version of e_hypot.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+hypotf(float x, float y)
+{
+        float a=x,b=y,t1,t2,y1,y2,w;
+        int32_t j,k,ha,hb;
+
+        GET_FLOAT_WORD(ha,x);
+        ha &= 0x7fffffff;
+        GET_FLOAT_WORD(hb,y);
+        hb &= 0x7fffffff;
+        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+        SET_FLOAT_WORD(a,ha);   /* a <- |a| */
+        SET_FLOAT_WORD(b,hb);   /* b <- |b| */
+        if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */
+        k=0;
+        if(ha > 0x58800000) {   /* a>2**50 */
+           if(ha >= 0x7f800000) {       /* Inf or NaN */
+               w = a+b;                 /* for sNaN */
+               if(ha == 0x7f800000) w = a;
+               if(hb == 0x7f800000) w = b;
+               return w;
+           }
+           /* scale a and b by 2**-68 */
+           ha -= 0x22000000; hb -= 0x22000000;  k += 68;
+           SET_FLOAT_WORD(a,ha);
+           SET_FLOAT_WORD(b,hb);
+        }
+        if(hb < 0x26800000) {   /* b < 2**-50 */
+            if(hb <= 0x007fffff) {      /* subnormal b or 0 */
+                if(hb==0) return a;
+                SET_FLOAT_WORD(t1,0x7e800000);  /* t1=2^126 */
+                b *= t1;
+                a *= t1;
+                k -= 126;
+            } else {            /* scale a and b by 2^68 */
+                ha += 0x22000000;       /* a *= 2^68 */
+                hb += 0x22000000;       /* b *= 2^68 */
+                k -= 68;
+                SET_FLOAT_WORD(a,ha);
+                SET_FLOAT_WORD(b,hb);
+            }
+        }
+    /* medium size a and b */
+        w = a-b;
+        if (w>b) {
+            SET_FLOAT_WORD(t1,ha&0xfffff000);
+            t2 = a-t1;
+            w  = sqrtf(t1*t1-(b*(-b)-t2*(a+t1)));
+        } else {
+            a  = a+a;
+            SET_FLOAT_WORD(y1,hb&0xfffff000);
+            y2 = b - y1;
+            SET_FLOAT_WORD(t1,ha+0x00800000);
+            t2 = a - t1;
+            w  = sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+        }
+        if(k!=0) {
+            SET_FLOAT_WORD(t1,0x3f800000+(k<<23));
+            return t1*w;
+        } else return w;
+}
diff --git a/src/math/e_log.c b/src/math/e_log.c
new file mode 100644
index 00000000..9eb0e444
--- /dev/null
+++ b/src/math/e_log.c
@@ -0,0 +1,131 @@
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* log(x)
+ * Return the logrithm of x
+ *
+ * Method :                  
+ *   1. Argument Reduction: find k and f such that 
+ *                      x = 2^k * (1+f), 
+ *         where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *   2. Approximation of log(1+f).
+ *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *               = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *               = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate 
+ *      a polynomial of degree 14 to approximate R The maximum error 
+ *      of this polynomial approximation is bounded by 2**-58.45. In
+ *      other words,
+ *                      2      4      6      8      10      12      14
+ *          R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
+ *      (the values of Lg1 to Lg7 are listed in the program)
+ *      and
+ *          |      2          14          |     -58.45
+ *          | Lg1*s +...+Lg7*s    -  R(z) | <= 2 
+ *          |                             |
+ *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *      In order to guarantee error in log below 1ulp, we compute log
+ *      by
+ *              log(1+f) = f - s*(f - R)        (if f is not too large)
+ *              log(1+f) = f - (hfsq - s*(hfsq+R)).     (better accuracy)
+ *      
+ *      3. Finally,  log(x) = k*ln2 + log(1+f).  
+ *                          = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *         Here ln2 is split into two floating point number: 
+ *                      ln2_hi + ln2_lo,
+ *         where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *      log(x) is NaN with signal if x < 0 (including -INF) ; 
+ *      log(+INF) is +INF; log(0) is -INF with signal;
+ *      log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static const double zero   =  0.0;
+
+double
+log(double x)
+{
+        double hfsq,f,s,z,R,w,t1,t2,dk;
+        int32_t k,hx,i,j;
+        uint32_t lx;
+
+        EXTRACT_WORDS(hx,lx,x);
+
+        k=0;
+        if (hx < 0x00100000) {                  /* x < 2**-1022  */
+            if (((hx&0x7fffffff)|lx)==0) 
+                return -two54/zero;             /* log(+-0)=-inf */
+            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 54; x *= two54; /* subnormal number, scale up x */
+            GET_HIGH_WORD(hx,x);
+        } 
+        if (hx >= 0x7ff00000) return x+x;
+        k += (hx>>20)-1023;
+        hx &= 0x000fffff;
+        i = (hx+0x95f64)&0x100000;
+        SET_HIGH_WORD(x,hx|(i^0x3ff00000));     /* normalize x or x/2 */
+        k += (i>>20);
+        f = x-1.0;
+        if((0x000fffff&(2+hx))<3) {     /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;  else {dk=(double)k;
+                                 return dk*ln2_hi+dk*ln2_lo;} }
+            R = f*f*(0.5-0.33333333333333333*f);
+            if(k==0) return f-R; else {dk=(double)k;
+                     return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+        }
+        s = f/(2.0+f); 
+        dk = (double)k;
+        z = s*s;
+        i = hx-0x6147a;
+        w = z*z;
+        j = 0x6b851-hx;
+        t1= w*(Lg2+w*(Lg4+w*Lg6)); 
+        t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); 
+        i |= j;
+        R = t2+t1;
+        if(i>0) {
+            hfsq=0.5*f*f;
+            if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+        } else {
+            if(k==0) return f-s*(f-R); else
+                     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+        }
+}
diff --git a/src/math/e_log10.c b/src/math/e_log10.c
new file mode 100644
index 00000000..3be179f7
--- /dev/null
+++ b/src/math/e_log10.c
@@ -0,0 +1,83 @@
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* log10(x)
+ * Return the base 10 logarithm of x
+ * 
+ * Method :
+ *      Let log10_2hi = leading 40 bits of log10(2) and
+ *          log10_2lo = log10(2) - log10_2hi,
+ *          ivln10   = 1/log(10) rounded.
+ *      Then
+ *              n = ilogb(x), 
+ *              if(n<0)  n = n+1;
+ *              x = scalbn(x,-n);
+ *              log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ *      To guarantee log10(10**n)=n, where 10**n is normal, the rounding 
+ *      mode must set to Round-to-Nearest.
+ * Note 2:
+ *      [1/log(10)] rounded to 53 bits has error  .198   ulps;
+ *      log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ *      log10(x) is NaN with signal if x < 0; 
+ *      log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ *      log10(NaN) is that NaN with no signal;
+ *      log10(10**N) = N  for N=0,1,...,22.
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following constants.
+ * The decimal values may be used, provided that the compiler will convert
+ * from decimal to binary accurately enough to produce the hexadecimal values
+ * shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+two54      =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10     =  4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi  =  3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo  =  3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static const double zero   =  0.0;
+
+double
+log10(double x)
+{
+        double y,z;
+        int32_t i,k,hx;
+        uint32_t lx;
+
+        EXTRACT_WORDS(hx,lx,x);
+
+        k=0;
+        if (hx < 0x00100000) {                  /* x < 2**-1022  */
+            if (((hx&0x7fffffff)|lx)==0)
+                return -two54/zero;             /* log(+-0)=-inf */
+            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 54; x *= two54; /* subnormal number, scale up x */
+            GET_HIGH_WORD(hx,x);
+        }
+        if (hx >= 0x7ff00000) return x+x;
+        k += (hx>>20)-1023;
+        i  = ((uint32_t)k&0x80000000)>>31;
+        hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+        y  = (double)(k+i);
+        SET_HIGH_WORD(x,hx);
+        z  = y*log10_2lo + ivln10*log(x);
+        return  z+y*log10_2hi;
+}
diff --git a/src/math/e_log10f.c b/src/math/e_log10f.c
new file mode 100644
index 00000000..8fc5c5ca
--- /dev/null
+++ b/src/math/e_log10f.c
@@ -0,0 +1,51 @@
+/* e_log10f.c -- float version of e_log10.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+two25      =  3.3554432000e+07, /* 0x4c000000 */
+ivln10     =  4.3429449201e-01, /* 0x3ede5bd9 */
+log10_2hi  =  3.0102920532e-01, /* 0x3e9a2080 */
+log10_2lo  =  7.9034151668e-07; /* 0x355427db */
+
+static const float zero   =  0.0;
+
+float
+log10f(float x)
+{
+        float y,z;
+        int32_t i,k,hx;
+
+        GET_FLOAT_WORD(hx,x);
+
+        k=0;
+        if (hx < 0x00800000) {                  /* x < 2**-126  */
+            if ((hx&0x7fffffff)==0)
+                return -two25/zero;             /* log(+-0)=-inf */
+            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 25; x *= two25; /* subnormal number, scale up x */
+            GET_FLOAT_WORD(hx,x);
+        }
+        if (hx >= 0x7f800000) return x+x;
+        k += (hx>>23)-127;
+        i  = ((uint32_t)k&0x80000000)>>31;
+        hx = (hx&0x007fffff)|((0x7f-i)<<23);
+        y  = (float)(k+i);
+        SET_FLOAT_WORD(x,hx);
+        z  = y*log10_2lo + ivln10*logf(x);
+        return  z+y*log10_2hi;
+}
diff --git a/src/math/e_logf.c b/src/math/e_logf.c
new file mode 100644
index 00000000..46a8b8ce
--- /dev/null
+++ b/src/math/e_logf.c
@@ -0,0 +1,81 @@
+/* e_logf.c -- float version of e_log.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+ln2_hi =   6.9313812256e-01,    /* 0x3f317180 */
+ln2_lo =   9.0580006145e-06,    /* 0x3717f7d1 */
+two25 =    3.355443200e+07,     /* 0x4c000000 */
+Lg1 = 6.6666668653e-01, /* 3F2AAAAB */
+Lg2 = 4.0000000596e-01, /* 3ECCCCCD */
+Lg3 = 2.8571429849e-01, /* 3E924925 */
+Lg4 = 2.2222198546e-01, /* 3E638E29 */
+Lg5 = 1.8183572590e-01, /* 3E3A3325 */
+Lg6 = 1.5313838422e-01, /* 3E1CD04F */
+Lg7 = 1.4798198640e-01; /* 3E178897 */
+
+static const float zero   =  0.0;
+
+float
+logf(float x)
+{
+        float hfsq,f,s,z,R,w,t1,t2,dk;
+        int32_t k,ix,i,j;
+
+        GET_FLOAT_WORD(ix,x);
+
+        k=0;
+        if (ix < 0x00800000) {                  /* x < 2**-126  */
+            if ((ix&0x7fffffff)==0)
+                return -two25/zero;             /* log(+-0)=-inf */
+            if (ix<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 25; x *= two25; /* subnormal number, scale up x */
+            GET_FLOAT_WORD(ix,x);
+        }
+        if (ix >= 0x7f800000) return x+x;
+        k += (ix>>23)-127;
+        ix &= 0x007fffff;
+        i = (ix+(0x95f64<<3))&0x800000;
+        SET_FLOAT_WORD(x,ix|(i^0x3f800000));    /* normalize x or x/2 */
+        k += (i>>23);
+        f = x-(float)1.0;
+        if((0x007fffff&(15+ix))<16) {   /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;  else {dk=(float)k;
+                                 return dk*ln2_hi+dk*ln2_lo;} }
+            R = f*f*((float)0.5-(float)0.33333333333333333*f);
+            if(k==0) return f-R; else {dk=(float)k;
+                     return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+        }
+        s = f/((float)2.0+f);
+        dk = (float)k;
+        z = s*s;
+        i = ix-(0x6147a<<3);
+        w = z*z;
+        j = (0x6b851<<3)-ix;
+        t1= w*(Lg2+w*(Lg4+w*Lg6));
+        t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+        i |= j;
+        R = t2+t1;
+        if(i>0) {
+            hfsq=(float)0.5*f*f;
+            if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+        } else {
+            if(k==0) return f-s*(f-R); else
+                     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+        }
+}
diff --git a/src/math/e_pow.c b/src/math/e_pow.c
new file mode 100644
index 00000000..aad24287
--- /dev/null
+++ b/src/math/e_pow.c
@@ -0,0 +1,300 @@
+/* @(#)e_pow.c 1.5 04/04/22 SMI */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* pow(x,y) return x**y
+ *
+ *                    n
+ * Method:  Let x =  2   * (1+f)
+ *      1. Compute and return log2(x) in two pieces:
+ *              log2(x) = w1 + w2,
+ *         where w1 has 53-24 = 29 bit trailing zeros.
+ *      2. Perform y*log2(x) = n+y' by simulating muti-precision 
+ *         arithmetic, where |y'|<=0.5.
+ *      3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ *      1.  (anything) ** 0  is 1
+ *      2.  (anything) ** 1  is itself
+ *      3.  (anything) ** NAN is NAN
+ *      4.  NAN ** (anything except 0) is NAN
+ *      5.  +-(|x| > 1) **  +INF is +INF
+ *      6.  +-(|x| > 1) **  -INF is +0
+ *      7.  +-(|x| < 1) **  +INF is +0
+ *      8.  +-(|x| < 1) **  -INF is +INF
+ *      9.  +-1         ** +-INF is NAN
+ *      10. +0 ** (+anything except 0, NAN)               is +0
+ *      11. -0 ** (+anything except 0, NAN, odd integer)  is +0
+ *      12. +0 ** (-anything except 0, NAN)               is +INF
+ *      13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
+ *      14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ *      15. +INF ** (+anything except 0,NAN) is +INF
+ *      16. +INF ** (-anything except 0,NAN) is +0
+ *      17. -INF ** (anything)  = -0 ** (-anything)
+ *      18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ *      19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ *      pow(x,y) returns x**y nearly rounded. In particular
+ *                      pow(integer,integer)
+ *      always returns the correct integer provided it is 
+ *      representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero    =  0.0,
+one     =  1.0,
+two     =  2.0,
+two53   =  9007199254740992.0,  /* 0x43400000, 0x00000000 */
+huge    =  1.0e300,
+tiny    =  1.0e-300,
+        /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+double
+pow(double x, double y)
+{
+        double z,ax,z_h,z_l,p_h,p_l;
+        double y1,t1,t2,r,s,t,u,v,w;
+        int32_t i,j,k,yisint,n;
+        int32_t hx,hy,ix,iy;
+        uint32_t lx,ly;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+        if((iy|ly)==0) return one;      
+
+    /* +-NaN return x+y */
+        if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+           iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) 
+                return x+y;     
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0       ... y is not an integer
+     * yisint = 1       ... y is an odd int
+     * yisint = 2       ... y is an even int
+     */
+        yisint  = 0;
+        if(hx<0) {      
+            if(iy>=0x43400000) yisint = 2; /* even integer y */
+            else if(iy>=0x3ff00000) {
+                k = (iy>>20)-0x3ff;        /* exponent */
+                if(k>20) {
+                    j = ly>>(52-k);
+                    if((j<<(52-k))==ly) yisint = 2-(j&1);
+                } else if(ly==0) {
+                    j = iy>>(20-k);
+                    if((j<<(20-k))==iy) yisint = 2-(j&1);
+                }
+            }           
+        } 
+
+    /* special value of y */
+        if(ly==0) {     
+            if (iy==0x7ff00000) {       /* y is +-inf */
+                if(((ix-0x3ff00000)|lx)==0)
+                    return  y - y;      /* inf**+-1 is NaN */
+                else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+                    return (hy>=0)? y: zero;
+                else                    /* (|x|<1)**-,+inf = inf,0 */
+                    return (hy<0)?-y: zero;
+            } 
+            if(iy==0x3ff00000) {        /* y is  +-1 */
+                if(hy<0) return one/x; else return x;
+            }
+            if(hy==0x40000000) return x*x; /* y is  2 */
+            if(hy==0x3fe00000) {        /* y is  0.5 */
+                if(hx>=0)       /* x >= +0 */
+                return sqrt(x); 
+            }
+        }
+
+        ax   = fabs(x);
+    /* special value of x */
+        if(lx==0) {
+            if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+                z = ax;                 /*x is +-0,+-inf,+-1*/
+                if(hy<0) z = one/z;     /* z = (1/|x|) */
+                if(hx<0) {
+                    if(((ix-0x3ff00000)|yisint)==0) {
+                        z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+                    } else if(yisint==1) 
+                        z = -z;         /* (x<0)**odd = -(|x|**odd) */
+                }
+                return z;
+            }
+        }
+    
+    /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be
+        n = (hx>>31)+1;
+       but ANSI C says a right shift of a signed negative quantity is
+       implementation defined.  */
+        n = ((uint32_t)hx>>31)-1;
+
+    /* (x<0)**(non-int) is NaN */
+        if((n|yisint)==0) return (x-x)/(x-x);
+
+        s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+        if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+    /* |y| is huge */
+        if(iy>0x41e00000) { /* if |y| > 2**31 */
+            if(iy>0x43f00000){  /* if |y| > 2**64, must o/uflow */
+                if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+                if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+            }
+        /* over/underflow if x is not close to one */
+            if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
+            if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
+        /* now |1-x| is tiny <= 2**-20, suffice to compute 
+           log(x) by x-x^2/2+x^3/3-x^4/4 */
+            t = ax-one;         /* t has 20 trailing zeros */
+            w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+            u = ivln2_h*t;      /* ivln2_h has 21 sig. bits */
+            v = t*ivln2_l-w*ivln2;
+            t1 = u+v;
+            SET_LOW_WORD(t1,0);
+            t2 = v-(t1-u);
+        } else {
+            double ss,s2,s_h,s_l,t_h,t_l;
+            n = 0;
+        /* take care subnormal number */
+            if(ix<0x00100000)
+                {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); }
+            n  += ((ix)>>20)-0x3ff;
+            j  = ix&0x000fffff;
+        /* determine interval */
+            ix = j|0x3ff00000;          /* normalize ix */
+            if(j<=0x3988E) k=0;         /* |x|<sqrt(3/2) */
+            else if(j<0xBB67A) k=1;     /* |x|<sqrt(3)   */
+            else {k=0;n+=1;ix -= 0x00100000;}
+            SET_HIGH_WORD(ax,ix);
+
+        /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+            u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */
+            v = one/(ax+bp[k]);
+            ss = u*v;
+            s_h = ss;
+            SET_LOW_WORD(s_h,0);
+        /* t_h=ax+bp[k] High */
+            t_h = zero;
+            SET_HIGH_WORD(t_h,((ix>>1)|0x20000000)+0x00080000+(k<<18));
+            t_l = ax - (t_h-bp[k]);
+            s_l = v*((u-s_h*t_h)-s_h*t_l);
+        /* compute log(ax) */
+            s2 = ss*ss;
+            r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+            r += s_l*(s_h+ss);
+            s2  = s_h*s_h;
+            t_h = 3.0+s2+r;
+            SET_LOW_WORD(t_h,0);
+            t_l = r-((t_h-3.0)-s2);
+        /* u+v = ss*(1+...) */
+            u = s_h*t_h;
+            v = s_l*t_h+t_l*ss;
+        /* 2/(3log2)*(ss+...) */
+            p_h = u+v;
+            SET_LOW_WORD(p_h,0);
+            p_l = v-(p_h-u);
+            z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */
+            z_l = cp_l*p_h+p_l*cp+dp_l[k];
+        /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+            t = (double)n;
+            t1 = (((z_h+z_l)+dp_h[k])+t);
+            SET_LOW_WORD(t1,0);
+            t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+        }
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+        y1  = y;
+        SET_LOW_WORD(y1,0);
+        p_l = (y-y1)*t1+y*t2;
+        p_h = y1*t1;
+        z = p_l+p_h;
+        EXTRACT_WORDS(j,i,z);
+        if (j>=0x40900000) {                            /* z >= 1024 */
+            if(((j-0x40900000)|i)!=0)                   /* if z > 1024 */
+                return s*huge*huge;                     /* overflow */
+            else {
+                if(p_l+ovt>z-p_h) return s*huge*huge;   /* overflow */
+            }
+        } else if((j&0x7fffffff)>=0x4090cc00 ) {        /* z <= -1075 */
+            if(((j-0xc090cc00)|i)!=0)           /* z < -1075 */
+                return s*tiny*tiny;             /* underflow */
+            else {
+                if(p_l<=z-p_h) return s*tiny*tiny;      /* underflow */
+            }
+        }
+    /*
+     * compute 2**(p_h+p_l)
+     */
+        i = j&0x7fffffff;
+        k = (i>>20)-0x3ff;
+        n = 0;
+        if(i>0x3fe00000) {              /* if |z| > 0.5, set n = [z+0.5] */
+            n = j+(0x00100000>>(k+1));
+            k = ((n&0x7fffffff)>>20)-0x3ff;     /* new k for n */
+            t = zero;
+            SET_HIGH_WORD(t,n&~(0x000fffff>>k));
+            n = ((n&0x000fffff)|0x00100000)>>(20-k);
+            if(j<0) n = -n;
+            p_h -= t;
+        } 
+        t = p_l+p_h;
+        SET_LOW_WORD(t,0);
+        u = t*lg2_h;
+        v = (p_l-(t-p_h))*lg2+t*lg2_l;
+        z = u+v;
+        w = v-(z-u);
+        t  = z*z;
+        t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        r  = (z*t1)/(t1-two)-(w+z*w);
+        z  = one-(r-z);
+        GET_HIGH_WORD(j,z);
+        j += (n<<20);
+        if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */
+        else SET_HIGH_WORD(z,j);
+        return s*z;
+}
diff --git a/src/math/e_powf.c b/src/math/e_powf.c
new file mode 100644
index 00000000..ae61c246
--- /dev/null
+++ b/src/math/e_powf.c
@@ -0,0 +1,243 @@
+/* e_powf.c -- float version of e_pow.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
+dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
+zero    =  0.0,
+one     =  1.0,
+two     =  2.0,
+two24   =  16777216.0,  /* 0x4b800000 */
+huge    =  1.0e30,
+tiny    =  1.0e-30,
+        /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  6.0000002384e-01, /* 0x3f19999a */
+L2  =  4.2857143283e-01, /* 0x3edb6db7 */
+L3  =  3.3333334327e-01, /* 0x3eaaaaab */
+L4  =  2.7272811532e-01, /* 0x3e8ba305 */
+L5  =  2.3066075146e-01, /* 0x3e6c3255 */
+L6  =  2.0697501302e-01, /* 0x3e53f142 */
+P1   =  1.6666667163e-01, /* 0x3e2aaaab */
+P2   = -2.7777778450e-03, /* 0xbb360b61 */
+P3   =  6.6137559770e-05, /* 0x388ab355 */
+P4   = -1.6533901999e-06, /* 0xb5ddea0e */
+P5   =  4.1381369442e-08, /* 0x3331bb4c */
+lg2  =  6.9314718246e-01, /* 0x3f317218 */
+lg2_h  =  6.93145752e-01, /* 0x3f317200 */
+lg2_l  =  1.42860654e-06, /* 0x35bfbe8c */
+ovt =  4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
+cp    =  9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
+cp_h  =  9.6179199219e-01, /* 0x3f763800 =head of cp */
+cp_l  =  4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */
+ivln2    =  1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
+ivln2_h  =  1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
+ivln2_l  =  7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
+
+float
+powf(float x, float y)
+{
+        float z,ax,z_h,z_l,p_h,p_l;
+        float y1,t1,t2,r,s,sn,t,u,v,w;
+        int32_t i,j,k,yisint,n;
+        int32_t hx,hy,ix,iy,is;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+        if(iy==0) return one;
+
+    /* +-NaN return x+y */
+        if(ix > 0x7f800000 ||
+           iy > 0x7f800000)
+                return x+y;
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0       ... y is not an integer
+     * yisint = 1       ... y is an odd int
+     * yisint = 2       ... y is an even int
+     */
+        yisint  = 0;
+        if(hx<0) {
+            if(iy>=0x4b800000) yisint = 2; /* even integer y */
+            else if(iy>=0x3f800000) {
+                k = (iy>>23)-0x7f;         /* exponent */
+                j = iy>>(23-k);
+                if((j<<(23-k))==iy) yisint = 2-(j&1);
+            }
+        }
+
+    /* special value of y */
+        if (iy==0x7f800000) {   /* y is +-inf */
+            if (ix==0x3f800000)
+                return  y - y;  /* inf**+-1 is NaN */
+            else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */
+                return (hy>=0)? y: zero;
+            else                        /* (|x|<1)**-,+inf = inf,0 */
+                return (hy<0)?-y: zero;
+        }
+        if(iy==0x3f800000) {    /* y is  +-1 */
+            if(hy<0) return one/x; else return x;
+        }
+        if(hy==0x40000000) return x*x; /* y is  2 */
+        if(hy==0x3f000000) {    /* y is  0.5 */
+            if(hx>=0)   /* x >= +0 */
+            return sqrtf(x);
+        }
+
+        ax   = fabsf(x);
+    /* special value of x */
+        if(ix==0x7f800000||ix==0||ix==0x3f800000){
+            z = ax;                     /*x is +-0,+-inf,+-1*/
+            if(hy<0) z = one/z; /* z = (1/|x|) */
+            if(hx<0) {
+                if(((ix-0x3f800000)|yisint)==0) {
+                    z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+                } else if(yisint==1)
+                    z = -z;             /* (x<0)**odd = -(|x|**odd) */
+            }
+            return z;
+        }
+
+        n = ((uint32_t)hx>>31)-1;
+
+    /* (x<0)**(non-int) is NaN */
+        if((n|yisint)==0) return (x-x)/(x-x);
+
+        sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+        if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */
+
+    /* |y| is huge */
+        if(iy>0x4d000000) { /* if |y| > 2**27 */
+        /* over/underflow if x is not close to one */
+            if(ix<0x3f7ffff8) return (hy<0)? sn*huge*huge:sn*tiny*tiny;
+            if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny;
+        /* now |1-x| is tiny <= 2**-20, suffice to compute
+           log(x) by x-x^2/2+x^3/3-x^4/4 */
+            t = ax-1;           /* t has 20 trailing zeros */
+            w = (t*t)*((float)0.5-t*((float)0.333333333333-t*(float)0.25));
+            u = ivln2_h*t;      /* ivln2_h has 16 sig. bits */
+            v = t*ivln2_l-w*ivln2;
+            t1 = u+v;
+            GET_FLOAT_WORD(is,t1);
+            SET_FLOAT_WORD(t1,is&0xfffff000);
+            t2 = v-(t1-u);
+        } else {
+            float s2,s_h,s_l,t_h,t_l;
+            n = 0;
+        /* take care subnormal number */
+            if(ix<0x00800000)
+                {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); }
+            n  += ((ix)>>23)-0x7f;
+            j  = ix&0x007fffff;
+        /* determine interval */
+            ix = j|0x3f800000;          /* normalize ix */
+            if(j<=0x1cc471) k=0;        /* |x|<sqrt(3/2) */
+            else if(j<0x5db3d7) k=1;    /* |x|<sqrt(3)   */
+            else {k=0;n+=1;ix -= 0x00800000;}
+            SET_FLOAT_WORD(ax,ix);
+
+        /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+            u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */
+            v = one/(ax+bp[k]);
+            s = u*v;
+            s_h = s;
+            GET_FLOAT_WORD(is,s_h);
+            SET_FLOAT_WORD(s_h,is&0xfffff000);
+        /* t_h=ax+bp[k] High */
+            is = ((ix>>1)&0xfffff000)|0x20000000;
+            SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21));
+            t_l = ax - (t_h-bp[k]);
+            s_l = v*((u-s_h*t_h)-s_h*t_l);
+        /* compute log(ax) */
+            s2 = s*s;
+            r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+            r += s_l*(s_h+s);
+            s2  = s_h*s_h;
+            t_h = (float)3.0+s2+r;
+            GET_FLOAT_WORD(is,t_h);
+            SET_FLOAT_WORD(t_h,is&0xfffff000);
+            t_l = r-((t_h-(float)3.0)-s2);
+        /* u+v = s*(1+...) */
+            u = s_h*t_h;
+            v = s_l*t_h+t_l*s;
+        /* 2/(3log2)*(s+...) */
+            p_h = u+v;
+            GET_FLOAT_WORD(is,p_h);
+            SET_FLOAT_WORD(p_h,is&0xfffff000);
+            p_l = v-(p_h-u);
+            z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */
+            z_l = cp_l*p_h+p_l*cp+dp_l[k];
+        /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+            t = (float)n;
+            t1 = (((z_h+z_l)+dp_h[k])+t);
+            GET_FLOAT_WORD(is,t1);
+            SET_FLOAT_WORD(t1,is&0xfffff000);
+            t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+        }
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+        GET_FLOAT_WORD(is,y);
+        SET_FLOAT_WORD(y1,is&0xfffff000);
+        p_l = (y-y1)*t1+y*t2;
+        p_h = y1*t1;
+        z = p_l+p_h;
+        GET_FLOAT_WORD(j,z);
+        if (j>0x43000000)                               /* if z > 128 */
+            return sn*huge*huge;                        /* overflow */
+        else if (j==0x43000000) {                       /* if z == 128 */
+            if(p_l+ovt>z-p_h) return sn*huge*huge;      /* overflow */
+        }
+        else if ((j&0x7fffffff)>0x43160000)             /* z <= -150 */
+            return sn*tiny*tiny;                        /* underflow */
+        else if (j==0xc3160000){                        /* z == -150 */
+            if(p_l<=z-p_h) return sn*tiny*tiny;         /* underflow */
+        }
+    /*
+     * compute 2**(p_h+p_l)
+     */
+        i = j&0x7fffffff;
+        k = (i>>23)-0x7f;
+        n = 0;
+        if(i>0x3f000000) {              /* if |z| > 0.5, set n = [z+0.5] */
+            n = j+(0x00800000>>(k+1));
+            k = ((n&0x7fffffff)>>23)-0x7f;      /* new k for n */
+            SET_FLOAT_WORD(t,n&~(0x007fffff>>k));
+            n = ((n&0x007fffff)|0x00800000)>>(23-k);
+            if(j<0) n = -n;
+            p_h -= t;
+        }
+        t = p_l+p_h;
+        GET_FLOAT_WORD(is,t);
+        SET_FLOAT_WORD(t,is&0xffff8000);
+        u = t*lg2_h;
+        v = (p_l-(t-p_h))*lg2+t*lg2_l;
+        z = u+v;
+        w = v-(z-u);
+        t  = z*z;
+        t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+        r  = (z*t1)/(t1-two)-(w+z*w);
+        z  = one-(r-z);
+        GET_FLOAT_WORD(j,z);
+        j += (n<<23);
+        if((j>>23)<=0) z = scalbnf(z,n);        /* subnormal output */
+        else SET_FLOAT_WORD(z,j);
+        return sn*z;
+}
diff --git a/src/math/e_rem_pio2.c b/src/math/e_rem_pio2.c
new file mode 100644
index 00000000..9eee36ae
--- /dev/null
+++ b/src/math/e_rem_pio2.c
@@ -0,0 +1,163 @@
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2(x,y)
+ * 
+ * return the remainder of x rem pi/2 in y[0]+y[1] 
+ * use __kernel_rem_pio2()
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi 
+ */
+static const int32_t two_over_pi[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, 
+};
+
+static const int32_t npio2_hw[] = {
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2:  53 bits of 2/pi
+ * pio2_1:   first  33 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 33 bit of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  33 bit of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double
+zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1  =  1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t =  6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2  =  6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t =  2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3  =  2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t =  8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+int32_t __ieee754_rem_pio2(double x, double *y)
+{
+        double z,w,t,r,fn;
+        double tx[3];
+        int32_t e0,i,j,nx,n,ix,hx;
+        uint32_t low;
+
+        GET_HIGH_WORD(hx,x);            /* high word of x */
+        ix = hx&0x7fffffff;
+        if(ix<=0x3fe921fb)   /* |x| ~<= pi/4 , no need for reduction */
+            {y[0] = x; y[1] = 0; return 0;}
+        if(ix<0x4002d97c) {  /* |x| < 3pi/4, special case with n=+-1 */
+            if(hx>0) { 
+                z = x - pio2_1;
+                if(ix!=0x3ff921fb) {    /* 33+53 bit pi is good enough */
+                    y[0] = z - pio2_1t;
+                    y[1] = (z-y[0])-pio2_1t;
+                } else {                /* near pi/2, use 33+33+53 bit pi */
+                    z -= pio2_2;
+                    y[0] = z - pio2_2t;
+                    y[1] = (z-y[0])-pio2_2t;
+                }
+                return 1;
+            } else {    /* negative x */
+                z = x + pio2_1;
+                if(ix!=0x3ff921fb) {    /* 33+53 bit pi is good enough */
+                    y[0] = z + pio2_1t;
+                    y[1] = (z-y[0])+pio2_1t;
+                } else {                /* near pi/2, use 33+33+53 bit pi */
+                    z += pio2_2;
+                    y[0] = z + pio2_2t;
+                    y[1] = (z-y[0])+pio2_2t;
+                }
+                return -1;
+            }
+        }
+        if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+            t  = fabs(x);
+            n  = (int32_t) (t*invpio2+half);
+            fn = (double)n;
+            r  = t-fn*pio2_1;
+            w  = fn*pio2_1t;    /* 1st round good to 85 bit */
+            if(n<32&&ix!=npio2_hw[n-1]) {       
+                y[0] = r-w;     /* quick check no cancellation */
+            } else {
+                uint32_t high;
+                j  = ix>>20;
+                y[0] = r-w; 
+                GET_HIGH_WORD(high,y[0]);
+                i = j-((high>>20)&0x7ff);
+                if(i>16) {  /* 2nd iteration needed, good to 118 */
+                    t  = r;
+                    w  = fn*pio2_2;     
+                    r  = t-w;
+                    w  = fn*pio2_2t-((t-r)-w);  
+                    y[0] = r-w;
+                    GET_HIGH_WORD(high,y[0]);
+                    i = j-((high>>20)&0x7ff);
+                    if(i>49)  { /* 3rd iteration need, 151 bits acc */
+                        t  = r; /* will cover all possible cases */
+                        w  = fn*pio2_3; 
+                        r  = t-w;
+                        w  = fn*pio2_3t-((t-r)-w);      
+                        y[0] = r-w;
+                    }
+                }
+            }
+            y[1] = (r-y[0])-w;
+            if(hx<0)    {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+            else         return n;
+        }
+    /* 
+     * all other (large) arguments
+     */
+        if(ix>=0x7ff00000) {            /* x is inf or NaN */
+            y[0]=y[1]=x-x; return 0;
+        }
+    /* set z = scalbn(|x|,ilogb(x)-23) */
+        GET_LOW_WORD(low,x);
+        e0      = (ix>>20)-1046;        /* e0 = ilogb(z)-23; */
+	INSERT_WORDS(z, ix - ((int32_t)(e0<<20)), low);
+        for(i=0;i<2;i++) {
+                tx[i] = (double)((int32_t)(z));
+                z     = (z-tx[i])*two24;
+        }
+        tx[2] = z;
+        nx = 3;
+        while(tx[nx-1]==zero) nx--;     /* skip zero term */
+        n  =  __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+        if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+        return n;
+}
diff --git a/src/math/e_rem_pio2f.c b/src/math/e_rem_pio2f.c
new file mode 100644
index 00000000..4992ea0c
--- /dev/null
+++ b/src/math/e_rem_pio2f.c
@@ -0,0 +1,175 @@
+/* e_rem_pio2f.c -- float version of e_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_rem_pio2f(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2f()
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+static const int32_t two_over_pi[] = {
+0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
+0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62,
+0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
+0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A,
+0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
+0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29,
+0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
+0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41,
+0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
+0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8,
+0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
+0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF,
+0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
+0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5,
+0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
+0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08,
+0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
+0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3,
+0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
+0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80,
+0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
+0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B,
+};
+
+/* This array is like the one in e_rem_pio2.c, but the numbers are
+   single precision and the last 8 bits are forced to 0.  */
+static const int32_t npio2_hw[] = {
+0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
+0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
+0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
+0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
+0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
+0x4242c700, 0x42490f00
+};
+
+/*
+ * invpio2:  24 bits of 2/pi
+ * pio2_1:   first  17 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 17 bit of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  17 bit of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const float
+zero =  0.0000000000e+00, /* 0x00000000 */
+half =  5.0000000000e-01, /* 0x3f000000 */
+two8 =  2.5600000000e+02, /* 0x43800000 */
+invpio2 =  6.3661980629e-01, /* 0x3f22f984 */
+pio2_1  =  1.5707855225e+00, /* 0x3fc90f80 */
+pio2_1t =  1.0804334124e-05, /* 0x37354443 */
+pio2_2  =  1.0804273188e-05, /* 0x37354400 */
+pio2_2t =  6.0770999344e-11, /* 0x2e85a308 */
+pio2_3  =  6.0770943833e-11, /* 0x2e85a300 */
+pio2_3t =  6.1232342629e-17; /* 0x248d3132 */
+
+int32_t __ieee754_rem_pio2f(float x, float *y)
+{
+        float z,w,t,r,fn;
+        float tx[3];
+        int32_t e0,i,j,nx,n,ix,hx;
+
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix<=0x3f490fd8)   /* |x| ~<= pi/4 , no need for reduction */
+            {y[0] = x; y[1] = 0; return 0;}
+        if(ix<0x4016cbe4) {  /* |x| < 3pi/4, special case with n=+-1 */
+            if(hx>0) {
+                z = x - pio2_1;
+                if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+                    y[0] = z - pio2_1t;
+                    y[1] = (z-y[0])-pio2_1t;
+                } else {                /* near pi/2, use 24+24+24 bit pi */
+                    z -= pio2_2;
+                    y[0] = z - pio2_2t;
+                    y[1] = (z-y[0])-pio2_2t;
+                }
+                return 1;
+            } else {    /* negative x */
+                z = x + pio2_1;
+                if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+                    y[0] = z + pio2_1t;
+                    y[1] = (z-y[0])+pio2_1t;
+                } else {                /* near pi/2, use 24+24+24 bit pi */
+                    z += pio2_2;
+                    y[0] = z + pio2_2t;
+                    y[1] = (z-y[0])+pio2_2t;
+                }
+                return -1;
+            }
+        }
+        if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
+            t  = fabsf(x);
+            n  = (int32_t) (t*invpio2+half);
+            fn = (float)n;
+            r  = t-fn*pio2_1;
+            w  = fn*pio2_1t;    /* 1st round good to 40 bit */
+            if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {
+                y[0] = r-w;     /* quick check no cancellation */
+            } else {
+                uint32_t high;
+                j  = ix>>23;
+                y[0] = r-w;
+                GET_FLOAT_WORD(high,y[0]);
+                i = j-((high>>23)&0xff);
+                if(i>8) {  /* 2nd iteration needed, good to 57 */
+                    t  = r;
+                    w  = fn*pio2_2;
+                    r  = t-w;
+                    w  = fn*pio2_2t-((t-r)-w);
+                    y[0] = r-w;
+                    GET_FLOAT_WORD(high,y[0]);
+                    i = j-((high>>23)&0xff);
+                    if(i>25)  { /* 3rd iteration need, 74 bits acc */
+                        t  = r; /* will cover all possible cases */
+                        w  = fn*pio2_3;
+                        r  = t-w;
+                        w  = fn*pio2_3t-((t-r)-w);
+                        y[0] = r-w;
+                    }
+                }
+            }
+            y[1] = (r-y[0])-w;
+            if(hx<0)    {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+            else         return n;
+        }
+    /*
+     * all other (large) arguments
+     */
+        if(ix>=0x7f800000) {            /* x is inf or NaN */
+            y[0]=y[1]=x-x; return 0;
+        }
+    /* set z = scalbn(|x|,ilogb(x)-7) */
+        e0      = (ix>>23)-134;         /* e0 = ilogb(z)-7; */
+        SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23)));
+        for(i=0;i<2;i++) {
+                tx[i] = (float)((int32_t)(z));
+                z     = (z-tx[i])*two8;
+        }
+        tx[2] = z;
+        nx = 3;
+        while(tx[nx-1]==zero) nx--;     /* skip zero term */
+        n  =  __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
+        if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+        return n;
+}
diff --git a/src/math/e_remainder.c b/src/math/e_remainder.c
new file mode 100644
index 00000000..9cb56919
--- /dev/null
+++ b/src/math/e_remainder.c
@@ -0,0 +1,69 @@
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* remainder(x,p)
+ * Return :                  
+ *      returns  x REM p  =  x - [x/p]*p as if in infinite 
+ *      precise arithmetic, where [x/p] is the (infinite bit) 
+ *      integer nearest x/p (in half way case choose the even one).
+ * Method : 
+ *      Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double zero = 0.0;
+
+
+double
+remainder(double x, double p)
+{
+        int32_t hx,hp;
+        uint32_t sx,lx,lp;
+        double p_half;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hp,lp,p);
+        sx = hx&0x80000000;
+        hp &= 0x7fffffff;
+        hx &= 0x7fffffff;
+
+    /* purge off exception values */
+        if((hp|lp)==0) return (x*p)/(x*p);      /* p = 0 */
+        if((hx>=0x7ff00000)||                   /* x not finite */
+          ((hp>=0x7ff00000)&&                   /* p is NaN */
+          (((hp-0x7ff00000)|lp)!=0)))
+            return (x*p)/(x*p);
+
+
+        if (hp<=0x7fdfffff) x = fmod(x,p+p);  /* now x < 2p */
+        if (((hx-hp)|(lx-lp))==0) return zero*x;
+        x  = fabs(x);
+        p  = fabs(p);
+        if (hp<0x00200000) {
+            if(x+x>p) {
+                x-=p;
+                if(x+x>=p) x -= p;
+            }
+        } else {
+            p_half = 0.5*p;
+            if(x>p_half) {
+                x-=p;
+                if(x>=p_half) x -= p;
+            }
+        }
+        GET_HIGH_WORD(hx,x);
+        SET_HIGH_WORD(x,hx^sx);
+        return x;
+}
diff --git a/src/math/e_remainderf.c b/src/math/e_remainderf.c
new file mode 100644
index 00000000..c292367d
--- /dev/null
+++ b/src/math/e_remainderf.c
@@ -0,0 +1,61 @@
+/* e_remainderf.c -- float version of e_remainder.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float zero = 0.0;
+
+
+float
+remainderf(float x, float p)
+{
+        int32_t hx,hp;
+        uint32_t sx;
+        float p_half;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hp,p);
+        sx = hx&0x80000000;
+        hp &= 0x7fffffff;
+        hx &= 0x7fffffff;
+
+    /* purge off exception values */
+        if(hp==0) return (x*p)/(x*p);           /* p = 0 */
+        if((hx>=0x7f800000)||                   /* x not finite */
+          ((hp>0x7f800000)))                    /* p is NaN */
+            return (x*p)/(x*p);
+
+
+        if (hp<=0x7effffff) x = fmodf(x,p+p); /* now x < 2p */
+        if ((hx-hp)==0) return zero*x;
+        x  = fabsf(x);
+        p  = fabsf(p);
+        if (hp<0x01000000) {
+            if(x+x>p) {
+                x-=p;
+                if(x+x>=p) x -= p;
+            }
+        } else {
+            p_half = (float)0.5*p;
+            if(x>p_half) {
+                x-=p;
+                if(x>=p_half) x -= p;
+            }
+        }
+        GET_FLOAT_WORD(hx,x);
+        SET_FLOAT_WORD(x,hx^sx);
+        return x;
+}
diff --git a/src/math/e_scalb.c b/src/math/e_scalb.c
new file mode 100644
index 00000000..cee2b44f
--- /dev/null
+++ b/src/math/e_scalb.c
@@ -0,0 +1,35 @@
+
+/* @(#)e_scalb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalb(x, fn) is provide for
+ * passing various standard test suite. One 
+ * should use scalbn() instead.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+scalb(double x, double fn)
+{
+        if (isnan(x)||isnan(fn)) return x*fn;
+        if (!isfinite(fn)) {
+            if(fn>0.0) return x*fn;
+            else       return x/(-fn);
+        }
+        if (rint(fn)!=fn) return (fn-fn)/(fn-fn);
+        if ( fn > 65000.0) return scalbn(x, 65000);
+        if (-fn > 65000.0) return scalbn(x,-65000);
+        return scalbn(x,(int)fn);
+}
diff --git a/src/math/e_scalbf.c b/src/math/e_scalbf.c
new file mode 100644
index 00000000..de7d7f67
--- /dev/null
+++ b/src/math/e_scalbf.c
@@ -0,0 +1,31 @@
+/* e_scalbf.c -- float version of e_scalb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+scalbf(float x, float fn)
+{
+        if (isnan(x)||isnan(fn)) return x*fn;
+        if (!isfinite(fn)) {
+            if(fn>(float)0.0) return x*fn;
+            else       return x/(-fn);
+        }
+        if (rintf(fn)!=fn) return (fn-fn)/(fn-fn);
+        if ( fn > (float)65000.0) return scalbnf(x, 65000);
+        if (-fn > (float)65000.0) return scalbnf(x,-65000);
+        return scalbnf(x,(int)fn);
+}
diff --git a/src/math/e_sinh.c b/src/math/e_sinh.c
new file mode 100644
index 00000000..3a574274
--- /dev/null
+++ b/src/math/e_sinh.c
@@ -0,0 +1,75 @@
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* sinh(x)
+ * Method : 
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ *      1. Replace x by |x| (sinh(-x) = -sinh(x)). 
+ *      2. 
+ *                                                  E + E/(E+1)
+ *          0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x)
+ *                                                      2
+ *
+ *          22       <= x <= lnovft :  sinh(x) := exp(x)/2 
+ *          lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2)
+ *          ln2ovft  <  x           :  sinh(x) := x*shuge (overflow)
+ *
+ * Special cases:
+ *      sinh(x) is |x| if x is +INF, -INF, or NaN.
+ *      only sinh(0)=0 is exact for finite x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0, shuge = 1.0e307;
+
+double
+sinh(double x)
+{
+        double t,w,h;
+        int32_t ix,jx;
+        uint32_t lx;
+
+    /* High word of |x|. */
+        GET_HIGH_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7ff00000) return x+x;  
+
+        h = 0.5;
+        if (jx<0) h = -h;
+    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+        if (ix < 0x40360000) {          /* |x|<22 */
+            if (ix<0x3e300000)          /* |x|<2**-28 */
+                if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+            t = expm1(fabs(x));
+            if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+            return h*(t+t/(t+one));
+        }
+
+    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+        if (ix < 0x40862E42)  return h*exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        GET_LOW_WORD(lx,x);
+        if (ix<0x408633CE || ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) {
+            w = exp(0.5*fabs(x));
+            t = h*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, sinh(x) overflow */
+        return x*shuge;
+}
diff --git a/src/math/e_sinhf.c b/src/math/e_sinhf.c
new file mode 100644
index 00000000..fe60608a
--- /dev/null
+++ b/src/math/e_sinhf.c
@@ -0,0 +1,56 @@
+/* e_sinhf.c -- float version of e_sinh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one = 1.0, shuge = 1.0e37;
+
+float
+sinhf(float x)
+{
+        float t,w,h;
+        int32_t ix,jx;
+
+        GET_FLOAT_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7f800000) return x+x;
+
+        h = 0.5;
+        if (jx<0) h = -h;
+    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+        if (ix < 0x41b00000) {          /* |x|<22 */
+            if (ix<0x31800000)          /* |x|<2**-28 */
+                if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+            t = expm1f(fabsf(x));
+            if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one));
+            return h*(t+t/(t+one));
+        }
+
+    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+        if (ix < 0x42b17180)  return h*expf(fabsf(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+        if (ix<=0x42b2d4fc) {
+            w = expf((float)0.5*fabsf(x));
+            t = h*w;
+            return t*w;
+        }
+
+    /* |x| > overflowthresold, sinh(x) overflow */
+        return x*shuge;
+}
diff --git a/src/math/e_sqrt.c b/src/math/e_sqrt.c
new file mode 100644
index 00000000..2bc68747
--- /dev/null
+++ b/src/math/e_sqrt.c
@@ -0,0 +1,442 @@
+
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* sqrt(x)
+ * Return correctly rounded sqrt.
+ *           ------------------------------------------
+ *           |  Use the hardware sqrt if you have one |
+ *           ------------------------------------------
+ * Method: 
+ *   Bit by bit method using integer arithmetic. (Slow, but portable) 
+ *   1. Normalization
+ *      Scale x to y in [1,4) with even powers of 2: 
+ *      find an integer k such that  1 <= (y=x*2^(2k)) < 4, then
+ *              sqrt(x) = 2^k * sqrt(y)
+ *   2. Bit by bit computation
+ *      Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
+ *           i                                                   0
+ *                                     i+1         2
+ *          s  = 2*q , and      y  =  2   * ( y - q  ).         (1)
+ *           i      i            i                 i
+ *                                                        
+ *      To compute q    from q , one checks whether 
+ *                  i+1       i                       
+ *
+ *                            -(i+1) 2
+ *                      (q + 2      ) <= y.                     (2)
+ *                        i
+ *                                                            -(i+1)
+ *      If (2) is false, then q   = q ; otherwise q   = q  + 2      .
+ *                             i+1   i             i+1   i
+ *
+ *      With some algebric manipulation, it is not difficult to see
+ *      that (2) is equivalent to 
+ *                             -(i+1)
+ *                      s  +  2       <= y                      (3)
+ *                       i                i
+ *
+ *      The advantage of (3) is that s  and y  can be computed by 
+ *                                    i      i
+ *      the following recurrence formula:
+ *          if (3) is false
+ *
+ *          s     =  s  ,       y    = y   ;                    (4)
+ *           i+1      i          i+1    i
+ *
+ *          otherwise,
+ *                         -i                     -(i+1)
+ *          s     =  s  + 2  ,  y    = y  -  s  - 2             (5)
+ *           i+1      i          i+1    i     i
+ *                              
+ *      One may easily use induction to prove (4) and (5). 
+ *      Note. Since the left hand side of (3) contain only i+2 bits,
+ *            it does not necessary to do a full (53-bit) comparison 
+ *            in (3).
+ *   3. Final rounding
+ *      After generating the 53 bits result, we compute one more bit.
+ *      Together with the remainder, we can decide whether the
+ *      result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ *      (it will never equal to 1/2ulp).
+ *      The rounding mode can be detected by checking whether
+ *      huge + tiny is equal to huge, and whether huge - tiny is
+ *      equal to huge for some floating point number "huge" and "tiny".
+ *              
+ * Special cases:
+ *      sqrt(+-0) = +-0         ... exact
+ *      sqrt(inf) = inf
+ *      sqrt(-ve) = NaN         ... with invalid signal
+ *      sqrt(NaN) = NaN         ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static  const double    one     = 1.0, tiny=1.0e-300;
+
+double
+sqrt(double x)
+{
+        double z;
+        int32_t sign = (int)0x80000000;
+        int32_t ix0,s0,q,m,t,i;
+        uint32_t r,t1,s1,ix1,q1;
+
+        EXTRACT_WORDS(ix0,ix1,x);
+
+    /* take care of Inf and NaN */
+        if((ix0&0x7ff00000)==0x7ff00000) {                      
+            return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+                                           sqrt(-inf)=sNaN */
+        } 
+    /* take care of zero */
+        if(ix0<=0) {
+            if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+            else if(ix0<0)
+                return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */
+        }
+    /* normalize x */
+        m = (ix0>>20);
+        if(m==0) {                              /* subnormal x */
+            while(ix0==0) {
+                m -= 21;
+                ix0 |= (ix1>>11); ix1 <<= 21;
+            }
+            for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+            m -= i-1;
+            ix0 |= (ix1>>(32-i));
+            ix1 <<= i;
+        }
+        m -= 1023;      /* unbias exponent */
+        ix0 = (ix0&0x000fffff)|0x00100000;
+        if(m&1){        /* odd m, double x to make it even */
+            ix0 += ix0 + ((ix1&sign)>>31);
+            ix1 += ix1;
+        }
+        m >>= 1;        /* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+        ix0 += ix0 + ((ix1&sign)>>31);
+        ix1 += ix1;
+        q = q1 = s0 = s1 = 0;   /* [q,q1] = sqrt(x) */
+        r = 0x00200000;         /* r = moving bit from right to left */
+
+        while(r!=0) {
+            t = s0+r; 
+            if(t<=ix0) { 
+                s0   = t+r; 
+                ix0 -= t; 
+                q   += r; 
+            } 
+            ix0 += ix0 + ((ix1&sign)>>31);
+            ix1 += ix1;
+            r>>=1;
+        }
+
+        r = sign;
+        while(r!=0) {
+            t1 = s1+r; 
+            t  = s0;
+            if((t<ix0)||((t==ix0)&&(t1<=ix1))) { 
+                s1  = t1+r;
+                if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+                ix0 -= t;
+                if (ix1 < t1) ix0 -= 1;
+                ix1 -= t1;
+                q1  += r;
+            }
+            ix0 += ix0 + ((ix1&sign)>>31);
+            ix1 += ix1;
+            r>>=1;
+        }
+
+    /* use floating add to find out rounding direction */
+        if((ix0|ix1)!=0) {
+            z = one-tiny; /* trigger inexact flag */
+            if (z>=one) {
+                z = one+tiny;
+                if (q1==(uint32_t)0xffffffff) { q1=0; q += 1;}
+                else if (z>one) {
+                    if (q1==(uint32_t)0xfffffffe) q+=1;
+                    q1+=2; 
+                } else
+                    q1 += (q1&1);
+            }
+        }
+        ix0 = (q>>1)+0x3fe00000;
+        ix1 =  q1>>1;
+        if ((q&1)==1) ix1 |= sign;
+        ix0 += (m <<20);
+        INSERT_WORDS(z,ix0,ix1);
+        return z;
+}
+
+/*
+Other methods  (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan 
+and K.C. Ng, written in May, 1986)
+
+        Two algorithms are given here to implement sqrt(x) 
+        (IEEE double precision arithmetic) in software.
+        Both supply sqrt(x) correctly rounded. The first algorithm (in
+        Section A) uses newton iterations and involves four divisions.
+        The second one uses reciproot iterations to avoid division, but
+        requires more multiplications. Both algorithms need the ability
+        to chop results of arithmetic operations instead of round them, 
+        and the INEXACT flag to indicate when an arithmetic operation
+        is executed exactly with no roundoff error, all part of the 
+        standard (IEEE 754-1985). The ability to perform shift, add,
+        subtract and logical AND operations upon 32-bit words is needed
+        too, though not part of the standard.
+
+A.  sqrt(x) by Newton Iteration
+
+   (1)  Initial approximation
+
+        Let x0 and x1 be the leading and the trailing 32-bit words of
+        a floating point number x (in IEEE double format) respectively 
+
+            1    11                  52                           ...widths
+           ------------------------------------------------------
+        x: |s|    e     |             f                         |
+           ------------------------------------------------------
+              msb    lsb  msb                                 lsb ...order
+
+ 
+             ------------------------        ------------------------
+        x0:  |s|   e    |    f1     |    x1: |          f2           |
+             ------------------------        ------------------------
+
+        By performing shifts and subtracts on x0 and x1 (both regarded
+        as integers), we obtain an 8-bit approximation of sqrt(x) as
+        follows.
+
+                k  := (x0>>1) + 0x1ff80000;
+                y0 := k - T1[31&(k>>15)].       ... y ~ sqrt(x) to 8 bits
+        Here k is a 32-bit integer and T1[] is an integer array containing
+        correction terms. Now magically the floating value of y (y's
+        leading 32-bit word is y0, the value of its trailing word is 0)
+        approximates sqrt(x) to almost 8-bit.
+
+        Value of T1:
+        static int T1[32]= {
+        0,      1024,   3062,   5746,   9193,   13348,  18162,  23592,
+        29598,  36145,  43202,  50740,  58733,  67158,  75992,  85215,
+        83599,  71378,  60428,  50647,  41945,  34246,  27478,  21581,
+        16499,  12183,  8588,   5674,   3403,   1742,   661,    130,};
+
+    (2) Iterative refinement
+
+        Apply Heron's rule three times to y, we have y approximates 
+        sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+                y := (y+x/y)/2          ... almost 17 sig. bits
+                y := (y+x/y)/2          ... almost 35 sig. bits
+                y := y-(y-x/y)/2        ... within 1 ulp
+
+
+        Remark 1.
+            Another way to improve y to within 1 ulp is:
+
+                y := (y+x/y)            ... almost 17 sig. bits to 2*sqrt(x)
+                y := y - 0x00100006     ... almost 18 sig. bits to sqrt(x)
+
+                                2
+                            (x-y )*y
+                y := y + 2* ----------  ...within 1 ulp
+                               2
+                             3y  + x
+
+
+        This formula has one division fewer than the one above; however,
+        it requires more multiplications and additions. Also x must be
+        scaled in advance to avoid spurious overflow in evaluating the
+        expression 3y*y+x. Hence it is not recommended uless division
+        is slow. If division is very slow, then one should use the 
+        reciproot algorithm given in section B.
+
+    (3) Final adjustment
+
+        By twiddling y's last bit it is possible to force y to be 
+        correctly rounded according to the prevailing rounding mode
+        as follows. Let r and i be copies of the rounding mode and
+        inexact flag before entering the square root program. Also we
+        use the expression y+-ulp for the next representable floating
+        numbers (up and down) of y. Note that y+-ulp = either fixed
+        point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+        mode.
+
+                I := FALSE;     ... reset INEXACT flag I
+                R := RZ;        ... set rounding mode to round-toward-zero
+                z := x/y;       ... chopped quotient, possibly inexact
+                If(not I) then {        ... if the quotient is exact
+                    if(z=y) {
+                        I := i;  ... restore inexact flag
+                        R := r;  ... restore rounded mode
+                        return sqrt(x):=y.
+                    } else {
+                        z := z - ulp;   ... special rounding
+                    }
+                }
+                i := TRUE;              ... sqrt(x) is inexact
+                If (r=RN) then z=z+ulp  ... rounded-to-nearest
+                If (r=RP) then {        ... round-toward-+inf
+                    y = y+ulp; z=z+ulp;
+                }
+                y := y+z;               ... chopped sum
+                y0:=y0-0x00100000;      ... y := y/2 is correctly rounded.
+                I := i;                 ... restore inexact flag
+                R := r;                 ... restore rounded mode
+                return sqrt(x):=y.
+                    
+    (4) Special cases
+
+        Square root of +inf, +-0, or NaN is itself;
+        Square root of a negative number is NaN with invalid signal.
+
+
+B.  sqrt(x) by Reciproot Iteration
+
+   (1)  Initial approximation
+
+        Let x0 and x1 be the leading and the trailing 32-bit words of
+        a floating point number x (in IEEE double format) respectively
+        (see section A). By performing shifs and subtracts on x0 and y0,
+        we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+            k := 0x5fe80000 - (x0>>1);
+            y0:= k - T2[63&(k>>14)].    ... y ~ 1/sqrt(x) to 7.8 bits
+
+        Here k is a 32-bit integer and T2[] is an integer array 
+        containing correction terms. Now magically the floating
+        value of y (y's leading 32-bit word is y0, the value of
+        its trailing word y1 is set to zero) approximates 1/sqrt(x)
+        to almost 7.8-bit.
+
+        Value of T2:
+        static int T2[64]= {
+        0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+        0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+        0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+        0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+        0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+        0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+        0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+        0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+    (2) Iterative refinement
+
+        Apply Reciproot iteration three times to y and multiply the
+        result by x to get an approximation z that matches sqrt(x)
+        to about 1 ulp. To be exact, we will have 
+                -1ulp < sqrt(x)-z<1.0625ulp.
+        
+        ... set rounding mode to Round-to-nearest
+           y := y*(1.5-0.5*x*y*y)       ... almost 15 sig. bits to 1/sqrt(x)
+           y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+        ... special arrangement for better accuracy
+           z := x*y                     ... 29 bits to sqrt(x), with z*y<1
+           z := z + 0.5*z*(1-z*y)       ... about 1 ulp to sqrt(x)
+
+        Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+        (a) the term z*y in the final iteration is always less than 1; 
+        (b) the error in the final result is biased upward so that
+                -1 ulp < sqrt(x) - z < 1.0625 ulp
+            instead of |sqrt(x)-z|<1.03125ulp.
+
+    (3) Final adjustment
+
+        By twiddling y's last bit it is possible to force y to be 
+        correctly rounded according to the prevailing rounding mode
+        as follows. Let r and i be copies of the rounding mode and
+        inexact flag before entering the square root program. Also we
+        use the expression y+-ulp for the next representable floating
+        numbers (up and down) of y. Note that y+-ulp = either fixed
+        point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+        mode.
+
+        R := RZ;                ... set rounding mode to round-toward-zero
+        switch(r) {
+            case RN:            ... round-to-nearest
+               if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+               if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+               break;
+            case RZ:case RM:    ... round-to-zero or round-to--inf
+               R:=RP;           ... reset rounding mod to round-to-+inf
+               if(x<z*z ... rounded up) z = z - ulp; else
+               if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+               break;
+            case RP:            ... round-to-+inf
+               if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+               if(x>z*z ...chopped) z = z+ulp;
+               break;
+        }
+
+        Remark 3. The above comparisons can be done in fixed point. For
+        example, to compare x and w=z*z chopped, it suffices to compare
+        x1 and w1 (the trailing parts of x and w), regarding them as
+        two's complement integers.
+
+        ...Is z an exact square root?
+        To determine whether z is an exact square root of x, let z1 be the
+        trailing part of z, and also let x0 and x1 be the leading and
+        trailing parts of x.
+
+        If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+            I := 1;             ... Raise Inexact flag: z is not exact
+        else {
+            j := 1 - [(x0>>20)&1]       ... j = logb(x) mod 2
+            k := z1 >> 26;              ... get z's 25-th and 26-th 
+                                            fraction bits
+            I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+        }
+        R:= r           ... restore rounded mode
+        return sqrt(x):=z.
+
+        If multiplication is cheaper then the foregoing red tape, the 
+        Inexact flag can be evaluated by
+
+            I := i;
+            I := (z*z!=x) or I.
+
+        Note that z*z can overwrite I; this value must be sensed if it is 
+        True.
+
+        Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+        zero.
+
+                    --------------------
+                z1: |        f2        | 
+                    --------------------
+                bit 31             bit 0
+
+        Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+        or even of logb(x) have the following relations:
+
+        -------------------------------------------------
+        bit 27,26 of z1         bit 1,0 of x1   logb(x)
+        -------------------------------------------------
+        00                      00              odd and even
+        01                      01              even
+        10                      10              odd
+        10                      00              even
+        11                      01              even
+        -------------------------------------------------
+
+    (4) Special cases (see (4) of Section A).   
+ 
+ */
+ 
diff --git a/src/math/e_sqrtf.c b/src/math/e_sqrtf.c
new file mode 100644
index 00000000..03a15beb
--- /dev/null
+++ b/src/math/e_sqrtf.c
@@ -0,0 +1,85 @@
+/* e_sqrtf.c -- float version of e_sqrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static  const float     one     = 1.0, tiny=1.0e-30;
+
+float
+sqrtf(float x)
+{
+        float z;
+        int32_t sign = (int)0x80000000;
+        int32_t ix,s,q,m,t,i;
+        uint32_t r;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* take care of Inf and NaN */
+        if((ix&0x7f800000)==0x7f800000) {
+            return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+                                           sqrt(-inf)=sNaN */
+        }
+    /* take care of zero */
+        if(ix<=0) {
+            if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */
+            else if(ix<0)
+                return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */
+        }
+    /* normalize x */
+        m = (ix>>23);
+        if(m==0) {                              /* subnormal x */
+            for(i=0;(ix&0x00800000)==0;i++) ix<<=1;
+            m -= i-1;
+        }
+        m -= 127;       /* unbias exponent */
+        ix = (ix&0x007fffff)|0x00800000;
+        if(m&1) /* odd m, double x to make it even */
+            ix += ix;
+        m >>= 1;        /* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+        ix += ix;
+        q = s = 0;              /* q = sqrt(x) */
+        r = 0x01000000;         /* r = moving bit from right to left */
+
+        while(r!=0) {
+            t = s+r;
+            if(t<=ix) {
+                s    = t+r;
+                ix  -= t;
+                q   += r;
+            }
+            ix += ix;
+            r>>=1;
+        }
+
+    /* use floating add to find out rounding direction */
+        if(ix!=0) {
+            z = one-tiny; /* trigger inexact flag */
+            if (z>=one) {
+                z = one+tiny;
+                if (z>one)
+                    q += 2;
+                else
+                    q += (q&1);
+            }
+        }
+        ix = (q>>1)+0x3f000000;
+        ix += (m <<23);
+        SET_FLOAT_WORD(z,ix);
+        return z;
+}
diff --git a/src/math/i386/e_exp.s b/src/math/i386/e_exp.s
new file mode 100644
index 00000000..d6c54a30
--- /dev/null
+++ b/src/math/i386/e_exp.s
@@ -0,0 +1,36 @@
+.global expf
+expf:
+	mov 4(%esp),%eax
+	flds 4(%esp)
+	shr $23,%eax
+	inc %al
+	jz 1f
+	jmp 0f
+
+.global exp
+exp:
+	mov 8(%esp),%eax
+	fldl 4(%esp)
+	shl %eax
+	cmp $0xffe00000,%eax
+	jae 1f
+
+0:	fldl2e
+	fmulp
+	fst %st(1)
+	frndint
+	fst %st(2)
+	fsubrp
+	f2xm1
+	fld1
+	faddp
+	fscale
+	fstp %st(1)
+	ret
+
+1:	fsts 4(%esp)
+	cmpl $0xff800000,4(%esp)
+	jnz 1f
+	fstp %st(0)
+	fldz
+1:	ret
diff --git a/src/math/i386/e_expf.s b/src/math/i386/e_expf.s
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/src/math/i386/e_expf.s
@@ -0,0 +1 @@
+
diff --git a/src/math/i386/e_log.s b/src/math/i386/e_log.s
new file mode 100644
index 00000000..34b8d38d
--- /dev/null
+++ b/src/math/i386/e_log.s
@@ -0,0 +1,6 @@
+.global log
+log:
+	fldln2
+	fldl 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_log10.s b/src/math/i386/e_log10.s
new file mode 100644
index 00000000..7f48941b
--- /dev/null
+++ b/src/math/i386/e_log10.s
@@ -0,0 +1,6 @@
+.global log10
+log10:
+	fldlg2
+	fldl 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_log10f.s b/src/math/i386/e_log10f.s
new file mode 100644
index 00000000..311486ea
--- /dev/null
+++ b/src/math/i386/e_log10f.s
@@ -0,0 +1,6 @@
+.global log10f
+log10f:
+	fldlg2
+	flds 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_logf.s b/src/math/i386/e_logf.s
new file mode 100644
index 00000000..b8beec0f
--- /dev/null
+++ b/src/math/i386/e_logf.s
@@ -0,0 +1,6 @@
+.global logf
+logf:
+	fldln2
+	flds 4(%esp)
+	fyl2x
+	ret
diff --git a/src/math/i386/e_remainder.s b/src/math/i386/e_remainder.s
new file mode 100644
index 00000000..b7ff3ef8
--- /dev/null
+++ b/src/math/i386/e_remainder.s
@@ -0,0 +1,16 @@
+.global remainderf
+remainderf:
+	flds 8(%esp)
+	flds 4(%esp)
+	jmp 1f
+	
+.global remainder
+remainder:
+	fldl 12(%esp)
+	fldl 4(%esp)
+1:	fprem1
+	fstsw %ax
+	sahf
+	jp 1b
+	fstp %st(1)
+	ret
diff --git a/src/math/i386/e_remainderf.s b/src/math/i386/e_remainderf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/e_remainderf.s
diff --git a/src/math/i386/e_sqrt.s b/src/math/i386/e_sqrt.s
new file mode 100644
index 00000000..11314dca
--- /dev/null
+++ b/src/math/i386/e_sqrt.s
@@ -0,0 +1,4 @@
+.global sqrt
+sqrt:	fldl 4(%esp)
+	fsqrt
+	ret
diff --git a/src/math/i386/e_sqrtf.s b/src/math/i386/e_sqrtf.s
new file mode 100644
index 00000000..015e24cd
--- /dev/null
+++ b/src/math/i386/e_sqrtf.s
@@ -0,0 +1,4 @@
+.global sqrtf
+sqrtf:	flds 4(%esp)
+	fsqrt
+	ret
diff --git a/src/math/i386/s_ceil.s b/src/math/i386/s_ceil.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ceil.s
diff --git a/src/math/i386/s_ceilf.s b/src/math/i386/s_ceilf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ceilf.s
diff --git a/src/math/i386/s_fabs.s b/src/math/i386/s_fabs.s
new file mode 100644
index 00000000..10c70f37
--- /dev/null
+++ b/src/math/i386/s_fabs.s
@@ -0,0 +1,5 @@
+.global fabs
+fabs:
+	fldl 4(%esp)
+	fabs
+	ret
diff --git a/src/math/i386/s_fabsf.s b/src/math/i386/s_fabsf.s
new file mode 100644
index 00000000..45442699
--- /dev/null
+++ b/src/math/i386/s_fabsf.s
@@ -0,0 +1,5 @@
+.global fabsf
+fabsf:
+	flds 4(%esp)
+	fabs
+	ret
diff --git a/src/math/i386/s_floor.s b/src/math/i386/s_floor.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_floor.s
diff --git a/src/math/i386/s_floorf.s b/src/math/i386/s_floorf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_floorf.s
diff --git a/src/math/i386/s_ldexp.s b/src/math/i386/s_ldexp.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ldexp.s
diff --git a/src/math/i386/s_ldexpf.s b/src/math/i386/s_ldexpf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_ldexpf.s
diff --git a/src/math/i386/s_rint.s b/src/math/i386/s_rint.s
new file mode 100644
index 00000000..5ba4ab4a
--- /dev/null
+++ b/src/math/i386/s_rint.s
@@ -0,0 +1,5 @@
+.global rint
+rint:
+	fldl 4(%esp)
+	frndint
+	ret
diff --git a/src/math/i386/s_rintf.s b/src/math/i386/s_rintf.s
new file mode 100644
index 00000000..d7aacd8f
--- /dev/null
+++ b/src/math/i386/s_rintf.s
@@ -0,0 +1,5 @@
+.global rintf
+rintf:
+	flds 4(%esp)
+	frndint
+	ret
diff --git a/src/math/i386/s_scalbln.s b/src/math/i386/s_scalbln.s
new file mode 100644
index 00000000..bd022b46
--- /dev/null
+++ b/src/math/i386/s_scalbln.s
@@ -0,0 +1,11 @@
+.global ldexp
+.global scalbn
+.global scalbln
+ldexp:
+scalbn:
+scalbln:
+	fildl 12(%esp)
+	fldl 4(%esp)
+	fscale
+	fstp %st(1)
+	ret
diff --git a/src/math/i386/s_scalblnf.s b/src/math/i386/s_scalblnf.s
new file mode 100644
index 00000000..379ec919
--- /dev/null
+++ b/src/math/i386/s_scalblnf.s
@@ -0,0 +1,11 @@
+.global ldexpf
+.global scalbnf
+.global scalblnf
+ldexpf:
+scalbnf:
+scalblnf:
+	fildl 8(%esp)
+	flds 4(%esp)
+	fscale
+	fstp %st(1)
+	ret
diff --git a/src/math/i386/s_trunc.s b/src/math/i386/s_trunc.s
new file mode 100644
index 00000000..0773891a
--- /dev/null
+++ b/src/math/i386/s_trunc.s
@@ -0,0 +1,36 @@
+.global ceilf
+ceilf:	flds 4(%esp)
+	jmp 1f
+	
+.global ceil
+ceil:	fldl 4(%esp)
+1:	mov $0x08fb,%edx
+	jmp 0f
+
+.global floorf
+floorf:	flds 4(%esp)
+	jmp 1f
+
+.global floor
+floor:	fldl 4(%esp)
+1:	mov $0x04f7,%edx
+	jmp 0f
+
+.global truncf
+truncf:	flds 4(%esp)
+	jmp 1f
+
+.global trunc
+trunc:	fldl 4(%esp)
+1:	mov $0x0cff,%edx
+
+0:	fstcw 4(%esp)
+	mov 5(%esp),%ah
+	or %dh,%ah
+	and %dl,%ah
+	xchg %ah,5(%esp)
+	fldcw 4(%esp)
+	frndint
+	mov %ah,5(%esp)
+	fldcw 4(%esp)
+	ret
diff --git a/src/math/i386/s_truncf.s b/src/math/i386/s_truncf.s
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/math/i386/s_truncf.s
diff --git a/src/math/k_cos.c b/src/math/k_cos.c
new file mode 100644
index 00000000..22e9841e
--- /dev/null
+++ b/src/math/k_cos.c
@@ -0,0 +1,85 @@
+
+/* @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_cos( x,  y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x. 
+ *
+ * Algorithm
+ *      1. Since cos(-x) = cos(x), we need only to consider positive x.
+ *      2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ *      3. cos(x) is approximated by a polynomial of degree 14 on
+ *         [0,pi/4]
+ *                                       4            14
+ *              cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ *         where the remez error is
+ *      
+ *      |              2     4     6     8     10    12     14 |     -58
+ *      |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
+ *      |                                                      | 
+ * 
+ *                     4     6     8     10    12     14 
+ *      4. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
+ *             cos(x) = 1 - x*x/2 + r
+ *         since cos(x+y) ~ cos(x) - sin(x)*y 
+ *                        ~ cos(x) - x*y,
+ *         a correction term is necessary in cos(x) and hence
+ *              cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ *         For better accuracy when x > 0.3, let qx = |x|/4 with
+ *         the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+ *         Then
+ *              cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
+ *         Note that 1-qx and (x*x/2-qx) is EXACT here, and the
+ *         magnitude of the latter is at least a quarter of x*x/2,
+ *         thus, reducing the rounding error in the subtraction.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1  =  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2  = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3  =  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4  = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5  =  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+double
+__kernel_cos(double x, double y)
+{
+        double a,hz,z,r,qx;
+        int32_t ix;
+        GET_HIGH_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* ix = |x|'s high word*/
+        if(ix<0x3e400000) {                     /* if x < 2**27 */
+            if(((int)x)==0) return one;         /* generate inexact */
+        }
+        z  = x*x;
+        r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+        if(ix < 0x3FD33333)                     /* if |x| < 0.3 */ 
+            return one - (0.5*z - (z*r - x*y));
+        else {
+            if(ix > 0x3fe90000) {               /* x > 0.78125 */
+                qx = 0.28125;
+            } else {
+                INSERT_WORDS(qx,ix-0x00200000,0);       /* x/4 */
+            }
+            hz = 0.5*z-qx;
+            a  = one-qx;
+            return a - (hz - (z*r-x*y));
+        }
+}
diff --git a/src/math/k_cosf.c b/src/math/k_cosf.c
new file mode 100644
index 00000000..61dc3749
--- /dev/null
+++ b/src/math/k_cosf.c
@@ -0,0 +1,52 @@
+/* k_cosf.c -- float version of k_cos.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3f800000 */
+C1  =  4.1666667908e-02, /* 0x3d2aaaab */
+C2  = -1.3888889225e-03, /* 0xbab60b61 */
+C3  =  2.4801587642e-05, /* 0x37d00d01 */
+C4  = -2.7557314297e-07, /* 0xb493f27c */
+C5  =  2.0875723372e-09, /* 0x310f74f6 */
+C6  = -1.1359647598e-11; /* 0xad47d74e */
+
+float
+__kernel_cosf(float x, float y)
+{
+        float a,hz,z,r,qx;
+        int32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* ix = |x|'s high word*/
+        if(ix<0x32000000) {                     /* if x < 2**27 */
+            if(((int)x)==0) return one;         /* generate inexact */
+        }
+        z  = x*x;
+        r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+        if(ix < 0x3e99999a)                     /* if |x| < 0.3 */
+            return one - ((float)0.5*z - (z*r - x*y));
+        else {
+            if(ix > 0x3f480000) {               /* x > 0.78125 */
+                qx = (float)0.28125;
+            } else {
+                SET_FLOAT_WORD(qx,ix-0x01000000);       /* x/4 */
+            }
+            hz = (float)0.5*z-qx;
+            a  = one-qx;
+            return a - (hz - (z*r-x*y));
+        }
+}
diff --git a/src/math/k_rem_pio2.c b/src/math/k_rem_pio2.c
new file mode 100644
index 00000000..d993e4f2
--- /dev/null
+++ b/src/math/k_rem_pio2.c
@@ -0,0 +1,300 @@
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ * 
+ * __kernel_rem_pio2 return the last three digits of N with 
+ *              y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of 
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ *      x[]     The input value (must be positive) is broken into nx 
+ *              pieces of 24-bit integers in double precision format.
+ *              x[i] will be the i-th 24 bit of x. The scaled exponent 
+ *              of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 
+ *              match x's up to 24 bits.
+ *
+ *              Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ *                      e0 = ilogb(z)-23
+ *                      z  = scalbn(z,-e0)
+ *              for i = 0,1,2
+ *                      x[i] = floor(z)
+ *                      z    = (z-x[i])*2**24
+ *
+ *
+ *      y[]     ouput result in an array of double precision numbers.
+ *              The dimension of y[] is:
+ *                      24-bit  precision       1
+ *                      53-bit  precision       2
+ *                      64-bit  precision       2
+ *                      113-bit precision       3
+ *              The actual value is the sum of them. Thus for 113-bit
+ *              precison, one may have to do something like:
+ *
+ *              long double t,w,r_head, r_tail;
+ *              t = (long double)y[2] + (long double)y[1];
+ *              w = (long double)y[0];
+ *              r_head = t+w;
+ *              r_tail = w - (r_head - t);
+ *
+ *      e0      The exponent of x[0]
+ *
+ *      nx      dimension of x[]
+ *
+ *      prec    an integer indicating the precision:
+ *                      0       24  bits (single)
+ *                      1       53  bits (double)
+ *                      2       64  bits (extended)
+ *                      3       113 bits (quad)
+ *
+ *      ipio2[]
+ *              integer array, contains the (24*i)-th to (24*i+23)-th 
+ *              bit of 2/pi after binary point. The corresponding 
+ *              floating value is
+ *
+ *                      ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ *      double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ *      jk      jk+1 is the initial number of terms of ipio2[] needed
+ *              in the computation. The recommended value is 2,3,4,
+ *              6 for single, double, extended,and quad.
+ *
+ *      jz      local integer variable indicating the number of 
+ *              terms of ipio2[] used. 
+ *
+ *      jx      nx - 1
+ *
+ *      jv      index for pointing to the suitable ipio2[] for the
+ *              computation. In general, we want
+ *                      ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ *              is an integer. Thus
+ *                      e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ *              Hence jv = max(0,(e0-3)/24).
+ *
+ *      jp      jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ *      q[]     double array with integral value, representing the
+ *              24-bits chunk of the product of x and 2/pi.
+ *
+ *      q0      the corresponding exponent of q[0]. Note that the
+ *              exponent for q[i] would be q0-24*i.
+ *
+ *      PIo2[]  double precision array, obtained by cutting pi/2
+ *              into 24 bits chunks. 
+ *
+ *      f[]     ipio2[] in floating point 
+ *
+ *      iq[]    integer array by breaking up q[] in 24-bits chunk.
+ *
+ *      fq[]    final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ *      ih      integer. If >0 it indicates q[] is >= 0.5, hence
+ *              it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+
+static const double PIo2[] = {
+  1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+  7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+  5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+  3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+  1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+  1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+  2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+  2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+static const double                     
+zero   = 0.0,
+one    = 1.0,
+two24   =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24  =  5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+        int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int32_t *ipio2)
+{
+        int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+        double z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+        jk = init_jk[prec];
+        jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+        jx =  nx-1;
+        jv = (e0-3)/24; if(jv<0) jv=0;
+        q0 =  e0-24*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+        j = jv-jx; m = jx+jk;
+        for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+        for (i=0;i<=jk;i++) {
+            for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+        }
+
+        jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+        for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+            fw    =  (double)((int32_t)(twon24* z));
+            iq[i] =  (int32_t)(z-two24*fw);
+            z     =  q[j-1]+fw;
+        }
+
+    /* compute n */
+        z  = scalbn(z,q0);              /* actual value of z */
+        z -= 8.0*floor(z*0.125);                /* trim off integer >= 8 */
+        n  = (int32_t) z;
+        z -= (double)n;
+        ih = 0;
+        if(q0>0) {      /* need iq[jz-1] to determine n */
+            i  = (iq[jz-1]>>(24-q0)); n += i;
+            iq[jz-1] -= i<<(24-q0);
+            ih = iq[jz-1]>>(23-q0);
+        } 
+        else if(q0==0) ih = iq[jz-1]>>23;
+        else if(z>=0.5) ih=2;
+
+        if(ih>0) {      /* q > 0.5 */
+            n += 1; carry = 0;
+            for(i=0;i<jz ;i++) {        /* compute 1-q */
+                j = iq[i];
+                if(carry==0) {
+                    if(j!=0) {
+                        carry = 1; iq[i] = 0x1000000- j;
+                    }
+                } else  iq[i] = 0xffffff - j;
+            }
+            if(q0>0) {          /* rare case: chance is 1 in 12 */
+                switch(q0) {
+                case 1:
+                   iq[jz-1] &= 0x7fffff; break;
+                case 2:
+                   iq[jz-1] &= 0x3fffff; break;
+                }
+            }
+            if(ih==2) {
+                z = one - z;
+                if(carry!=0) z -= scalbn(one,q0);
+            }
+        }
+
+    /* check if recomputation is needed */
+        if(z==zero) {
+            j = 0;
+            for (i=jz-1;i>=jk;i--) j |= iq[i];
+            if(j==0) { /* need recomputation */
+                for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+                for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+                    f[jx+i] = (double) ipio2[jv+i];
+                    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+                    q[i] = fw;
+                }
+                jz += k;
+                goto recompute;
+            }
+        }
+
+    /* chop off zero terms */
+        if(z==0.0) {
+            jz -= 1; q0 -= 24;
+            while(iq[jz]==0) { jz--; q0-=24;}
+        } else { /* break z into 24-bit if necessary */
+            z = scalbn(z,-q0);
+            if(z>=two24) { 
+                fw = (double)((int32_t)(twon24*z));
+                iq[jz] = (int32_t)(z-two24*fw);
+                jz += 1; q0 += 24;
+                iq[jz] = (int32_t) fw;
+            } else iq[jz] = (int32_t) z ;
+        }
+
+    /* convert integer "bit" chunk to floating-point value */
+        fw = scalbn(one,q0);
+        for(i=jz;i>=0;i--) {
+            q[i] = fw*(double)iq[i]; fw*=twon24;
+        }
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+        for(i=jz;i>=0;i--) {
+            for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+            fq[jz-i] = fw;
+        }
+
+    /* compress fq[] into y[] */
+        switch(prec) {
+            case 0:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i];
+                y[0] = (ih==0)? fw: -fw; 
+                break;
+            case 1:
+            case 2:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i]; 
+                y[0] = (ih==0)? fw: -fw; 
+                fw = fq[0]-fw;
+                for (i=1;i<=jz;i++) fw += fq[i];
+                y[1] = (ih==0)? fw: -fw; 
+                break;
+            case 3:     /* painful */
+                for (i=jz;i>0;i--) {
+                    fw      = fq[i-1]+fq[i]; 
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (i=jz;i>1;i--) {
+                    fw      = fq[i-1]+fq[i]; 
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; 
+                if(ih==0) {
+                    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+                } else {
+                    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+                }
+        }
+        return n&7;
+}
diff --git a/src/math/k_rem_pio2f.c b/src/math/k_rem_pio2f.c
new file mode 100644
index 00000000..b543f084
--- /dev/null
+++ b/src/math/k_rem_pio2f.c
@@ -0,0 +1,192 @@
+/* k_rem_pio2f.c -- float version of k_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/* In the float version, the input parameter x contains 8 bit
+   integers, not 24 bit integers.  113 bit precision is not supported.  */
+
+static const int init_jk[] = {4,7,9}; /* initial value for jk */
+
+static const float PIo2[] = {
+  1.5703125000e+00, /* 0x3fc90000 */
+  4.5776367188e-04, /* 0x39f00000 */
+  2.5987625122e-05, /* 0x37da0000 */
+  7.5437128544e-08, /* 0x33a20000 */
+  6.0026650317e-11, /* 0x2e840000 */
+  7.3896444519e-13, /* 0x2b500000 */
+  5.3845816694e-15, /* 0x27c20000 */
+  5.6378512969e-18, /* 0x22d00000 */
+  8.3009228831e-20, /* 0x1fc40000 */
+  3.2756352257e-22, /* 0x1bc60000 */
+  6.3331015649e-25, /* 0x17440000 */
+};
+
+static const float
+zero   = 0.0,
+one    = 1.0,
+two8   =  2.5600000000e+02, /* 0x43800000 */
+twon8  =  3.9062500000e-03; /* 0x3b800000 */
+
+        int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const int32_t *ipio2)
+{
+        int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+        float z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+        jk = init_jk[prec];
+        jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+        jx =  nx-1;
+        jv = (e0-3)/8; if(jv<0) jv=0;
+        q0 =  e0-8*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+        j = jv-jx; m = jx+jk;
+        for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+        for (i=0;i<=jk;i++) {
+            for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+        }
+
+        jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+        for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+            fw    =  (float)((int32_t)(twon8* z));
+            iq[i] =  (int32_t)(z-two8*fw);
+            z     =  q[j-1]+fw;
+        }
+
+    /* compute n */
+        z  = scalbnf(z,q0);             /* actual value of z */
+        z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
+        n  = (int32_t) z;
+        z -= (float)n;
+        ih = 0;
+        if(q0>0) {      /* need iq[jz-1] to determine n */
+            i  = (iq[jz-1]>>(8-q0)); n += i;
+            iq[jz-1] -= i<<(8-q0);
+            ih = iq[jz-1]>>(7-q0);
+        }
+        else if(q0==0) ih = iq[jz-1]>>7;
+        else if(z>=(float)0.5) ih=2;
+
+        if(ih>0) {      /* q > 0.5 */
+            n += 1; carry = 0;
+            for(i=0;i<jz ;i++) {        /* compute 1-q */
+                j = iq[i];
+                if(carry==0) {
+                    if(j!=0) {
+                        carry = 1; iq[i] = 0x100- j;
+                    }
+                } else  iq[i] = 0xff - j;
+            }
+            if(q0>0) {          /* rare case: chance is 1 in 12 */
+                switch(q0) {
+                case 1:
+                   iq[jz-1] &= 0x7f; break;
+                case 2:
+                   iq[jz-1] &= 0x3f; break;
+                }
+            }
+            if(ih==2) {
+                z = one - z;
+                if(carry!=0) z -= scalbnf(one,q0);
+            }
+        }
+
+    /* check if recomputation is needed */
+        if(z==zero) {
+            j = 0;
+            for (i=jz-1;i>=jk;i--) j |= iq[i];
+            if(j==0) { /* need recomputation */
+                for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+                for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+                    f[jx+i] = (float) ipio2[jv+i];
+                    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+                    q[i] = fw;
+                }
+                jz += k;
+                goto recompute;
+            }
+        }
+
+    /* chop off zero terms */
+        if(z==(float)0.0) {
+            jz -= 1; q0 -= 8;
+            while(iq[jz]==0) { jz--; q0-=8;}
+        } else { /* break z into 8-bit if necessary */
+            z = scalbnf(z,-q0);
+            if(z>=two8) {
+                fw = (float)((int32_t)(twon8*z));
+                iq[jz] = (int32_t)(z-two8*fw);
+                jz += 1; q0 += 8;
+                iq[jz] = (int32_t) fw;
+            } else iq[jz] = (int32_t) z ;
+        }
+
+    /* convert integer "bit" chunk to floating-point value */
+        fw = scalbnf(one,q0);
+        for(i=jz;i>=0;i--) {
+            q[i] = fw*(float)iq[i]; fw*=twon8;
+        }
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+        for(i=jz;i>=0;i--) {
+            for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+            fq[jz-i] = fw;
+        }
+
+    /* compress fq[] into y[] */
+        switch(prec) {
+            case 0:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i];
+                y[0] = (ih==0)? fw: -fw;
+                break;
+            case 1:
+            case 2:
+                fw = 0.0;
+                for (i=jz;i>=0;i--) fw += fq[i];
+                y[0] = (ih==0)? fw: -fw;
+                fw = fq[0]-fw;
+                for (i=1;i<=jz;i++) fw += fq[i];
+                y[1] = (ih==0)? fw: -fw;
+                break;
+            case 3:     /* painful */
+                for (i=jz;i>0;i--) {
+                    fw      = fq[i-1]+fq[i];
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (i=jz;i>1;i--) {
+                    fw      = fq[i-1]+fq[i];
+                    fq[i]  += fq[i-1]-fw;
+                    fq[i-1] = fw;
+                }
+                for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+                if(ih==0) {
+                    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+                } else {
+                    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+                }
+        }
+        return n&7;
+}
diff --git a/src/math/k_sin.c b/src/math/k_sin.c
new file mode 100644
index 00000000..9def2589
--- /dev/null
+++ b/src/math/k_sin.c
@@ -0,0 +1,68 @@
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). 
+ *
+ * Algorithm
+ *      1. Since sin(-x) = -sin(x), we need only to consider positive x. 
+ *      2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.
+ *      3. sin(x) is approximated by a polynomial of degree 13 on
+ *         [0,pi/4]
+ *                               3            13
+ *              sin(x) ~ x + S1*x + ... + S6*x
+ *         where
+ *      
+ *      |sin(x)         2     4     6     8     10     12  |     -58
+ *      |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
+ *      |  x                                               | 
+ * 
+ *      4. sin(x+y) = sin(x) + sin'(x')*y
+ *                  ~ sin(x) + (1-x*x/2)*y
+ *         For better accuracy, let 
+ *                   3      2      2      2      2
+ *              r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ *         then                   3    2
+ *              sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1  = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2  =  8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3  = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4  =  2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5  = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6  =  1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+double
+__kernel_sin(double x, double y, int iy)
+{
+        double z,r,v;
+        int32_t ix;
+        GET_HIGH_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* high word of x */
+        if(ix<0x3e400000)                       /* |x| < 2**-27 */
+           {if((int)x==0) return x;}            /* generate inexact */
+        z       =  x*x;
+        v       =  z*x;
+        r       =  S2+z*(S3+z*(S4+z*(S5+z*S6)));
+        if(iy==0) return x+v*(S1+z*r);
+        else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/src/math/k_sinf.c b/src/math/k_sinf.c
new file mode 100644
index 00000000..617f6148
--- /dev/null
+++ b/src/math/k_sinf.c
@@ -0,0 +1,42 @@
+/* k_sinf.c -- float version of k_sin.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+half =  5.0000000000e-01,/* 0x3f000000 */
+S1  = -1.6666667163e-01, /* 0xbe2aaaab */
+S2  =  8.3333337680e-03, /* 0x3c088889 */
+S3  = -1.9841270114e-04, /* 0xb9500d01 */
+S4  =  2.7557314297e-06, /* 0x3638ef1b */
+S5  = -2.5050759689e-08, /* 0xb2d72f34 */
+S6  =  1.5896910177e-10; /* 0x2f2ec9d3 */
+
+float
+__kernel_sinf(float x, float y, int iy)
+{
+        float z,r,v;
+        int32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* high word of x */
+        if(ix<0x32000000)                       /* |x| < 2**-27 */
+           {if((int)x==0) return x;}            /* generate inexact */
+        z       =  x*x;
+        v       =  z*x;
+        r       =  S2+z*(S3+z*(S4+z*(S5+z*S6)));
+        if(iy==0) return x+v*(S1+z*r);
+        else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/src/math/k_tan.c b/src/math/k_tan.c
new file mode 100644
index 00000000..f721ae6d
--- /dev/null
+++ b/src/math/k_tan.c
@@ -0,0 +1,149 @@
+/* @(#)k_tan.c 1.5 04/04/22 SMI */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned.
+ *
+ * Algorithm
+ *      1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ *      2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+ *      3. tan(x) is approximated by a odd polynomial of degree 27 on
+ *         [0,0.67434]
+ *                               3             27
+ *              tan(x) ~ x + T1*x + ... + T13*x
+ *         where
+ *
+ *              |tan(x)         2     4            26   |     -59.2
+ *              |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
+ *              |  x                                    |
+ *
+ *         Note: tan(x+y) = tan(x) + tan'(x)*y
+ *                        ~ tan(x) + (1+x*x)*y
+ *         Therefore, for better accuracy in computing tan(x+y), let
+ *                   3      2      2       2       2
+ *              r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ *         then
+ *                                  3    2
+ *              tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ *      4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
+ *              tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ *                     = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include <math.h>
+#include "math_private.h"
+static const double xxx[] = {
+                 3.33333333333334091986e-01,    /* 3FD55555, 55555563 */
+                 1.33333333333201242699e-01,    /* 3FC11111, 1110FE7A */
+                 5.39682539762260521377e-02,    /* 3FABA1BA, 1BB341FE */
+                 2.18694882948595424599e-02,    /* 3F9664F4, 8406D637 */
+                 8.86323982359930005737e-03,    /* 3F8226E3, E96E8493 */
+                 3.59207910759131235356e-03,    /* 3F6D6D22, C9560328 */
+                 1.45620945432529025516e-03,    /* 3F57DBC8, FEE08315 */
+                 5.88041240820264096874e-04,    /* 3F4344D8, F2F26501 */
+                 2.46463134818469906812e-04,    /* 3F3026F7, 1A8D1068 */
+                 7.81794442939557092300e-05,    /* 3F147E88, A03792A6 */
+                 7.14072491382608190305e-05,    /* 3F12B80F, 32F0A7E9 */
+                -1.85586374855275456654e-05,    /* BEF375CB, DB605373 */
+                 2.59073051863633712884e-05,    /* 3EFB2A70, 74BF7AD4 */
+/* one */        1.00000000000000000000e+00,    /* 3FF00000, 00000000 */
+/* pio4 */       7.85398163397448278999e-01,    /* 3FE921FB, 54442D18 */
+/* pio4lo */     3.06161699786838301793e-17     /* 3C81A626, 33145C07 */
+};
+#define one     xxx[13]
+#define pio4    xxx[14]
+#define pio4lo  xxx[15]
+#define T       xxx
+/* INDENT ON */
+
+double
+__kernel_tan(double x, double y, int iy) {
+        double z, r, v, w, s;
+        int32_t ix, hx;
+
+        GET_HIGH_WORD(hx,x);
+        ix = hx & 0x7fffffff;                   /* high word of |x| */
+        if (ix < 0x3e300000) {                  /* x < 2**-28 */
+                if ((int) x == 0) {             /* generate inexact */
+                        uint32_t low;
+                        GET_LOW_WORD(low,x);
+                        if (((ix | low) | (iy + 1)) == 0)
+                                return one / fabs(x);
+                        else {
+                                if (iy == 1)
+                                        return x;
+                                else {  /* compute -1 / (x+y) carefully */
+                                        double a, t;
+
+                                        z = w = x + y;
+                                        SET_LOW_WORD(z, 0);
+                                        v = y - (z - x);
+                                        t = a = -one / w;
+                                        SET_LOW_WORD(t, 0);
+                                        s = one + t * z;
+                                        return t + a * (s + t * v);
+                                }
+                        }
+                }
+        }
+        if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */
+                if (hx < 0) {
+                        x = -x;
+                        y = -y;
+                }
+                z = pio4 - x;
+                w = pio4lo - y;
+                x = z + w;
+                y = 0.0;
+        }
+        z = x * x;
+        w = z * z;
+        /*
+         * Break x^5*(T[1]+x^2*T[2]+...) into
+         * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+         * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+         */
+        r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] +
+                w * T[11]))));
+        v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] +
+                w * T[12])))));
+        s = z * x;
+        r = y + z * (s * (r + v) + y);
+        r += T[0] * s;
+        w = x + r;
+        if (ix >= 0x3FE59428) {
+                v = (double) iy;
+                return (double) (1 - ((hx >> 30) & 2)) *
+                        (v - 2.0 * (x - (w * w / (w + v) - r)));
+        }
+        if (iy == 1)
+                return w;
+        else {
+                /*
+                 * if allow error up to 2 ulp, simply return
+                 * -1.0 / (x+r) here
+                 */
+                /* compute -1.0 / (x+r) accurately */
+                double a, t;
+                z = w;
+                SET_LOW_WORD(z,0);
+                v = r - (z - x);        /* z+v = r+x */
+                t = a = -1.0 / w;       /* a = -1.0/w */
+                SET_LOW_WORD(t,0);
+                s = 1.0 + t * z;
+                return t + a * (s + t * v);
+        }
+}
diff --git a/src/math/k_tanf.c b/src/math/k_tanf.c
new file mode 100644
index 00000000..99ede58c
--- /dev/null
+++ b/src/math/k_tanf.c
@@ -0,0 +1,105 @@
+/* k_tanf.c -- float version of k_tan.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+static const float
+one   =  1.0000000000e+00, /* 0x3f800000 */
+pio4  =  7.8539812565e-01, /* 0x3f490fda */
+pio4lo=  3.7748947079e-08, /* 0x33222168 */
+T[] =  {
+  3.3333334327e-01, /* 0x3eaaaaab */
+  1.3333334029e-01, /* 0x3e088889 */
+  5.3968254477e-02, /* 0x3d5d0dd1 */
+  2.1869488060e-02, /* 0x3cb327a4 */
+  8.8632395491e-03, /* 0x3c11371f */
+  3.5920790397e-03, /* 0x3b6b6916 */
+  1.4562094584e-03, /* 0x3abede48 */
+  5.8804126456e-04, /* 0x3a1a26c8 */
+  2.4646313977e-04, /* 0x398137b9 */
+  7.8179444245e-05, /* 0x38a3f445 */
+  7.1407252108e-05, /* 0x3895c07a */
+ -1.8558637748e-05, /* 0xb79bae5f */
+  2.5907305826e-05, /* 0x37d95384 */
+};
+
+float
+__kernel_tanf(float x, float y, int iy)
+{
+        float z,r,v,w,s;
+        int32_t ix,hx;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;     /* high word of |x| */
+        if(ix<0x31800000) {                     /* x < 2**-28 */
+                if ((int) x == 0) {             /* generate inexact */
+                        if ((ix | (iy + 1)) == 0)
+                                return one / fabsf(x);
+                        else {
+                                if (iy == 1)
+                                        return x;
+                                else {  /* compute -1 / (x+y) carefully */
+                                        double a, t;
+
+                                        z = w = x + y;
+                                        GET_FLOAT_WORD(ix, z);
+                                        SET_FLOAT_WORD(z, ix & 0xfffff000);
+                                        v = y - (z - x);
+                                        t = a = -one / w;
+                                        GET_FLOAT_WORD(ix, t);
+                                        SET_FLOAT_WORD(t, ix & 0xfffff000);
+                                        s = one + t * z;
+                                        return t + a * (s + t * v);
+                                }
+                        }
+                }
+        }
+        if(ix>=0x3f2ca140) {                    /* |x|>=0.6744 */
+            if(hx<0) {x = -x; y = -y;}
+            z = pio4-x;
+            w = pio4lo-y;
+            x = z+w; y = 0.0;
+        }
+        z       =  x*x;
+        w       =  z*z;
+    /* Break x^5*(T[1]+x^2*T[2]+...) into
+     *    x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+     *    x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+     */
+        r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
+        v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
+        s = z*x;
+        r = y + z*(s*(r+v)+y);
+        r += T[0]*s;
+        w = x+r;
+        if(ix>=0x3f2ca140) {
+            v = (float)iy;
+            return (float)(1-((hx>>30)&2))*(v-(float)2.0*(x-(w*w/(w+v)-r)));
+        }
+        if(iy==1) return w;
+        else {          /* if allow error up to 2 ulp,
+                           simply return -1.0/(x+r) here */
+     /*  compute -1.0/(x+r) accurately */
+            float a,t;
+            int32_t i;
+            z  = w;
+            GET_FLOAT_WORD(i,z);
+            SET_FLOAT_WORD(z,i&0xfffff000);
+            v  = r-(z - x);     /* z+v = r+x */
+            t = a  = -(float)1.0/w;     /* a = -1.0/w */
+            GET_FLOAT_WORD(i,t);
+            SET_FLOAT_WORD(t,i&0xfffff000);
+            s  = (float)1.0+t*z;
+            return t+a*(s+t*v);
+        }
+}
diff --git a/src/math/math_private.h b/src/math/math_private.h
new file mode 100644
index 00000000..28a6a195
--- /dev/null
+++ b/src/math/math_private.h
@@ -0,0 +1,143 @@
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef _MATH_PRIVATE_H_
+#define _MATH_PRIVATE_H_
+
+#include <inttypes.h>
+
+/*
+ * The original fdlibm code used statements like:
+ *      n0 = ((*(int*)&one)>>29)^1;             * index of high word *
+ *      ix0 = *(n0+(int*)&x);                   * high word of x *
+ *      ix1 = *((1-n0)+(int*)&x);               * low word of x *
+ * to dig two 32 bit words out of the 64 bit IEEE floating point
+ * value.  That is non-ANSI, and, moreover, the gcc instruction
+ * scheduler gets it wrong.  We instead use the following macros.
+ * Unlike the original code, we determine the endianness at compile
+ * time, not at run time; I don't see much benefit to selecting
+ * endianness at run time.
+ */
+
+/*
+ * A union which permits us to convert between a double and two 32 bit
+ * ints.
+ */
+
+typedef union
+{
+  double value;
+  uint64_t words;
+} ieee_double_shape_type;
+
+/* Get two 32 bit ints from a double.  */
+
+#define EXTRACT_WORDS(ix0,ix1,d)                                \
+do {                                                            \
+  ieee_double_shape_type ew_u;                                  \
+  ew_u.value = (d);                                             \
+  (ix0) = ew_u.words >> 32;                                     \
+  (ix1) = (uint32_t)ew_u.words;                                 \
+} while (0)
+
+/* Get the more significant 32 bit int from a double.  */
+
+#define GET_HIGH_WORD(i,d)                                      \
+do {                                                            \
+  ieee_double_shape_type gh_u;                                  \
+  gh_u.value = (d);                                             \
+  (i) = gh_u.words >> 32;                                       \
+} while (0)
+
+/* Get the less significant 32 bit int from a double.  */
+
+#define GET_LOW_WORD(i,d)                                       \
+do {                                                            \
+  ieee_double_shape_type gl_u;                                  \
+  gl_u.value = (d);                                             \
+  (i) = (uint32_t)gl_u.words;                                   \
+} while (0)
+
+/* Set a double from two 32 bit ints.  */
+
+#define INSERT_WORDS(d,ix0,ix1)                                 \
+do {                                                            \
+  ieee_double_shape_type iw_u;                                  \
+  iw_u.words = ((uint64_t)(ix0) << 32) | (ix1);                 \
+  (d) = iw_u.value;                                             \
+} while (0)
+
+/* Set the more significant 32 bits of a double from an int.  */
+
+#define SET_HIGH_WORD(d,v)                                      \
+do {                                                            \
+  ieee_double_shape_type sh_u;                                  \
+  sh_u.value = (d);                                             \
+  sh_u.words &= 0xffffffff;                                     \
+  sh_u.words |= ((uint64_t)(v) << 32);                          \
+  (d) = sh_u.value;                                             \
+} while (0)
+
+/* Set the less significant 32 bits of a double from an int.  */
+
+#define SET_LOW_WORD(d,v)                                       \
+do {                                                            \
+  ieee_double_shape_type sl_u;                                  \
+  sl_u.value = (d);                                             \
+  sl_u.words &= 0xffffffff00000000ull;                          \
+  sl_u.words |= (uint32_t)(v);                                  \
+  (d) = sl_u.value;                                             \
+} while (0)
+
+/*
+ * A union which permits us to convert between a float and a 32 bit
+ * int.
+ */
+
+typedef union
+{
+  float value;
+  uint32_t word;
+} ieee_float_shape_type;
+
+/* Get a 32 bit int from a float.  */
+
+#define GET_FLOAT_WORD(i,d)                                     \
+do {                                                            \
+  ieee_float_shape_type gf_u;                                   \
+  gf_u.value = (d);                                             \
+  (i) = gf_u.word;                                              \
+} while (0)
+
+/* Set a float from a 32 bit int.  */
+
+#define SET_FLOAT_WORD(d,i)                                     \
+do {                                                            \
+  ieee_float_shape_type sf_u;                                   \
+  sf_u.word = (i);                                              \
+  (d) = sf_u.value;                                             \
+} while (0)
+
+/* fdlibm kernel function */
+int     __ieee754_rem_pio2(double,double*);
+double  __kernel_sin(double,double,int);
+double  __kernel_cos(double,double);
+double  __kernel_tan(double,double,int);
+int     __kernel_rem_pio2(double*,double*,int,int,int,const int*);
+
+/* float versions of fdlibm kernel functions */
+int     __ieee754_rem_pio2f(float,float*);
+float   __kernel_sinf(float,float,int);
+float   __kernel_cosf(float,float);
+float   __kernel_tanf(float,float,int);
+int     __kernel_rem_pio2f(float*,float*,int,int,int,const int*);
+
+#endif /* !_MATH_PRIVATE_H_ */
diff --git a/src/math/s_asinh.c b/src/math/s_asinh.c
new file mode 100644
index 00000000..26016091
--- /dev/null
+++ b/src/math/s_asinh.c
@@ -0,0 +1,53 @@
+/* @(#)s_asinh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* asinh(x)
+ * Method :
+ *      Based on
+ *              asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ *      we have
+ *      asinh(x) := x  if  1+x*x=1,
+ *               := sign(x)*(log(x)+ln2)) for large |x|, else
+ *               := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ *               := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+huge=  1.00000000000000000000e+300;
+
+double
+asinh(double x)
+{
+        double t,w;
+        int32_t hx,ix;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7ff00000) return x+x;  /* x is inf or NaN */
+        if(ix< 0x3e300000) {    /* |x|<2**-28 */
+            if(huge+x>one) return x;    /* return x inexact except 0 */
+        }
+        if(ix>0x41b00000) {     /* |x| > 2**28 */
+            w = log(fabs(x))+ln2;
+        } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */
+            t = fabs(x);
+            w = log(2.0*t+one/(sqrt(x*x+one)+t));
+        } else {                /* 2.0 > |x| > 2**-28 */
+            t = x*x;
+            w =log1p(fabs(x)+t/(one+sqrt(one+t)));
+        }
+        if(hx>0) return w; else return -w;
+}
diff --git a/src/math/s_asinhf.c b/src/math/s_asinhf.c
new file mode 100644
index 00000000..04f8d072
--- /dev/null
+++ b/src/math/s_asinhf.c
@@ -0,0 +1,45 @@
+/* s_asinhf.c -- float version of s_asinh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+one =  1.0000000000e+00, /* 0x3F800000 */
+ln2 =  6.9314718246e-01, /* 0x3f317218 */
+huge=  1.0000000000e+30;
+
+float
+asinhf(float x)
+{
+        float t,w;
+        int32_t hx,ix;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7f800000) return x+x;  /* x is inf or NaN */
+        if(ix< 0x31800000) {    /* |x|<2**-28 */
+            if(huge+x>one) return x;    /* return x inexact except 0 */
+        }
+        if(ix>0x4d800000) {     /* |x| > 2**28 */
+            w = logf(fabsf(x))+ln2;
+        } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */
+            t = fabsf(x);
+            w = logf((float)2.0*t+one/(sqrtf(x*x+one)+t));
+        } else {                /* 2.0 > |x| > 2**-28 */
+            t = x*x;
+            w =log1pf(fabsf(x)+t/(one+sqrtf(one+t)));
+        }
+        if(hx>0) return w; else return -w;
+}
diff --git a/src/math/s_atan.c b/src/math/s_atan.c
new file mode 100644
index 00000000..1faac024
--- /dev/null
+++ b/src/math/s_atan.c
@@ -0,0 +1,115 @@
+/* @(#)s_atan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* atan(x)
+ * Method
+ *   1. Reduce x to positive by atan(x) = -atan(-x).
+ *   2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ *      is further reduced to one of the following intervals and the
+ *      arctangent of t is evaluated by the corresponding formula:
+ *
+ *      [0,7/16]      atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ *      [7/16,11/16]  atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ *      [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ *      [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ *      [39/16,INF]   atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double atanhi[] = {
+  4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+  7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+  9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+  1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+static const double atanlo[] = {
+  2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+  3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+  1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+  6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+static const double aT[] = {
+  3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+  1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+  9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+  6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+  4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+  1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+        static const double
+one   = 1.0,
+huge   = 1.0e300;
+
+double
+atan(double x)
+{
+        double w,s1,s2,z;
+        int32_t ix,hx,id;
+
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x44100000) {    /* if |x| >= 2^66 */
+            uint32_t low;
+            GET_LOW_WORD(low,x);
+            if(ix>0x7ff00000||
+                (ix==0x7ff00000&&(low!=0)))
+                return x+x;             /* NaN */
+            if(hx>0) return  atanhi[3]+atanlo[3];
+            else     return -atanhi[3]-atanlo[3];
+        } if (ix < 0x3fdc0000) {        /* |x| < 0.4375 */
+            if (ix < 0x3e200000) {      /* |x| < 2^-29 */
+                if(huge+x>one) return x;        /* raise inexact */
+            }
+            id = -1;
+        } else {
+        x = fabs(x);
+        if (ix < 0x3ff30000) {          /* |x| < 1.1875 */
+            if (ix < 0x3fe60000) {      /* 7/16 <=|x|<11/16 */
+                id = 0; x = (2.0*x-one)/(2.0+x);
+            } else {                    /* 11/16<=|x|< 19/16 */
+                id = 1; x  = (x-one)/(x+one);
+            }
+        } else {
+            if (ix < 0x40038000) {      /* |x| < 2.4375 */
+                id = 2; x  = (x-1.5)/(one+1.5*x);
+            } else {                    /* 2.4375 <= |x| < 2^66 */
+                id = 3; x  = -1.0/x;
+            }
+        }}
+    /* end of argument reduction */
+        z = x*x;
+        w = z*z;
+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+        s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+        s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+        if (id<0) return x - x*(s1+s2);
+        else {
+            z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+            return (hx<0)? -z:z;
+        }
+}
diff --git a/src/math/s_atanf.c b/src/math/s_atanf.c
new file mode 100644
index 00000000..03067e18
--- /dev/null
+++ b/src/math/s_atanf.c
@@ -0,0 +1,95 @@
+/* s_atanf.c -- float version of s_atan.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float atanhi[] = {
+  4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
+  7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
+  9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
+  1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
+};
+
+static const float atanlo[] = {
+  5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
+  3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
+  3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
+  7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
+};
+
+static const float aT[] = {
+  3.3333334327e-01, /* 0x3eaaaaaa */
+ -2.0000000298e-01, /* 0xbe4ccccd */
+  1.4285714924e-01, /* 0x3e124925 */
+ -1.1111110449e-01, /* 0xbde38e38 */
+  9.0908870101e-02, /* 0x3dba2e6e */
+ -7.6918758452e-02, /* 0xbd9d8795 */
+  6.6610731184e-02, /* 0x3d886b35 */
+ -5.8335702866e-02, /* 0xbd6ef16b */
+  4.9768779427e-02, /* 0x3d4bda59 */
+ -3.6531571299e-02, /* 0xbd15a221 */
+  1.6285819933e-02, /* 0x3c8569d7 */
+};
+
+        static const float
+one   = 1.0,
+huge   = 1.0e30;
+
+float
+atanf(float x)
+{
+        float w,s1,s2,z;
+        int32_t ix,hx,id;
+
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x50800000) {    /* if |x| >= 2^34 */
+            if(ix>0x7f800000)
+                return x+x;             /* NaN */
+            if(hx>0) return  atanhi[3]+atanlo[3];
+            else     return -atanhi[3]-atanlo[3];
+        } if (ix < 0x3ee00000) {        /* |x| < 0.4375 */
+            if (ix < 0x31000000) {      /* |x| < 2^-29 */
+                if(huge+x>one) return x;        /* raise inexact */
+            }
+            id = -1;
+        } else {
+        x = fabsf(x);
+        if (ix < 0x3f980000) {          /* |x| < 1.1875 */
+            if (ix < 0x3f300000) {      /* 7/16 <=|x|<11/16 */
+                id = 0; x = ((float)2.0*x-one)/((float)2.0+x);
+            } else {                    /* 11/16<=|x|< 19/16 */
+                id = 1; x  = (x-one)/(x+one);
+            }
+        } else {
+            if (ix < 0x401c0000) {      /* |x| < 2.4375 */
+                id = 2; x  = (x-(float)1.5)/(one+(float)1.5*x);
+            } else {                    /* 2.4375 <= |x| < 2^66 */
+                id = 3; x  = -(float)1.0/x;
+            }
+        }}
+    /* end of argument reduction */
+        z = x*x;
+        w = z*z;
+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+        s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+        s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+        if (id<0) return x - x*(s1+s2);
+        else {
+            z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+            return (hx<0)? -z:z;
+        }
+}
diff --git a/src/math/s_cbrt.c b/src/math/s_cbrt.c
new file mode 100644
index 00000000..8adcb191
--- /dev/null
+++ b/src/math/s_cbrt.c
@@ -0,0 +1,77 @@
+/* @(#)s_cbrt.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+static const uint32_t
+        B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+        B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+
+static const double
+C =  5.42857142857142815906e-01, /* 19/35     = 0x3FE15F15, 0xF15F15F1 */
+D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+E =  1.41428571428571436819e+00, /* 99/70     = 0x3FF6A0EA, 0x0EA0EA0F */
+F =  1.60714285714285720630e+00, /* 45/28     = 0x3FF9B6DB, 0x6DB6DB6E */
+G =  3.57142857142857150787e-01; /* 5/14      = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+double
+cbrt(double x)
+{
+        int32_t hx;
+        double r,s,t=0.0,w;
+        uint32_t sign;
+        uint32_t high,low;
+
+        GET_HIGH_WORD(hx,x);
+        sign=hx&0x80000000;             /* sign= sign(x) */
+        hx  ^=sign;
+        if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+        GET_LOW_WORD(low,x);
+        if((hx|low)==0)
+            return(x);          /* cbrt(0) is itself */
+
+        SET_HIGH_WORD(x,hx);    /* x <- |x| */
+    /* rough cbrt to 5 bits */
+        if(hx<0x00100000)               /* subnormal number */
+          {SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */
+           t*=x; GET_HIGH_WORD(high,t); SET_HIGH_WORD(t,high/3+B2);
+          }
+        else
+          SET_HIGH_WORD(t,hx/3+B1);
+
+
+    /* new cbrt to 23 bits, may be implemented in single precision */
+        r=t*t/x;
+        s=C+r*t;
+        t*=G+F/(s+E+D/s);
+
+    /* chopped to 20 bits and make it larger than cbrt(x) */
+        GET_HIGH_WORD(high,t);
+        INSERT_WORDS(t,high+0x00000001,0);
+
+
+    /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+        s=t*t;          /* t*t is exact */
+        r=x/s;
+        w=t+t;
+        r=(r-t)/(w+r);  /* r-s is exact */
+        t=t+t*r;
+
+    /* retore the sign bit */
+        GET_HIGH_WORD(high,t);
+        SET_HIGH_WORD(t,high|sign);
+        return(t);
+}
diff --git a/src/math/s_cbrtf.c b/src/math/s_cbrtf.c
new file mode 100644
index 00000000..e7b46de7
--- /dev/null
+++ b/src/math/s_cbrtf.c
@@ -0,0 +1,67 @@
+/* s_cbrtf.c -- float version of s_cbrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/* cbrtf(x)
+ * Return cube root of x
+ */
+static const unsigned
+        B1 = 709958130, /* B1 = (84+2/3-0.03306235651)*2**23 */
+        B2 = 642849266; /* B2 = (76+2/3-0.03306235651)*2**23 */
+
+static const float
+C =  5.4285717010e-01, /* 19/35     = 0x3f0af8b0 */
+D = -7.0530611277e-01, /* -864/1225 = 0xbf348ef1 */
+E =  1.4142856598e+00, /* 99/70     = 0x3fb50750 */
+F =  1.6071428061e+00, /* 45/28     = 0x3fcdb6db */
+G =  3.5714286566e-01; /* 5/14      = 0x3eb6db6e */
+
+float
+cbrtf(float x)
+{
+        float r,s,t;
+        int32_t hx;
+        uint32_t sign;
+        uint32_t high;
+
+        GET_FLOAT_WORD(hx,x);
+        sign=hx&0x80000000;             /* sign= sign(x) */
+        hx  ^=sign;
+        if(hx>=0x7f800000) return(x+x); /* cbrt(NaN,INF) is itself */
+        if(hx==0)
+            return(x);          /* cbrt(0) is itself */
+
+        SET_FLOAT_WORD(x,hx);   /* x <- |x| */
+    /* rough cbrt to 5 bits */
+        if(hx<0x00800000)               /* subnormal number */
+          {SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */
+           t*=x; GET_FLOAT_WORD(high,t); SET_FLOAT_WORD(t,high/3+B2);
+          }
+        else
+          SET_FLOAT_WORD(t,hx/3+B1);
+
+
+    /* new cbrt to 23 bits */
+        r=t*t/x;
+        s=C+r*t;
+        t*=G+F/(s+E+D/s);
+
+    /* retore the sign bit */
+        GET_FLOAT_WORD(high,t);
+        SET_FLOAT_WORD(t,high|sign);
+        return(t);
+}
diff --git a/src/math/s_ceil.c b/src/math/s_ceil.c
new file mode 100644
index 00000000..1670cade
--- /dev/null
+++ b/src/math/s_ceil.c
@@ -0,0 +1,68 @@
+/* @(#)s_ceil.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+ceil(double x)
+{
+        int32_t i0,i1,j0;
+        uint32_t i,j;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0<0) {i0=0x80000000;i1=0;}
+                    else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+                }
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                if(huge+x>0.0) {        /* raise inexact flag */
+                    if(i0>0) i0 += (0x00100000)>>j0;
+                    i0 &= (~i); i1=0;
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            if(huge+x>0.0) {            /* raise inexact flag */
+                if(i0>0) {
+                    if(j0==20) i0+=1;
+                    else {
+                        j = i1 + (1<<(52-j0));
+                        if(j<i1) i0+=1; /* got a carry */
+                        i1 = j;
+                    }
+                }
+                i1 &= (~i);
+            }
+        }
+        INSERT_WORDS(x,i0,i1);
+        return x;
+}
diff --git a/src/math/s_ceilf.c b/src/math/s_ceilf.c
new file mode 100644
index 00000000..3615041f
--- /dev/null
+++ b/src/math/s_ceilf.c
@@ -0,0 +1,49 @@
+/* s_ceilf.c -- float version of s_ceil.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+float
+ceilf(float x)
+{
+        int32_t i0,j0;
+        uint32_t i;
+
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0<0) {i0=0x80000000;}
+                    else if(i0!=0) { i0=0x3f800000;}
+                }
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) return x; /* x is integral */
+                if(huge+x>(float)0.0) { /* raise inexact flag */
+                    if(i0>0) i0 += (0x00800000)>>j0;
+                    i0 &= (~i);
+                }
+            }
+        } else {
+            if(j0==0x80) return x+x;    /* inf or NaN */
+            else return x;              /* x is integral */
+        }
+        SET_FLOAT_WORD(x,i0);
+        return x;
+}
diff --git a/src/math/s_copysign.c b/src/math/s_copysign.c
new file mode 100644
index 00000000..59d3877c
--- /dev/null
+++ b/src/math/s_copysign.c
@@ -0,0 +1,30 @@
+/* @(#)s_copysign.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+copysign(double x, double y)
+{
+        uint32_t hx,hy;
+        GET_HIGH_WORD(hx,x);
+        GET_HIGH_WORD(hy,y);
+        SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000));
+        return x;
+}
diff --git a/src/math/s_copysignf.c b/src/math/s_copysignf.c
new file mode 100644
index 00000000..d650e8e5
--- /dev/null
+++ b/src/math/s_copysignf.c
@@ -0,0 +1,33 @@
+/* s_copysignf.c -- float version of s_copysign.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysignf(float x, float y)
+ * copysignf(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+copysignf(float x, float y)
+{
+        uint32_t ix,iy;
+        GET_FLOAT_WORD(ix,x);
+        GET_FLOAT_WORD(iy,y);
+        SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000));
+        return x;
+}
diff --git a/src/math/s_cos.c b/src/math/s_cos.c
new file mode 100644
index 00000000..1893ab13
--- /dev/null
+++ b/src/math/s_cos.c
@@ -0,0 +1,74 @@
+/* @(#)s_cos.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ *      __kernel_sin            ... sine function on [-pi/4,pi/4]
+ *      __kernel_cos            ... cosine function on [-pi/4,pi/4]
+ *      __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *      in [-pi/4 , +pi/4], and let n = k mod 4.
+ *      We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *          0          S           C             T
+ *          1          C          -S            -1/T
+ *          2         -S          -C             T
+ *          3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *      TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+cos(double x)
+{
+        double y[2],z=0.0;
+        int32_t n, ix;
+
+    /* High word of x. */
+        GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+
+    /* cos(Inf or NaN) is NaN */
+        else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_cos(y[0],y[1]);
+                case 1: return -__kernel_sin(y[0],y[1],1);
+                case 2: return -__kernel_cos(y[0],y[1]);
+                default:
+                        return  __kernel_sin(y[0],y[1],1);
+            }
+        }
+}
diff --git a/src/math/s_cosf.c b/src/math/s_cosf.c
new file mode 100644
index 00000000..14b8e98b
--- /dev/null
+++ b/src/math/s_cosf.c
@@ -0,0 +1,47 @@
+/* s_cosf.c -- float version of s_cos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one=1.0;
+
+float
+cosf(float x)
+{
+        float y[2],z=0.0;
+        int32_t n,ix;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
+
+    /* cos(Inf or NaN) is NaN */
+        else if (ix>=0x7f800000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2f(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_cosf(y[0],y[1]);
+                case 1: return -__kernel_sinf(y[0],y[1],1);
+                case 2: return -__kernel_cosf(y[0],y[1]);
+                default:
+                        return  __kernel_sinf(y[0],y[1],1);
+            }
+        }
+}
diff --git a/src/math/s_erf.c b/src/math/s_erf.c
new file mode 100644
index 00000000..e321feea
--- /dev/null
+++ b/src/math/s_erf.c
@@ -0,0 +1,298 @@
+/* @(#)s_erf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ *                           x
+ *                    2      |\
+ *     erf(x)  =  ---------  | exp(-t*t)dt
+ *                 sqrt(pi) \|
+ *                           0
+ *
+ *     erfc(x) =  1-erf(x)
+ *  Note that
+ *              erf(-x) = -erf(x)
+ *              erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ *      1. For |x| in [0, 0.84375]
+ *          erf(x)  = x + x*R(x^2)
+ *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
+ *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
+ *         where R = P/Q where P is an odd poly of degree 8 and
+ *         Q is an odd poly of degree 10.
+ *                                               -57.90
+ *                      | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ *         Remark. The formula is derived by noting
+ *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ *         and that
+ *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ *         is close to one. The interval is chosen because the fix
+ *         point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ *         near 0.6174), and by some experiment, 0.84375 is chosen to
+ *         guarantee the error is less than one ulp for erf.
+ *
+ *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ *         c = 0.84506291151 rounded to single (24 bits)
+ *              erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
+ *              erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
+ *                        1+(c+P1(s)/Q1(s))    if x < 0
+ *              |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ *         Remark: here we use the taylor series expansion at x=1.
+ *              erf(1+s) = erf(1) + s*Poly(s)
+ *                       = 0.845.. + P1(s)/Q1(s)
+ *         That is, we use rational approximation to approximate
+ *                      erf(1+s) - (c = (single)0.84506291151)
+ *         Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ *         where
+ *              P1(s) = degree 6 poly in s
+ *              Q1(s) = degree 6 poly in s
+ *
+ *      3. For x in [1.25,1/0.35(~2.857143)],
+ *              erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ *              erf(x)  = 1 - erfc(x)
+ *         where
+ *              R1(z) = degree 7 poly in z, (z=1/x^2)
+ *              S1(z) = degree 8 poly in z
+ *
+ *      4. For x in [1/0.35,28]
+ *              erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ *                      = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ *                      = 2.0 - tiny            (if x <= -6)
+ *              erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ *              erf(x)  = sign(x)*(1.0 - tiny)
+ *         where
+ *              R2(z) = degree 6 poly in z, (z=1/x^2)
+ *              S2(z) = degree 7 poly in z
+ *
+ *      Note1:
+ *         To compute exp(-x*x-0.5625+R/S), let s be a single
+ *         precision number and s := x; then
+ *              -x*x = -s*s + (s-x)*(s+x)
+ *              exp(-x*x-0.5626+R/S) =
+ *                      exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ *      Note2:
+ *         Here 4 and 5 make use of the asymptotic series
+ *                        exp(-x*x)
+ *              erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ *                        x*sqrt(pi)
+ *         We use rational approximation to approximate
+ *              g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ *         Here is the error bound for R1/S1 and R2/S2
+ *              |R1/S1 - f(x)|  < 2**(-62.57)
+ *              |R2/S2 - f(x)|  < 2**(-61.52)
+ *
+ *      5. For inf > x >= 28
+ *              erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
+ *              erfc(x) = tiny*tiny (raise underflow) if x > 0
+ *                      = 2 - tiny if x<0
+ *
+ *      7. Special case:
+ *              erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
+ *              erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ *              erfc/erf(NaN) is NaN
+ */
+
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+tiny        = 1e-300,
+half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+        /* c = (float)0.84506291151 */
+erx =  8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to  erf on [0,0.84375]
+ */
+efx =  1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8=  1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0  =  1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1  = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2  = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3  = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4  = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1  =  3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2  =  6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3  =  5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4  =  1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5  = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to  erf  in [0.84375,1.25]
+ */
+pa0  = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1  =  4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2  = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3  =  3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4  = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5  =  3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6  = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1  =  1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2  =  5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3  =  7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4  =  1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5  =  1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6  =  1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to  erfc in [1.25,1/0.35]
+ */
+ra0  = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1  = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2  = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3  = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4  = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5  = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6  = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7  = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1  =  1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2  =  1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3  =  4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4  =  6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5  =  4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6  =  1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7  =  6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8  = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to  erfc in [1/.35,28]
+ */
+rb0  = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1  = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2  = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3  = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4  = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5  = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6  = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1  =  3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2  =  3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3  =  1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4  =  3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5  =  2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6  =  4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7  = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+double
+erf(double x)
+{
+        int32_t hx,ix,i;
+        double R,S,P,Q,s,y,z,r;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7ff00000) {            /* erf(nan)=nan */
+            i = ((uint32_t)hx>>31)<<1;
+            return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+        }
+
+        if(ix < 0x3feb0000) {           /* |x|<0.84375 */
+            if(ix < 0x3e300000) {       /* |x|<2**-28 */
+                if (ix < 0x00800000)
+                    return 0.125*(8.0*x+efx8*x);  /*avoid underflow */
+                return x + efx*x;
+            }
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            return x + x*y;
+        }
+        if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabs(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+        }
+        if (ix >= 0x40180000) {         /* inf>|x|>=6 */
+            if(hx>=0) return one-tiny; else return tiny-one;
+        }
+        x = fabs(x);
+        s = one/(x*x);
+        if(ix< 0x4006DB6E) {    /* |x| < 1/0.35 */
+            R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+            S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+        } else {        /* |x| >= 1/0.35 */
+            R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+            S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+        }
+        z  = x;
+        SET_LOW_WORD(z,0);
+        r  =  exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S);
+        if(hx>=0) return one-r/x; else return  r/x-one;
+}
+
+double
+erfc(double x)
+{
+        int32_t hx,ix;
+        double R,S,P,Q,s,y,z,r;
+        GET_HIGH_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7ff00000) {                    /* erfc(nan)=nan */
+                                                /* erfc(+-inf)=0,2 */
+            return (double)(((uint32_t)hx>>31)<<1)+one/x;
+        }
+
+        if(ix < 0x3feb0000) {           /* |x|<0.84375 */
+            if(ix < 0x3c700000)         /* |x|<2**-56 */
+                return one-x;
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            if(hx < 0x3fd00000) {       /* x<1/4 */
+                return one-(x+x*y);
+            } else {
+                r = x*y;
+                r += (x-half);
+                return half - r ;
+            }
+        }
+        if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabs(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) {
+                z  = one-erx; return z - P/Q;
+            } else {
+                z = erx+P/Q; return one+z;
+            }
+        }
+        if (ix < 0x403c0000) {          /* |x|<28 */
+            x = fabs(x);
+            s = one/(x*x);
+            if(ix< 0x4006DB6D) {        /* |x| < 1/.35 ~ 2.857143*/
+                R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+                S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+            } else {                    /* |x| >= 1/.35 ~ 2.857143 */
+                if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+                R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+                S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+            }
+            z  = x;
+            SET_LOW_WORD(z,0);
+            r  =  exp(-z*z-0.5625)*
+                        exp((z-x)*(z+x)+R/S);
+            if(hx>0) return r/x; else return two-r/x;
+        } else {
+            if(hx>0) return tiny*tiny; else return two-tiny;
+        }
+}
diff --git a/src/math/s_erff.c b/src/math/s_erff.c
new file mode 100644
index 00000000..28e2f7b3
--- /dev/null
+++ b/src/math/s_erff.c
@@ -0,0 +1,207 @@
+/* s_erff.c -- float version of s_erf.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+tiny        = 1e-30,
+half=  5.0000000000e-01, /* 0x3F000000 */
+one =  1.0000000000e+00, /* 0x3F800000 */
+two =  2.0000000000e+00, /* 0x40000000 */
+        /* c = (subfloat)0.84506291151 */
+erx =  8.4506291151e-01, /* 0x3f58560b */
+/*
+ * Coefficients for approximation to  erf on [0,0.84375]
+ */
+efx =  1.2837916613e-01, /* 0x3e0375d4 */
+efx8=  1.0270333290e+00, /* 0x3f8375d4 */
+pp0  =  1.2837916613e-01, /* 0x3e0375d4 */
+pp1  = -3.2504209876e-01, /* 0xbea66beb */
+pp2  = -2.8481749818e-02, /* 0xbce9528f */
+pp3  = -5.7702702470e-03, /* 0xbbbd1489 */
+pp4  = -2.3763017452e-05, /* 0xb7c756b1 */
+qq1  =  3.9791721106e-01, /* 0x3ecbbbce */
+qq2  =  6.5022252500e-02, /* 0x3d852a63 */
+qq3  =  5.0813062117e-03, /* 0x3ba68116 */
+qq4  =  1.3249473704e-04, /* 0x390aee49 */
+qq5  = -3.9602282413e-06, /* 0xb684e21a */
+/*
+ * Coefficients for approximation to  erf  in [0.84375,1.25]
+ */
+pa0  = -2.3621185683e-03, /* 0xbb1acdc6 */
+pa1  =  4.1485610604e-01, /* 0x3ed46805 */
+pa2  = -3.7220788002e-01, /* 0xbebe9208 */
+pa3  =  3.1834661961e-01, /* 0x3ea2fe54 */
+pa4  = -1.1089469492e-01, /* 0xbde31cc2 */
+pa5  =  3.5478305072e-02, /* 0x3d1151b3 */
+pa6  = -2.1663755178e-03, /* 0xbb0df9c0 */
+qa1  =  1.0642088205e-01, /* 0x3dd9f331 */
+qa2  =  5.4039794207e-01, /* 0x3f0a5785 */
+qa3  =  7.1828655899e-02, /* 0x3d931ae7 */
+qa4  =  1.2617121637e-01, /* 0x3e013307 */
+qa5  =  1.3637083583e-02, /* 0x3c5f6e13 */
+qa6  =  1.1984500103e-02, /* 0x3c445aa3 */
+/*
+ * Coefficients for approximation to  erfc in [1.25,1/0.35]
+ */
+ra0  = -9.8649440333e-03, /* 0xbc21a093 */
+ra1  = -6.9385856390e-01, /* 0xbf31a0b7 */
+ra2  = -1.0558626175e+01, /* 0xc128f022 */
+ra3  = -6.2375331879e+01, /* 0xc2798057 */
+ra4  = -1.6239666748e+02, /* 0xc322658c */
+ra5  = -1.8460508728e+02, /* 0xc3389ae7 */
+ra6  = -8.1287437439e+01, /* 0xc2a2932b */
+ra7  = -9.8143291473e+00, /* 0xc11d077e */
+sa1  =  1.9651271820e+01, /* 0x419d35ce */
+sa2  =  1.3765776062e+02, /* 0x4309a863 */
+sa3  =  4.3456588745e+02, /* 0x43d9486f */
+sa4  =  6.4538726807e+02, /* 0x442158c9 */
+sa5  =  4.2900814819e+02, /* 0x43d6810b */
+sa6  =  1.0863500214e+02, /* 0x42d9451f */
+sa7  =  6.5702495575e+00, /* 0x40d23f7c */
+sa8  = -6.0424413532e-02, /* 0xbd777f97 */
+/*
+ * Coefficients for approximation to  erfc in [1/.35,28]
+ */
+rb0  = -9.8649431020e-03, /* 0xbc21a092 */
+rb1  = -7.9928326607e-01, /* 0xbf4c9dd4 */
+rb2  = -1.7757955551e+01, /* 0xc18e104b */
+rb3  = -1.6063638306e+02, /* 0xc320a2ea */
+rb4  = -6.3756646729e+02, /* 0xc41f6441 */
+rb5  = -1.0250950928e+03, /* 0xc480230b */
+rb6  = -4.8351919556e+02, /* 0xc3f1c275 */
+sb1  =  3.0338060379e+01, /* 0x41f2b459 */
+sb2  =  3.2579251099e+02, /* 0x43a2e571 */
+sb3  =  1.5367296143e+03, /* 0x44c01759 */
+sb4  =  3.1998581543e+03, /* 0x4547fdbb */
+sb5  =  2.5530502930e+03, /* 0x451f90ce */
+sb6  =  4.7452853394e+02, /* 0x43ed43a7 */
+sb7  = -2.2440952301e+01; /* 0xc1b38712 */
+
+float
+erff(float x)
+{
+        int32_t hx,ix,i;
+        float R,S,P,Q,s,y,z,r;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7f800000) {            /* erf(nan)=nan */
+            i = ((uint32_t)hx>>31)<<1;
+            return (float)(1-i)+one/x;  /* erf(+-inf)=+-1 */
+        }
+
+        if(ix < 0x3f580000) {           /* |x|<0.84375 */
+            if(ix < 0x31800000) {       /* |x|<2**-28 */
+                if (ix < 0x04000000)
+                    /*avoid underflow */
+                    return (float)0.125*((float)8.0*x+efx8*x);
+                return x + efx*x;
+            }
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            return x + x*y;
+        }
+        if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabsf(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+        }
+        if (ix >= 0x40c00000) {         /* inf>|x|>=6 */
+            if(hx>=0) return one-tiny; else return tiny-one;
+        }
+        x = fabsf(x);
+        s = one/(x*x);
+        if(ix< 0x4036DB6E) {    /* |x| < 1/0.35 */
+            R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+            S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+        } else {        /* |x| >= 1/0.35 */
+            R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+            S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+        }
+        GET_FLOAT_WORD(ix,x);
+        SET_FLOAT_WORD(z,ix&0xfffff000);
+        r  =  expf(-z*z-(float)0.5625)*expf((z-x)*(z+x)+R/S);
+        if(hx>=0) return one-r/x; else return  r/x-one;
+}
+
+float
+erfcf(float x)
+{
+        int32_t hx,ix;
+        float R,S,P,Q,s,y,z,r;
+        GET_FLOAT_WORD(hx,x);
+        ix = hx&0x7fffffff;
+        if(ix>=0x7f800000) {                    /* erfc(nan)=nan */
+                                                /* erfc(+-inf)=0,2 */
+            return (float)(((uint32_t)hx>>31)<<1)+one/x;
+        }
+
+        if(ix < 0x3f580000) {           /* |x|<0.84375 */
+            if(ix < 0x23800000)         /* |x|<2**-56 */
+                return one-x;
+            z = x*x;
+            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+            y = r/s;
+            if(hx < 0x3e800000) {       /* x<1/4 */
+                return one-(x+x*y);
+            } else {
+                r = x*y;
+                r += (x-half);
+                return half - r ;
+            }
+        }
+        if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */
+            s = fabsf(x)-one;
+            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+            if(hx>=0) {
+                z  = one-erx; return z - P/Q;
+            } else {
+                z = erx+P/Q; return one+z;
+            }
+        }
+        if (ix < 0x41e00000) {          /* |x|<28 */
+            x = fabsf(x);
+            s = one/(x*x);
+            if(ix< 0x4036DB6D) {        /* |x| < 1/.35 ~ 2.857143*/
+                R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+                                ra5+s*(ra6+s*ra7))))));
+                S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+                                sa5+s*(sa6+s*(sa7+s*sa8)))))));
+            } else {                    /* |x| >= 1/.35 ~ 2.857143 */
+                if(hx<0&&ix>=0x40c00000) return two-tiny;/* x < -6 */
+                R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+                                rb5+s*rb6)))));
+                S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+                                sb5+s*(sb6+s*sb7))))));
+            }
+            GET_FLOAT_WORD(ix,x);
+            SET_FLOAT_WORD(z,ix&0xfffff000);
+            r  =  expf(-z*z-(float)0.5625)*
+                        expf((z-x)*(z+x)+R/S);
+            if(hx>0) return r/x; else return two-r/x;
+        } else {
+            if(hx>0) return tiny*tiny; else return two-tiny;
+        }
+}
diff --git a/src/math/s_expm1.c b/src/math/s_expm1.c
new file mode 100644
index 00000000..6f1f6675
--- /dev/null
+++ b/src/math/s_expm1.c
@@ -0,0 +1,217 @@
+/* @(#)s_expm1.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ *   1. Argument reduction:
+ *      Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658
+ *
+ *      Here a correction term c will be computed to compensate
+ *      the error in r when rounded to a floating-point number.
+ *
+ *   2. Approximating expm1(r) by a special rational function on
+ *      the interval [0,0.34658]:
+ *      Since
+ *          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ *      we define R1(r*r) by
+ *          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ *      That is,
+ *          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ *                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ *                   = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ *      We use a special Reme algorithm on [0,0.347] to generate
+ *      a polynomial of degree 5 in r*r to approximate R1. The
+ *      maximum error of this polynomial approximation is bounded
+ *      by 2**-61. In other words,
+ *          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ *      where   Q1  =  -1.6666666666666567384E-2,
+ *              Q2  =   3.9682539681370365873E-4,
+ *              Q3  =  -9.9206344733435987357E-6,
+ *              Q4  =   2.5051361420808517002E-7,
+ *              Q5  =  -6.2843505682382617102E-9;
+ *      (where z=r*r, and the values of Q1 to Q5 are listed below)
+ *      with error bounded by
+ *          |                  5           |     -61
+ *          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2
+ *          |                              |
+ *
+ *      expm1(r) = exp(r)-1 is then computed by the following
+ *      specific way which minimize the accumulation rounding error:
+ *                             2     3
+ *                            r     r    [ 3 - (R1 + R1*r/2)  ]
+ *            expm1(r) = r + --- + --- * [--------------------]
+ *                            2     2    [ 6 - r*(3 - R1*r/2) ]
+ *
+ *      To compensate the error in the argument reduction, we use
+ *              expm1(r+c) = expm1(r) + c + expm1(r)*c
+ *                         ~ expm1(r) + c + r*c
+ *      Thus c+r*c will be added in as the correction terms for
+ *      expm1(r+c). Now rearrange the term to avoid optimization
+ *      screw up:
+ *                      (      2                                    2 )
+ *                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
+ *       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ *                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
+ *                      (                                             )
+ *
+ *                 = r - E
+ *   3. Scale back to obtain expm1(x):
+ *      From step 1, we have
+ *         expm1(x) = either 2^k*[expm1(r)+1] - 1
+ *                  = or     2^k*[expm1(r) + (1-2^-k)]
+ *   4. Implementation notes:
+ *      (A). To save one multiplication, we scale the coefficient Qi
+ *           to Qi*2^i, and replace z by (x^2)/2.
+ *      (B). To achieve maximum accuracy, we compute expm1(x) by
+ *        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ *        (ii)  if k=0, return r-E
+ *        (iii) if k=-1, return 0.5*(r-E)-0.5
+ *        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ *                     else          return  1.0+2.0*(r-E);
+ *        (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ *        (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ *        (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ *      expm1(INF) is INF, expm1(NaN) is NaN;
+ *      expm1(-INF) is -1, and
+ *      for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *      For IEEE double
+ *          if x >  7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+one             = 1.0,
+huge            = 1.0e+300,
+tiny            = 1.0e-300,
+o_threshold     = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi          = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo          = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2          = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+        /* scaled coefficients related to expm1 */
+Q1  =  -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2  =   1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3  =  -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4  =   4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5  =  -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+double
+expm1(double x)
+{
+        double y,hi,lo,c=0.0,t,e,hxs,hfx,r1;
+        int32_t k,xsb;
+        uint32_t hx;
+
+        GET_HIGH_WORD(hx,x);
+        xsb = hx&0x80000000;            /* sign bit of x */
+        if(xsb==0) y=x; else y= -x;     /* y = |x| */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out huge and non-finite argument */
+        if(hx >= 0x4043687A) {                  /* if |x|>=56*ln2 */
+            if(hx >= 0x40862E42) {              /* if |x|>=709.78... */
+                if(hx>=0x7ff00000) {
+                    uint32_t low;
+                    GET_LOW_WORD(low,x);
+                    if(((hx&0xfffff)|low)!=0)
+                         return x+x;     /* NaN */
+                    else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+                }
+                if(x > o_threshold) return huge*huge; /* overflow */
+            }
+            if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+                if(x+tiny<0.0)          /* raise inexact */
+                return tiny-one;        /* return -1 */
+            }
+        }
+
+    /* argument reduction */
+        if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+            if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                if(xsb==0)
+                    {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;}
+                else
+                    {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;}
+            } else {
+                k  = invln2*x+((xsb==0)?0.5:-0.5);
+                t  = k;
+                hi = x - t*ln2_hi;      /* t*ln2_hi is exact here */
+                lo = t*ln2_lo;
+            }
+            x  = hi - lo;
+            c  = (hi-x)-lo;
+        }
+        else if(hx < 0x3c900000) {      /* when |x|<2**-54, return x */
+            t = huge+x; /* return x with inexact flags when x!=0 */
+            return x - (t-(huge+x));
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        hfx = 0.5*x;
+        hxs = x*hfx;
+        r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+        t  = 3.0-r1*hfx;
+        e  = hxs*((r1-t)/(6.0 - x*t));
+        if(k==0) return x - (x*e-hxs);          /* c is 0 */
+        else {
+            e  = (x*(e-c)-c);
+            e -= hxs;
+            if(k== -1) return 0.5*(x-e)-0.5;
+            if(k==1) {
+                if(x < -0.25) return -2.0*(e-(x+0.5));
+                else          return  one+2.0*(x-e);
+            }
+            if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */
+                uint32_t high;
+                y = one-(e-x);
+                GET_HIGH_WORD(high,y);
+                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */
+                return y-one;
+            }
+            t = one;
+            if(k<20) {
+                uint32_t high;
+                SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k));  /* t=1-2^-k */
+                y = t-(e-x);
+                GET_HIGH_WORD(high,y);
+                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */
+           } else {
+                uint32_t high;
+                SET_HIGH_WORD(t,((0x3ff-k)<<20));       /* 2^-k */
+                y = x-(e+t);
+                y += one;
+                GET_HIGH_WORD(high,y);
+                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */
+            }
+        }
+        return y;
+}
diff --git a/src/math/s_expm1f.c b/src/math/s_expm1f.c
new file mode 100644
index 00000000..b22cf0f9
--- /dev/null
+++ b/src/math/s_expm1f.c
@@ -0,0 +1,122 @@
+/* s_expm1f.c -- float version of s_expm1.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+one             = 1.0,
+huge            = 1.0e+30,
+tiny            = 1.0e-30,
+o_threshold     = 8.8721679688e+01,/* 0x42b17180 */
+ln2_hi          = 6.9313812256e-01,/* 0x3f317180 */
+ln2_lo          = 9.0580006145e-06,/* 0x3717f7d1 */
+invln2          = 1.4426950216e+00,/* 0x3fb8aa3b */
+        /* scaled coefficients related to expm1 */
+Q1  =  -3.3333335072e-02, /* 0xbd088889 */
+Q2  =   1.5873016091e-03, /* 0x3ad00d01 */
+Q3  =  -7.9365076090e-05, /* 0xb8a670cd */
+Q4  =   4.0082177293e-06, /* 0x36867e54 */
+Q5  =  -2.0109921195e-07; /* 0xb457edbb */
+
+float
+expm1f(float x)
+{
+        float y,hi,lo,c=0.0,t,e,hxs,hfx,r1;
+        int32_t k,xsb;
+        uint32_t hx;
+
+        GET_FLOAT_WORD(hx,x);
+        xsb = hx&0x80000000;            /* sign bit of x */
+        if(xsb==0) y=x; else y= -x;     /* y = |x| */
+        hx &= 0x7fffffff;               /* high word of |x| */
+
+    /* filter out huge and non-finite argument */
+        if(hx >= 0x4195b844) {                  /* if |x|>=27*ln2 */
+            if(hx >= 0x42b17218) {              /* if |x|>=88.721... */
+                if(hx>0x7f800000)
+                    return x+x;          /* NaN */
+                if(hx==0x7f800000)
+                    return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+                if(x > o_threshold) return huge*huge; /* overflow */
+            }
+            if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */
+                if(x+tiny<(float)0.0)   /* raise inexact */
+                return tiny-one;        /* return -1 */
+            }
+        }
+
+    /* argument reduction */
+        if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */
+            if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */
+                if(xsb==0)
+                    {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;}
+                else
+                    {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;}
+            } else {
+                k  = invln2*x+((xsb==0)?(float)0.5:(float)-0.5);
+                t  = k;
+                hi = x - t*ln2_hi;      /* t*ln2_hi is exact here */
+                lo = t*ln2_lo;
+            }
+            x  = hi - lo;
+            c  = (hi-x)-lo;
+        }
+        else if(hx < 0x33000000) {      /* when |x|<2**-25, return x */
+            t = huge+x; /* return x with inexact flags when x!=0 */
+            return x - (t-(huge+x));
+        }
+        else k = 0;
+
+    /* x is now in primary range */
+        hfx = (float)0.5*x;
+        hxs = x*hfx;
+        r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+        t  = (float)3.0-r1*hfx;
+        e  = hxs*((r1-t)/((float)6.0 - x*t));
+        if(k==0) return x - (x*e-hxs);          /* c is 0 */
+        else {
+            e  = (x*(e-c)-c);
+            e -= hxs;
+            if(k== -1) return (float)0.5*(x-e)-(float)0.5;
+            if(k==1) {
+                if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5));
+                else          return  one+(float)2.0*(x-e);
+            }
+            if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */
+                int32_t i;
+                y = one-(e-x);
+                GET_FLOAT_WORD(i,y);
+                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */
+                return y-one;
+            }
+            t = one;
+            if(k<23) {
+                int32_t i;
+                SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */
+                y = t-(e-x);
+                GET_FLOAT_WORD(i,y);
+                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */
+           } else {
+                int32_t i;
+                SET_FLOAT_WORD(t,((0x7f-k)<<23));       /* 2^-k */
+                y = x-(e+t);
+                y += one;
+                GET_FLOAT_WORD(i,y);
+                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */
+            }
+        }
+        return y;
+}
diff --git a/src/math/s_fabs.c b/src/math/s_fabs.c
new file mode 100644
index 00000000..74433250
--- /dev/null
+++ b/src/math/s_fabs.c
@@ -0,0 +1,27 @@
+/* @(#)s_fabs.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+fabs(double x)
+{
+        uint32_t high;
+        GET_HIGH_WORD(high,x);
+        SET_HIGH_WORD(x,high&0x7fffffff);
+        return x;
+}
diff --git a/src/math/s_fabsf.c b/src/math/s_fabsf.c
new file mode 100644
index 00000000..655d57d8
--- /dev/null
+++ b/src/math/s_fabsf.c
@@ -0,0 +1,30 @@
+/* s_fabsf.c -- float version of s_fabs.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabsf(x) returns the absolute value of x.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+fabsf(float x)
+{
+        uint32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        SET_FLOAT_WORD(x,ix&0x7fffffff);
+        return x;
+}
diff --git a/src/math/s_floor.c b/src/math/s_floor.c
new file mode 100644
index 00000000..273cf6f4
--- /dev/null
+++ b/src/math/s_floor.c
@@ -0,0 +1,69 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to floor(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+floor(double x)
+{
+        int32_t i0,i1,j0;
+        uint32_t i,j;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0>=0) {i0=i1=0;}
+                    else if(((i0&0x7fffffff)|i1)!=0)
+                        { i0=0xbff00000;i1=0;}
+                }
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                if(huge+x>0.0) {        /* raise inexact flag */
+                    if(i0<0) i0 += (0x00100000)>>j0;
+                    i0 &= (~i); i1=0;
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            if(huge+x>0.0) {            /* raise inexact flag */
+                if(i0<0) {
+                    if(j0==20) i0+=1;
+                    else {
+                        j = i1+(1<<(52-j0));
+                        if(j<i1) i0 +=1 ;       /* got a carry */
+                        i1=j;
+                    }
+                }
+                i1 &= (~i);
+            }
+        }
+        INSERT_WORDS(x,i0,i1);
+        return x;
+}
diff --git a/src/math/s_floorf.c b/src/math/s_floorf.c
new file mode 100644
index 00000000..1164decc
--- /dev/null
+++ b/src/math/s_floorf.c
@@ -0,0 +1,58 @@
+/* s_floorf.c -- float version of s_floor.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floorf(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to floorf(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float huge = 1.0e30;
+
+float
+floorf(float x)
+{
+        int32_t i0,j0;
+        uint32_t i;
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+                    if(i0>=0) {i0=0;}
+                    else if((i0&0x7fffffff)!=0)
+                        { i0=0xbf800000;}
+                }
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) return x; /* x is integral */
+                if(huge+x>(float)0.0) { /* raise inexact flag */
+                    if(i0<0) i0 += (0x00800000)>>j0;
+                    i0 &= (~i);
+                }
+            }
+        } else {
+            if(j0==0x80) return x+x;    /* inf or NaN */
+            else return x;              /* x is integral */
+        }
+        SET_FLOAT_WORD(x,i0);
+        return x;
+}
diff --git a/src/math/s_ilogb.c b/src/math/s_ilogb.c
new file mode 100644
index 00000000..f1ac498a
--- /dev/null
+++ b/src/math/s_ilogb.c
@@ -0,0 +1,45 @@
+/* @(#)s_ilogb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = FP_ILOGB0
+ * ilogb(NaN) = FP_ILOGBNAN (no signal is raised)
+ * ilogb(inf) = INT_MAX (no signal is raised)
+ */
+
+#include <limits.h>
+
+#include <math.h>
+#include "math_private.h"
+
+int ilogb(double x)
+{
+        int32_t hx,lx,ix;
+
+        EXTRACT_WORDS(hx,lx,x);
+        hx &= 0x7fffffff;
+        if(hx<0x00100000) {
+            if((hx|lx)==0)
+                return FP_ILOGB0;
+            else                        /* subnormal x */
+                if(hx==0) {
+                    for (ix = -1043; lx>0; lx<<=1) ix -=1;
+                } else {
+                    for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+                }
+            return ix;
+        }
+        else if (hx<0x7ff00000) return (hx>>20)-1023;
+        else if (hx>0x7ff00000 || lx!=0) return FP_ILOGBNAN;
+        else return INT_MAX;
+}
diff --git a/src/math/s_ilogbf.c b/src/math/s_ilogbf.c
new file mode 100644
index 00000000..30359fef
--- /dev/null
+++ b/src/math/s_ilogbf.c
@@ -0,0 +1,37 @@
+/* s_ilogbf.c -- float version of s_ilogb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <limits.h>
+
+#include <math.h>
+#include "math_private.h"
+
+int ilogbf(float x)
+{
+        int32_t hx,ix;
+
+        GET_FLOAT_WORD(hx,x);
+        hx &= 0x7fffffff;
+        if(hx<0x00800000) {
+            if(hx==0)
+                return FP_ILOGB0;
+            else                        /* subnormal x */
+                for (ix = -126,hx<<=8; hx>0; hx<<=1) ix -=1;
+            return ix;
+        }
+        else if (hx<0x7f800000) return (hx>>23)-127;
+        else if (hx>0x7f800000) return FP_ILOGBNAN;
+        else return INT_MAX;
+}
diff --git a/src/math/s_ldexp.c b/src/math/s_ldexp.c
new file mode 100644
index 00000000..f4d1cd6a
--- /dev/null
+++ b/src/math/s_ldexp.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+double ldexp(double x, int n)
+{
+	return scalbn(x, n);
+}
diff --git a/src/math/s_ldexpf.c b/src/math/s_ldexpf.c
new file mode 100644
index 00000000..3bad5f39
--- /dev/null
+++ b/src/math/s_ldexpf.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+float ldexpf(float x, int n)
+{
+	return scalbnf(x, n);
+}
diff --git a/src/math/s_llrint.c b/src/math/s_llrint.c
new file mode 100644
index 00000000..2b1e00d0
--- /dev/null
+++ b/src/math/s_llrint.c
@@ -0,0 +1,8 @@
+#include <math.h>
+
+// FIXME: incorrect exception behavior
+
+long long llrint(double x)
+{
+	return rint(x);
+}
diff --git a/src/math/s_log1p.c b/src/math/s_log1p.c
new file mode 100644
index 00000000..886d5ab1
--- /dev/null
+++ b/src/math/s_log1p.c
@@ -0,0 +1,157 @@
+/* @(#)s_log1p.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double log1p(double x)
+ *
+ * Method :
+ *   1. Argument Reduction: find k and f such that
+ *                      1+x = 2^k * (1+f),
+ *         where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *      Note. If k=0, then f=x is exact. However, if k!=0, then f
+ *      may not be representable exactly. In that case, a correction
+ *      term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ *      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ *      and add back the correction term c/u.
+ *      (Note: when x > 2**53, one can simply return log(x))
+ *
+ *   2. Approximation of log1p(f).
+ *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *               = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *               = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate
+ *      a polynomial of degree 14 to approximate R The maximum error
+ *      of this polynomial approximation is bounded by 2**-58.45. In
+ *      other words,
+ *                      2      4      6      8      10      12      14
+ *          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
+ *      (the values of Lp1 to Lp7 are listed in the program)
+ *      and
+ *          |      2          14          |     -58.45
+ *          | Lp1*s +...+Lp7*s    -  R(z) | <= 2
+ *          |                             |
+ *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *      In order to guarantee error in log below 1ulp, we compute log
+ *      by
+ *              log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ *      3. Finally, log1p(x) = k*ln2 + log1p(f).
+ *                           = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *         Here ln2 is split into two floating point number:
+ *                      ln2_hi + ln2_lo,
+ *         where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *      log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ *      log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ *      log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *      according to an error analysis, the error is always less than
+ *      1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ *       algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ *              u = 1+x;
+ *              if(u==1.0) return x ; else
+ *                         return log(u)*(x/(u-1.0));
+ *
+ *       See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static const double zero = 0.0;
+
+double
+log1p(double x)
+{
+        double hfsq,f=0,c=0,s,z,R,u;
+        int32_t k,hx,hu=0,ax;
+
+        GET_HIGH_WORD(hx,x);
+        ax = hx&0x7fffffff;
+
+        k = 1;
+        if (hx < 0x3FDA827A) {                  /* x < 0.41422  */
+            if(ax>=0x3ff00000) {                /* x <= -1.0 */
+                if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+                else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */
+            }
+            if(ax<0x3e200000) {                 /* |x| < 2**-29 */
+                if(two54+x>zero                 /* raise inexact */
+                    &&ax<0x3c900000)            /* |x| < 2**-54 */
+                    return x;
+                else
+                    return x - x*x*0.5;
+            }
+            if(hx>0||hx<=((int32_t)0xbfd2bec3)) {
+                k=0;f=x;hu=1;}  /* -0.2929<x<0.41422 */
+        }
+        if (hx >= 0x7ff00000) return x+x;
+        if(k!=0) {
+            if(hx<0x43400000) {
+                u  = 1.0+x;
+                GET_HIGH_WORD(hu,u);
+                k  = (hu>>20)-1023;
+                c  = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+                c /= u;
+            } else {
+                u  = x;
+                GET_HIGH_WORD(hu,u);
+                k  = (hu>>20)-1023;
+                c  = 0;
+            }
+            hu &= 0x000fffff;
+            if(hu<0x6a09e) {
+                SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */
+            } else {
+                k += 1;
+                SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */
+                hu = (0x00100000-hu)>>2;
+            }
+            f = u-1.0;
+        }
+        hfsq=0.5*f*f;
+        if(hu==0) {     /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;
+                          else {c += k*ln2_lo; return k*ln2_hi+c;} }
+            R = hfsq*(1.0-0.66666666666666666*f);
+            if(k==0) return f-R; else
+                     return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+        }
+        s = f/(2.0+f);
+        z = s*s;
+        R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+        if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                 return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/src/math/s_log1pf.c b/src/math/s_log1pf.c
new file mode 100644
index 00000000..dcdd6bb3
--- /dev/null
+++ b/src/math/s_log1pf.c
@@ -0,0 +1,96 @@
+/* s_log1pf.c -- float version of s_log1p.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+ln2_hi =   6.9313812256e-01,    /* 0x3f317180 */
+ln2_lo =   9.0580006145e-06,    /* 0x3717f7d1 */
+two25 =    3.355443200e+07,     /* 0x4c000000 */
+Lp1 = 6.6666668653e-01, /* 3F2AAAAB */
+Lp2 = 4.0000000596e-01, /* 3ECCCCCD */
+Lp3 = 2.8571429849e-01, /* 3E924925 */
+Lp4 = 2.2222198546e-01, /* 3E638E29 */
+Lp5 = 1.8183572590e-01, /* 3E3A3325 */
+Lp6 = 1.5313838422e-01, /* 3E1CD04F */
+Lp7 = 1.4798198640e-01; /* 3E178897 */
+
+static const float zero = 0.0;
+
+float
+log1pf(float x)
+{
+        float hfsq,f=0,c=0,s,z,R,u;
+        int32_t k,hx,hu=0,ax;
+
+        GET_FLOAT_WORD(hx,x);
+        ax = hx&0x7fffffff;
+
+        k = 1;
+        if (hx < 0x3ed413d7) {                  /* x < 0.41422  */
+            if(ax>=0x3f800000) {                /* x <= -1.0 */
+                if(x==(float)-1.0) return -two25/zero; /* log1p(-1)=+inf */
+                else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */
+            }
+            if(ax<0x31000000) {                 /* |x| < 2**-29 */
+                if(two25+x>zero                 /* raise inexact */
+                    &&ax<0x24800000)            /* |x| < 2**-54 */
+                    return x;
+                else
+                    return x - x*x*(float)0.5;
+            }
+            if(hx>0||hx<=((int32_t)0xbe95f61f)) {
+                k=0;f=x;hu=1;}  /* -0.2929<x<0.41422 */
+        }
+        if (hx >= 0x7f800000) return x+x;
+        if(k!=0) {
+            if(hx<0x5a000000) {
+                u  = (float)1.0+x;
+                GET_FLOAT_WORD(hu,u);
+                k  = (hu>>23)-127;
+                /* correction term */
+                c  = (k>0)? (float)1.0-(u-x):x-(u-(float)1.0);
+                c /= u;
+            } else {
+                u  = x;
+                GET_FLOAT_WORD(hu,u);
+                k  = (hu>>23)-127;
+                c  = 0;
+            }
+            hu &= 0x007fffff;
+            if(hu<0x3504f7) {
+                SET_FLOAT_WORD(u,hu|0x3f800000);/* normalize u */
+            } else {
+                k += 1;
+                SET_FLOAT_WORD(u,hu|0x3f000000);        /* normalize u/2 */
+                hu = (0x00800000-hu)>>2;
+            }
+            f = u-(float)1.0;
+        }
+        hfsq=(float)0.5*f*f;
+        if(hu==0) {     /* |f| < 2**-20 */
+            if(f==zero) { if(k==0) return zero;
+                          else {c += k*ln2_lo; return k*ln2_hi+c;} }
+            R = hfsq*((float)1.0-(float)0.66666666666666666*f);
+            if(k==0) return f-R; else
+                     return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+        }
+        s = f/((float)2.0+f);
+        z = s*s;
+        R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+        if(k==0) return f-(hfsq-s*(hfsq+R)); else
+                 return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
diff --git a/src/math/s_logb.c b/src/math/s_logb.c
new file mode 100644
index 00000000..be399c77
--- /dev/null
+++ b/src/math/s_logb.c
@@ -0,0 +1,34 @@
+/* @(#)s_logb.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * double logb(x)
+ * IEEE 754 logb. Included to pass IEEE test suite. Not recommend.
+ * Use ilogb instead.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+logb(double x)
+{
+        int32_t lx,ix;
+        EXTRACT_WORDS(ix,lx,x);
+        ix &= 0x7fffffff;                       /* high |x| */
+        if((ix|lx)==0) return -1.0/fabs(x);
+        if(ix>=0x7ff00000) return x*x;
+        if((ix>>=20)==0)                        /* IEEE 754 logb */
+                return -1022.0;
+        else
+                return (double) (ix-1023);
+}
diff --git a/src/math/s_logbf.c b/src/math/s_logbf.c
new file mode 100644
index 00000000..747664d3
--- /dev/null
+++ b/src/math/s_logbf.c
@@ -0,0 +1,31 @@
+/* s_logbf.c -- float version of s_logb.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+logbf(float x)
+{
+        int32_t ix;
+        GET_FLOAT_WORD(ix,x);
+        ix &= 0x7fffffff;                       /* high |x| */
+        if(ix==0) return (float)-1.0/fabsf(x);
+        if(ix>=0x7f800000) return x*x;
+        if((ix>>=23)==0)                        /* IEEE 754 logb */
+                return -126.0;
+        else
+                return (float) (ix-127);
+}
diff --git a/src/math/s_lrint.c b/src/math/s_lrint.c
new file mode 100644
index 00000000..da8e1989
--- /dev/null
+++ b/src/math/s_lrint.c
@@ -0,0 +1,8 @@
+#include <math.h>
+
+// FIXME: incorrect exception behavior
+
+long lrint(double x)
+{
+	return rint(x);
+}
diff --git a/src/math/s_lrintf.c b/src/math/s_lrintf.c
new file mode 100644
index 00000000..d0b469b9
--- /dev/null
+++ b/src/math/s_lrintf.c
@@ -0,0 +1,8 @@
+#include <math.h>
+
+// FIXME: incorrect exception behavior
+
+long lrintf(float x)
+{
+	return rintf(x);
+}
diff --git a/src/math/s_modf.c b/src/math/s_modf.c
new file mode 100644
index 00000000..a5528d6b
--- /dev/null
+++ b/src/math/s_modf.c
@@ -0,0 +1,71 @@
+/* @(#)s_modf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ *      Bit twiddling.
+ *
+ * Exception:
+ *      No exception.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one = 1.0;
+
+double
+modf(double x, double *iptr)
+{
+        int32_t i0,i1,j0;
+        uint32_t i;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;    /* exponent of x */
+        if(j0<20) {                     /* integer part in high x */
+            if(j0<0) {                  /* |x|<1 */
+                INSERT_WORDS(*iptr,i0&0x80000000,0);    /* *iptr = +-0 */
+                return x;
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) {            /* x is integral */
+                    uint32_t high;
+                    *iptr = x;
+                    GET_HIGH_WORD(high,x);
+                    INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */
+                    return x;
+                } else {
+                    INSERT_WORDS(*iptr,i0&(~i),0);
+                    return x - *iptr;
+                }
+            }
+        } else if (j0>51) {             /* no fraction part */
+            uint32_t high;
+            *iptr = x*one;
+            GET_HIGH_WORD(high,x);
+            INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */
+            return x;
+        } else {                        /* fraction part in low x */
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) {             /* x is integral */
+                uint32_t high;
+                *iptr = x;
+                GET_HIGH_WORD(high,x);
+                INSERT_WORDS(x,high&0x80000000,0);      /* return +-0 */
+                return x;
+            } else {
+                INSERT_WORDS(*iptr,i0,i1&(~i));
+                return x - *iptr;
+            }
+        }
+}
diff --git a/src/math/s_modff.c b/src/math/s_modff.c
new file mode 100644
index 00000000..de4dfd25
--- /dev/null
+++ b/src/math/s_modff.c
@@ -0,0 +1,52 @@
+/* s_modff.c -- float version of s_modf.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one = 1.0;
+
+float
+modff(float x, float *iptr)
+{
+        int32_t i0,j0;
+        uint32_t i;
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;      /* exponent of x */
+        if(j0<23) {                     /* integer part in x */
+            if(j0<0) {                  /* |x|<1 */
+                SET_FLOAT_WORD(*iptr,i0&0x80000000);    /* *iptr = +-0 */
+                return x;
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) {                 /* x is integral */
+                    uint32_t ix;
+                    *iptr = x;
+                    GET_FLOAT_WORD(ix,x);
+                    SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */
+                    return x;
+                } else {
+                    SET_FLOAT_WORD(*iptr,i0&(~i));
+                    return x - *iptr;
+                }
+            }
+        } else {                        /* no fraction part */
+            uint32_t ix;
+            *iptr = x*one;
+            GET_FLOAT_WORD(ix,x);
+            SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */
+            return x;
+        }
+}
diff --git a/src/math/s_nextafter.c b/src/math/s_nextafter.c
new file mode 100644
index 00000000..46d298ec
--- /dev/null
+++ b/src/math/s_nextafter.c
@@ -0,0 +1,72 @@
+/* @(#)s_nextafter.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ *      nextafter(x,y)
+ *      return the next machine floating-point number of x in the
+ *      direction toward y.
+ *   Special cases:
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+nextafter(double x, double y)
+{
+        volatile double t;
+        int32_t hx,hy,ix,iy;
+        uint32_t lx,ly;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        ix = hx&0x7fffffff;             /* |x| */
+        iy = hy&0x7fffffff;             /* |y| */
+
+        if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
+           ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     /* y is nan */
+           return x+y;
+        if(x==y) return y;              /* x=y, return y */
+        if((ix|lx)==0) {                        /* x == 0 */
+            INSERT_WORDS(x,hy&0x80000000,1);    /* return +-minsubnormal */
+            t = x*x;
+            if(t==x) return t; else return x;   /* raise underflow flag */
+        }
+        if(hx>=0) {                             /* x > 0 */
+            if(hx>hy||((hx==hy)&&(lx>ly))) {    /* x > y, x -= ulp */
+                if(lx==0) hx -= 1;
+                lx -= 1;
+            } else {                            /* x < y, x += ulp */
+                lx += 1;
+                if(lx==0) hx += 1;
+            }
+        } else {                                /* x < 0 */
+            if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+                if(lx==0) hx -= 1;
+                lx -= 1;
+            } else {                            /* x > y, x += ulp */
+                lx += 1;
+                if(lx==0) hx += 1;
+            }
+        }
+        hy = hx&0x7ff00000;
+        if(hy>=0x7ff00000) return x+x;  /* overflow  */
+        if(hy<0x00100000) {             /* underflow */
+            t = x*x;
+            if(t!=x) {          /* raise underflow flag */
+                INSERT_WORDS(y,hx,lx);
+                return y;
+            }
+        }
+        INSERT_WORDS(x,hx,lx);
+        return x;
+}
diff --git a/src/math/s_nextafterf.c b/src/math/s_nextafterf.c
new file mode 100644
index 00000000..7ce08838
--- /dev/null
+++ b/src/math/s_nextafterf.c
@@ -0,0 +1,63 @@
+/* s_nextafterf.c -- float version of s_nextafter.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+nextafterf(float x, float y)
+{
+        volatile float t;
+        int32_t hx,hy,ix,iy;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        ix = hx&0x7fffffff;             /* |x| */
+        iy = hy&0x7fffffff;             /* |y| */
+
+        if((ix>0x7f800000) ||   /* x is nan */
+           (iy>0x7f800000))     /* y is nan */
+           return x+y;
+        if(x==y) return y;              /* x=y, return y */
+        if(ix==0) {                             /* x == 0 */
+            SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */
+            t = x*x;
+            if(t==x) return t; else return x;   /* raise underflow flag */
+        }
+        if(hx>=0) {                             /* x > 0 */
+            if(hx>hy) {                         /* x > y, x -= ulp */
+                hx -= 1;
+            } else {                            /* x < y, x += ulp */
+                hx += 1;
+            }
+        } else {                                /* x < 0 */
+            if(hy>=0||hx>hy){                   /* x < y, x -= ulp */
+                hx -= 1;
+            } else {                            /* x > y, x += ulp */
+                hx += 1;
+            }
+        }
+        hy = hx&0x7f800000;
+        if(hy>=0x7f800000) return x+x;  /* overflow  */
+        if(hy<0x00800000) {             /* underflow */
+            t = x*x;
+            if(t!=x) {          /* raise underflow flag */
+                SET_FLOAT_WORD(y,hx);
+                return y;
+            }
+        }
+        SET_FLOAT_WORD(x,hx);
+        return x;
+}
diff --git a/src/math/s_remquo.c b/src/math/s_remquo.c
new file mode 100644
index 00000000..1a2992d6
--- /dev/null
+++ b/src/math/s_remquo.c
@@ -0,0 +1,149 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+double
+remquo(double x, double y, int *quo)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+        uint32_t lx,ly,lz,q,sxy;
+
+        EXTRACT_WORDS(hx,lx,x);
+        EXTRACT_WORDS(hy,ly,y);
+        sxy = (hx ^ hy) & 0x80000000;
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */
+          ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */
+            return (x*y)/(x*y);
+        if(hx<=hy) {
+            if((hx<hy)||(lx<ly)) {
+                q = 0;
+                goto fixup;     /* |x|<|y| return x or x-y */
+            }
+            if(lx==ly) {
+                *quo = 1;
+                return Zero[(uint32_t)sx>>31]; /* |x|=|y| return x*0*/
+            }
+        }
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00100000) {     /* subnormal x */
+            if(hx==0) {
+                for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+            } else {
+                for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+            }
+        } else ix = (hx>>20)-1023;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00100000) {     /* subnormal y */
+            if(hy==0) {
+                for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+            } else {
+                for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+            }
+        } else iy = (hy>>20)-1023;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -1022) 
+            hx = 0x00100000|(0x000fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -1022-ix;
+            if(n<=31) {
+                hx = (hx<<n)|(lx>>(32-n));
+                lx <<= n;
+            } else {
+                hx = lx<<(n-32);
+                lx = 0;
+            }
+        }
+        if(iy >= -1022) 
+            hy = 0x00100000|(0x000fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -1022-iy;
+            if(n<=31) {
+                hy = (hy<<n)|(ly>>(32-n));
+                ly <<= n;
+            } else {
+                hy = ly<<(n-32);
+                ly = 0;
+            }
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        q = 0;
+        while(n--) {
+            hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+            if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+            else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;}
+            q <<= 1;
+        }
+        hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+        if(hz>=0) {hx=hz;lx=lz;q++;}
+
+    /* convert back to floating value and restore the sign */
+        if((hx|lx)==0) {                        /* return sign(x)*0 */
+            *quo = (sxy ? -q : q);
+            return Zero[(uint32_t)sx>>31];
+        }
+        while(hx<0x00100000) {          /* normalize x */
+            hx = hx+hx+(lx>>31); lx = lx+lx;
+            iy -= 1;
+        }
+        if(iy>= -1022) {        /* normalize output */
+            hx = ((hx-0x00100000)|((iy+1023)<<20));
+        } else {                /* subnormal output */
+            n = -1022 - iy;
+            if(n<=20) {
+                lx = (lx>>n)|((uint32_t)hx<<(32-n));
+                hx >>= n;
+            } else if (n<=31) {
+                lx = (hx<<(32-n))|(lx>>n); hx = sx;
+            } else {
+                lx = hx>>(n-32); hx = sx;
+            }
+        }
+fixup:
+        INSERT_WORDS(x,hx,lx);
+        y = fabs(y);
+        if (y < 0x1p-1021) {
+            if (x+x>y || (x+x==y && (q & 1))) {
+                q++;
+                x-=y;
+            }
+        } else if (x>0.5*y || (x==0.5*y && (q & 1))) {
+            q++;
+            x-=y;
+        }
+        GET_HIGH_WORD(hx,x);
+        SET_HIGH_WORD(x,hx^sx);
+        q &= 0x7fffffff;
+        *quo = (sxy ? -q : q);
+        return x;
+}
diff --git a/src/math/s_remquof.c b/src/math/s_remquof.c
new file mode 100644
index 00000000..be2a561a
--- /dev/null
+++ b/src/math/s_remquof.c
@@ -0,0 +1,118 @@
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*-
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float Zero[] = {0.0, -0.0,};
+
+/*
+ * Return the IEEE remainder and set *quo to the last n bits of the
+ * quotient, rounded to the nearest integer.  We choose n=31 because
+ * we wind up computing all the integer bits of the quotient anyway as
+ * a side-effect of computing the remainder by the shift and subtract
+ * method.  In practice, this is far more bits than are needed to use
+ * remquo in reduction algorithms.
+ */
+float
+remquof(float x, float y, int *quo)
+{
+        int32_t n,hx,hy,hz,ix,iy,sx,i;
+        uint32_t q,sxy;
+
+        GET_FLOAT_WORD(hx,x);
+        GET_FLOAT_WORD(hy,y);
+        sxy = (hx ^ hy) & 0x80000000;
+        sx = hx&0x80000000;             /* sign of x */
+        hx ^=sx;                /* |x| */
+        hy &= 0x7fffffff;       /* |y| */
+
+    /* purge off exception values */
+        if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */
+            return (x*y)/(x*y);
+        if(hx<hy) {
+            q = 0;
+            goto fixup; /* |x|<|y| return x or x-y */
+        } else if(hx==hy) {
+            *quo = 1;
+            return Zero[(uint32_t)sx>>31];     /* |x|=|y| return x*0*/
+        }
+
+    /* determine ix = ilogb(x) */
+        if(hx<0x00800000) {     /* subnormal x */
+            for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
+        } else ix = (hx>>23)-127;
+
+    /* determine iy = ilogb(y) */
+        if(hy<0x00800000) {     /* subnormal y */
+            for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1;
+        } else iy = (hy>>23)-127;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+        if(ix >= -126)
+            hx = 0x00800000|(0x007fffff&hx);
+        else {          /* subnormal x, shift x to normal */
+            n = -126-ix;
+            hx <<= n;
+        }
+        if(iy >= -126)
+            hy = 0x00800000|(0x007fffff&hy);
+        else {          /* subnormal y, shift y to normal */
+            n = -126-iy;
+            hy <<= n;
+        }
+
+    /* fix point fmod */
+        n = ix - iy;
+        q = 0;
+        while(n--) {
+            hz=hx-hy;
+            if(hz<0) hx = hx << 1;
+            else {hx = hz << 1; q++;}
+            q <<= 1;
+        }
+        hz=hx-hy;
+        if(hz>=0) {hx=hz;q++;}
+
+    /* convert back to floating value and restore the sign */
+        if(hx==0) {                             /* return sign(x)*0 */
+            *quo = (sxy ? -q : q);
+            return Zero[(uint32_t)sx>>31];
+        }
+        while(hx<0x00800000) {          /* normalize x */
+            hx <<= 1;
+            iy -= 1;
+        }
+        if(iy>= -126) {         /* normalize output */
+            hx = ((hx-0x00800000)|((iy+127)<<23));
+        } else {                /* subnormal output */
+            n = -126 - iy;
+            hx >>= n;
+        }
+fixup:
+        SET_FLOAT_WORD(x,hx);
+        y = fabsf(y);
+        if (y < 0x1p-125f) {
+            if (x+x>y || (x+x==y && (q & 1))) {
+                q++;
+                x-=y;
+            }
+        } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) {
+            q++;
+            x-=y;
+        }
+        GET_FLOAT_WORD(hx,x);
+        SET_FLOAT_WORD(x,hx^sx);
+        q &= 0x7fffffff;
+        *quo = (sxy ? -q : q);
+        return x;
+}
diff --git a/src/math/s_rint.c b/src/math/s_rint.c
new file mode 100644
index 00000000..aec7d3c9
--- /dev/null
+++ b/src/math/s_rint.c
@@ -0,0 +1,80 @@
+/* @(#)s_rint.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ *      Using floating addition.
+ * Exception:
+ *      Inexact flag raised if x not equal to rint(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+/*
+ * TWO23 is long double instead of double to avoid a bug in gcc.  Without
+ * this, gcc thinks that TWO23[sx]+x and w-TWO23[sx] already have double
+ * precision and doesn't clip them to double precision when they are
+ * assigned and returned.
+ */
+static const long double
+TWO52[2]={
+  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+double
+rint(double x)
+{
+        int32_t i0,j0,sx;
+        uint32_t i,i1;
+        double w,t;
+        EXTRACT_WORDS(i0,i1,x);
+        sx = (i0>>31)&1;
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {
+                if(((i0&0x7fffffff)|i1)==0) return x;
+                i1 |= (i0&0x0fffff);
+                i0 &= 0xfffe0000;
+                i0 |= ((i1|-i1)>>12)&0x80000;
+                SET_HIGH_WORD(x,i0);
+                w = TWO52[sx]+x;
+                t =  w-TWO52[sx];
+                GET_HIGH_WORD(i0,t);
+                SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31));
+                return t;
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                i>>=1;
+                if(((i0&i)|i1)!=0) {
+                    if(j0==19) i1 = 0x40000000; else
+                    i0 = (i0&(~i))|((0x20000)>>j0);
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            i>>=1;
+            if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+        }
+        INSERT_WORDS(x,i0,i1);
+        w = TWO52[sx]+x;
+        return w-TWO52[sx];
+}
diff --git a/src/math/s_rintf.c b/src/math/s_rintf.c
new file mode 100644
index 00000000..c441870d
--- /dev/null
+++ b/src/math/s_rintf.c
@@ -0,0 +1,45 @@
+/* s_rintf.c -- float version of s_rint.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+TWO23[2]={
+  8.3886080000e+06, /* 0x4b000000 */
+ -8.3886080000e+06, /* 0xcb000000 */
+};
+
+float
+rintf(float x)
+{
+        int32_t i0,j0,sx;
+        volatile float w,t;     /* volatile works around gcc bug */
+        GET_FLOAT_WORD(i0,x);
+        sx = (i0>>31)&1;
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {
+                if((i0&0x7fffffff)==0) return x;
+                w = TWO23[sx]+x;
+                t =  w-TWO23[sx];
+                return t;
+            }
+            w = TWO23[sx]+x;
+            return w-TWO23[sx];
+        }
+        if(j0==0x80) return x+x;        /* inf or NaN */
+        else return x;                  /* x is integral */
+}
diff --git a/src/math/s_round.c b/src/math/s_round.c
new file mode 100644
index 00000000..d5bea7a9
--- /dev/null
+++ b/src/math/s_round.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003, Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+double
+round(double x)
+{
+	double t;
+
+	if (!isfinite(x))
+		return (x);
+
+	if (x >= 0.0) {
+		t = ceil(x);
+		if (t - x > 0.5)
+			t -= 1.0;
+		return (t);
+	} else {
+		t = ceil(-x);
+		if (t + x > 0.5)
+			t -= 1.0;
+		return (-t);
+	}
+}
diff --git a/src/math/s_roundf.c b/src/math/s_roundf.c
new file mode 100644
index 00000000..c4fc3e19
--- /dev/null
+++ b/src/math/s_roundf.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003, Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+float
+roundf(float x)
+{
+	float t;
+
+	if (!isfinite(x))
+		return (x);
+
+	if (x >= 0.0) {
+		t = ceilf(x);
+		if (t - x > 0.5)
+			t -= 1.0;
+		return (t);
+	} else {
+		t = ceilf(-x);
+		if (t + x > 0.5)
+			t -= 1.0;
+		return (-t);
+	}
+}
diff --git a/src/math/s_scalbln.c b/src/math/s_scalbln.c
new file mode 100644
index 00000000..12b9391b
--- /dev/null
+++ b/src/math/s_scalbln.c
@@ -0,0 +1,61 @@
+/* @(#)s_scalbn.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n  computed by  exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double
+two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+huge   = 1.0e+300,
+tiny   = 1.0e-300;
+
+double
+scalbln (double x, long n)
+{
+        int32_t k,hx,lx;
+        EXTRACT_WORDS(hx,lx,x);
+        k = (hx&0x7ff00000)>>20;                /* extract exponent */
+        if (k==0) {                             /* 0 or subnormal x */
+            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+            x *= two54;
+            GET_HIGH_WORD(hx,x);
+            k = ((hx&0x7ff00000)>>20) - 54;
+            if (n< -50000) return tiny*x;       /*underflow*/
+            }
+        if (k==0x7ff) return x+x;               /* NaN or Inf */
+        k = k+n;
+        if (k >  0x7fe) return huge*copysign(huge,x); /* overflow  */
+        if (k > 0)                              /* normal result */
+            {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;}
+        if (k <= -54) {
+            if (n > 50000)      /* in case integer overflow in n+k */
+                return huge*copysign(huge,x);   /*overflow*/
+            else return tiny*copysign(tiny,x);  /*underflow*/
+        }
+        k += 54;                                /* subnormal result */
+        SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20));
+        return x*twom54;
+}
+
+double
+scalbn (double x, int n)
+{
+        return scalbln(x, n);
+}
diff --git a/src/math/s_scalblnf.c b/src/math/s_scalblnf.c
new file mode 100644
index 00000000..21e7641c
--- /dev/null
+++ b/src/math/s_scalblnf.c
@@ -0,0 +1,57 @@
+/* s_scalbnf.c -- float version of s_scalbn.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float
+two25   =  3.355443200e+07,     /* 0x4c000000 */
+twom25  =  2.9802322388e-08,    /* 0x33000000 */
+huge   = 1.0e+30,
+tiny   = 1.0e-30;
+
+float
+scalblnf (float x, long n)
+{
+        int32_t k,ix;
+        GET_FLOAT_WORD(ix,x);
+        k = (ix&0x7f800000)>>23;                /* extract exponent */
+        if (k==0) {                             /* 0 or subnormal x */
+            if ((ix&0x7fffffff)==0) return x; /* +-0 */
+            x *= two25;
+            GET_FLOAT_WORD(ix,x);
+            k = ((ix&0x7f800000)>>23) - 25;
+            if (n< -50000) return tiny*x;       /*underflow*/
+            }
+        if (k==0xff) return x+x;                /* NaN or Inf */
+        k = k+n;
+        if (k >  0xfe) return huge*copysignf(huge,x); /* overflow  */
+        if (k > 0)                              /* normal result */
+            {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;}
+        if (k <= -25) {
+            if (n > 50000)      /* in case integer overflow in n+k */
+                return huge*copysignf(huge,x);  /*overflow*/
+            else return tiny*copysignf(tiny,x); /*underflow*/
+        }
+        k += 25;                                /* subnormal result */
+        SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23));
+        return x*twom25;
+}
+
+float
+scalbnf (float x, int n)
+{
+        return scalblnf(x, n);
+}
diff --git a/src/math/s_sin.c b/src/math/s_sin.c
new file mode 100644
index 00000000..2a2774ed
--- /dev/null
+++ b/src/math/s_sin.c
@@ -0,0 +1,74 @@
+/* @(#)s_sin.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ *      __kernel_sin            ... sine function on [-pi/4,pi/4]
+ *      __kernel_cos            ... cose function on [-pi/4,pi/4]
+ *      __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *      in [-pi/4 , +pi/4], and let n = k mod 4.
+ *      We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *          0          S           C             T
+ *          1          C          -S            -1/T
+ *          2         -S          -C             T
+ *          3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *      TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+sin(double x)
+{
+        double y[2],z=0.0;
+        int32_t n, ix;
+
+    /* High word of x. */
+        GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
+
+    /* sin(Inf or NaN) is NaN */
+        else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_sin(y[0],y[1],1);
+                case 1: return  __kernel_cos(y[0],y[1]);
+                case 2: return -__kernel_sin(y[0],y[1],1);
+                default:
+                        return -__kernel_cos(y[0],y[1]);
+            }
+        }
+}
diff --git a/src/math/s_sinf.c b/src/math/s_sinf.c
new file mode 100644
index 00000000..d2b8e806
--- /dev/null
+++ b/src/math/s_sinf.c
@@ -0,0 +1,45 @@
+/* s_sinf.c -- float version of s_sin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+sinf(float x)
+{
+        float y[2],z=0.0;
+        int32_t n, ix;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
+
+    /* sin(Inf or NaN) is NaN */
+        else if (ix>=0x7f800000) return x-x;
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2f(x,y);
+            switch(n&3) {
+                case 0: return  __kernel_sinf(y[0],y[1],1);
+                case 1: return  __kernel_cosf(y[0],y[1]);
+                case 2: return -__kernel_sinf(y[0],y[1],1);
+                default:
+                        return -__kernel_cosf(y[0],y[1]);
+            }
+        }
+}
diff --git a/src/math/s_tan.c b/src/math/s_tan.c
new file mode 100644
index 00000000..3333cb3d
--- /dev/null
+++ b/src/math/s_tan.c
@@ -0,0 +1,68 @@
+/* @(#)s_tan.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ *      __kernel_tan            ... tangent function on [-pi/4,pi/4]
+ *      __ieee754_rem_pio2      ... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on
+ *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ *      in [-pi/4 , +pi/4], and let n = k mod 4.
+ *      We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *          0          S           C             T
+ *          1          C          -S            -1/T
+ *          2         -S          -C             T
+ *          3         -C           S            -1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *      TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+double
+tan(double x)
+{
+        double y[2],z=0.0;
+        int32_t n, ix;
+
+    /* High word of x. */
+        GET_HIGH_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);
+
+    /* tan(Inf or NaN) is NaN */
+        else if (ix>=0x7ff00000) return x-x;            /* NaN */
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2(x,y);
+            return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even
+                                                        -1 -- n odd */
+        }
+}
diff --git a/src/math/s_tanf.c b/src/math/s_tanf.c
new file mode 100644
index 00000000..660dd9c3
--- /dev/null
+++ b/src/math/s_tanf.c
@@ -0,0 +1,40 @@
+/* s_tanf.c -- float version of s_tan.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+float
+tanf(float x)
+{
+        float y[2],z=0.0;
+        int32_t n, ix;
+
+        GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+        ix &= 0x7fffffff;
+        if(ix <= 0x3f490fda) return __kernel_tanf(x,z,1);
+
+    /* tan(Inf or NaN) is NaN */
+        else if (ix>=0x7f800000) return x-x;            /* NaN */
+
+    /* argument reduction needed */
+        else {
+            n = __ieee754_rem_pio2f(x,y);
+            return __kernel_tanf(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even
+                                                              -1 -- n odd */
+        }
+}
diff --git a/src/math/s_tanh.c b/src/math/s_tanh.c
new file mode 100644
index 00000000..78b8e849
--- /dev/null
+++ b/src/math/s_tanh.c
@@ -0,0 +1,74 @@
+/* @(#)s_tanh.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ *                                     x    -x
+ *                                    e  - e
+ *      0. tanh(x) is defined to be -----------
+ *                                     x    -x
+ *                                    e  + e
+ *      1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ *      2.  0      <= x <= 2**-55 : tanh(x) := x*(one+x)
+ *                                              -t
+ *          2**-55 <  x <=  1     : tanh(x) := -----; t = expm1(-2x)
+ *                                             t + 2
+ *                                                   2
+ *          1      <= x <=  22.0  : tanh(x) := 1-  ----- ; t=expm1(2x)
+ *                                                 t + 2
+ *          22.0   <  x <= INF    : tanh(x) := 1.
+ *
+ * Special cases:
+ *      tanh(NaN) is NaN;
+ *      only tanh(0)=0 is exact for finite argument.
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+
+double
+tanh(double x)
+{
+        double t,z;
+        int32_t jx,ix;
+
+    /* High word of |x|. */
+        GET_HIGH_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7ff00000) {
+            if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
+            else       return one/x-one;    /* tanh(NaN) = NaN */
+        }
+
+    /* |x| < 22 */
+        if (ix < 0x40360000) {          /* |x|<22 */
+            if (ix<0x3c800000)          /* |x|<2**-55 */
+                return x*(one+x);       /* tanh(small) = small */
+            if (ix>=0x3ff00000) {       /* |x|>=1  */
+                t = expm1(two*fabs(x));
+                z = one - two/(t+two);
+            } else {
+                t = expm1(-two*fabs(x));
+                z= -t/(t+two);
+            }
+    /* |x| > 22, return +-1 */
+        } else {
+            z = one - tiny;             /* raised inexact flag */
+        }
+        return (jx>=0)? z: -z;
+}
diff --git a/src/math/s_tanhf.c b/src/math/s_tanhf.c
new file mode 100644
index 00000000..a0820409
--- /dev/null
+++ b/src/math/s_tanhf.c
@@ -0,0 +1,52 @@
+/* s_tanhf.c -- float version of s_tanh.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float one=1.0, two=2.0, tiny = 1.0e-30;
+
+float
+tanhf(float x)
+{
+        float t,z;
+        int32_t jx,ix;
+
+        GET_FLOAT_WORD(jx,x);
+        ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+        if(ix>=0x7f800000) {
+            if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
+            else       return one/x-one;    /* tanh(NaN) = NaN */
+        }
+
+    /* |x| < 22 */
+        if (ix < 0x41b00000) {          /* |x|<22 */
+            if (ix<0x24000000)          /* |x|<2**-55 */
+                return x*(one+x);       /* tanh(small) = small */
+            if (ix>=0x3f800000) {       /* |x|>=1  */
+                t = expm1f(two*fabsf(x));
+                z = one - two/(t+two);
+            } else {
+                t = expm1f(-two*fabsf(x));
+                z= -t/(t+two);
+            }
+    /* |x| > 22, return +-1 */
+        } else {
+            z = one - tiny;             /* raised inexact flag */
+        }
+        return (jx>=0)? z: -z;
+}
diff --git a/src/math/s_trunc.c b/src/math/s_trunc.c
new file mode 100644
index 00000000..02c65567
--- /dev/null
+++ b/src/math/s_trunc.c
@@ -0,0 +1,58 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * trunc(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to trunc(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const double huge = 1.0e300;
+
+double
+trunc(double x)
+{
+        int32_t i0,i1,j0;
+        uint32_t i,j;
+        EXTRACT_WORDS(i0,i1,x);
+        j0 = ((i0>>20)&0x7ff)-0x3ff;
+        if(j0<20) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */
+                    i0 &= 0x80000000U;
+                    i1 = 0;
+                }
+            } else {
+                i = (0x000fffff)>>j0;
+                if(((i0&i)|i1)==0) return x; /* x is integral */
+                if(huge+x>0.0) {        /* raise inexact flag */
+                    i0 &= (~i); i1=0;
+                }
+            }
+        } else if (j0>51) {
+            if(j0==0x400) return x+x;   /* inf or NaN */
+            else return x;              /* x is integral */
+        } else {
+            i = ((uint32_t)(0xffffffff))>>(j0-20);
+            if((i1&i)==0) return x;     /* x is integral */
+            if(huge+x>0.0)              /* raise inexact flag */
+                i1 &= (~i);
+        }
+        INSERT_WORDS(x,i0,i1);
+        return x;
+}
diff --git a/src/math/s_truncf.c b/src/math/s_truncf.c
new file mode 100644
index 00000000..c253e62b
--- /dev/null
+++ b/src/math/s_truncf.c
@@ -0,0 +1,50 @@
+/* @(#)s_floor.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * truncf(x)
+ * Return x rounded toward 0 to integral value
+ * Method:
+ *      Bit twiddling.
+ * Exception:
+ *      Inexact flag raised if x not equal to truncf(x).
+ */
+
+#include <math.h>
+#include "math_private.h"
+
+static const float huge = 1.0e30F;
+
+float
+truncf(float x)
+{
+        int32_t i0,j0;
+        uint32_t i;
+        GET_FLOAT_WORD(i0,x);
+        j0 = ((i0>>23)&0xff)-0x7f;
+        if(j0<23) {
+            if(j0<0) {  /* raise inexact if x != 0 */
+                if(huge+x>0.0F)         /* |x|<1, so return 0*sign(x) */
+                    i0 &= 0x80000000;
+            } else {
+                i = (0x007fffff)>>j0;
+                if((i0&i)==0) return x; /* x is integral */
+                if(huge+x>0.0F)         /* raise inexact flag */
+                    i0 &= (~i);
+            }
+        } else {
+            if(j0==0x80) return x+x;    /* inf or NaN */
+            else return x;              /* x is integral */
+        }
+        SET_FLOAT_WORD(x,i0);
+        return x;
+}
diff --git a/src/misc/basename.c b/src/misc/basename.c
new file mode 100644
index 00000000..c87e00cd
--- /dev/null
+++ b/src/misc/basename.c
@@ -0,0 +1,12 @@
+#include <string.h>
+#include <libgen.h>
+
+char *basename(char *s)
+{
+	size_t i;
+	if (!s || !*s) return ".";
+	i = strlen(s)-1;
+	for (; i&&s[i]=='/'; i--) s[i] = 0;
+	for (; i&&s[i-1]!='/'; i--);
+	return s+i;
+}
diff --git a/src/misc/bswap_32.c b/src/misc/bswap_32.c
new file mode 100644
index 00000000..a2418ca9
--- /dev/null
+++ b/src/misc/bswap_32.c
@@ -0,0 +1,7 @@
+#include <endian.h>
+#include <stdint.h>
+
+uint32_t bswap_32(uint32_t x)
+{
+	return x>>24 | x>>16&0xff00 | x<<16&0xff0000 | x<<24;
+}
diff --git a/src/misc/bswap_64.c b/src/misc/bswap_64.c
new file mode 100644
index 00000000..961300b5
--- /dev/null
+++ b/src/misc/bswap_64.c
@@ -0,0 +1,9 @@
+#include <endian.h>
+#include <stdint.h>
+
+uint32_t bswap_32(uint32_t);
+
+uint64_t bswap_64(uint64_t x)
+{
+	return bswap_32(x)+0LL<<32 | bswap_32(x>>32);
+}
diff --git a/src/misc/crypt.c b/src/misc/crypt.c
new file mode 100644
index 00000000..42918ef0
--- /dev/null
+++ b/src/misc/crypt.c
@@ -0,0 +1,2578 @@
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ *	B. Schneier, Applied Cryptography: protocols, algorithms,
+ *	and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author).  A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ *	It is assumed that the 8-byte arrays passed by reference can be
+ *	addressed as arrays of uint32_t's (ie. the CPU is not picky about
+ *	alignment).
+ */
+
+#include <stdint.h>
+#include "libc.h"
+
+static int i64c(int i)
+{
+	i &= 0x3f;
+	if (i == 0)
+		return '.';
+	if (i == 1)
+		return '/';
+	if (i < 12)
+		return ('0' - 2 + i);
+	if (i < 38)
+		return ('A' - 12 + i);
+	return ('a' - 38 + i);
+}
+
+/* Generated by const_des_init() (removed) */
+
+static const uint8_t final_perm[64] = {
+	0x39, 0x31, 0x29, 0x21, 0x19, 0x11, 0x09, 0x01, 0x3b, 0x33, 0x2b, 0x23, 0x1b, 0x13, 0x0b, 0x03,
+	0x3d, 0x35, 0x2d, 0x25, 0x1d, 0x15, 0x0d, 0x05, 0x3f, 0x37, 0x2f, 0x27, 0x1f, 0x17, 0x0f, 0x07,
+	0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 0x08, 0x00, 0x3a, 0x32, 0x2a, 0x22, 0x1a, 0x12, 0x0a, 0x02,
+	0x3c, 0x34, 0x2c, 0x24, 0x1c, 0x14, 0x0c, 0x04, 0x3e, 0x36, 0x2e, 0x26, 0x1e, 0x16, 0x0e, 0x06,
+};
+static const uint8_t m_sbox[4][4096] = {
+	{
+		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7,
+		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee,
+		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea,
+		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5,
+		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1,
+		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2,
+		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec,
+		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9,
+		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07,
+		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e,
+		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a,
+		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05,
+		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01,
+		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02,
+		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c,
+		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09,
+		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47,
+		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e,
+		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a,
+		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45,
+		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41,
+		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42,
+		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c,
+		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49,
+		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7,
+		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe,
+		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa,
+		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5,
+		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1,
+		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2,
+		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc,
+		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9,
+		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7,
+		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde,
+		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda,
+		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5,
+		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1,
+		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2,
+		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc,
+		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9,
+		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77,
+		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e,
+		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a,
+		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75,
+		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71,
+		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72,
+		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c,
+		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79,
+		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17,
+		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e,
+		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a,
+		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15,
+		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11,
+		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12,
+		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c,
+		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19,
+		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47,
+		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e,
+		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a,
+		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45,
+		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41,
+		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42,
+		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c,
+		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49,
+		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27,
+		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e,
+		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a,
+		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25,
+		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21,
+		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22,
+		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c,
+		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29,
+		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7,
+		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee,
+		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea,
+		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5,
+		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1,
+		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2,
+		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec,
+		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9,
+		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7,
+		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe,
+		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa,
+		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5,
+		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1,
+		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2,
+		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc,
+		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9,
+		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27,
+		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e,
+		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a,
+		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25,
+		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21,
+		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22,
+		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c,
+		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29,
+		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7,
+		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe,
+		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba,
+		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5,
+		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1,
+		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2,
+		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc,
+		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9,
+		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7,
+		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde,
+		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda,
+		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5,
+		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1,
+		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2,
+		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc,
+		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9,
+		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87,
+		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e,
+		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a,
+		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85,
+		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81,
+		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82,
+		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c,
+		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89,
+		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17,
+		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e,
+		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a,
+		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15,
+		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11,
+		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12,
+		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c,
+		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19,
+		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37,
+		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e,
+		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a,
+		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35,
+		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31,
+		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32,
+		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c,
+		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39,
+		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7,
+		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae,
+		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa,
+		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5,
+		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1,
+		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2,
+		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac,
+		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9,
+		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7,
+		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae,
+		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa,
+		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5,
+		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1,
+		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2,
+		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac,
+		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9,
+		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67,
+		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e,
+		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a,
+		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65,
+		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61,
+		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62,
+		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c,
+		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69,
+		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67,
+		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e,
+		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a,
+		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65,
+		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61,
+		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62,
+		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c,
+		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69,
+		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7,
+		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce,
+		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca,
+		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5,
+		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1,
+		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2,
+		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc,
+		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9,
+		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7,
+		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce,
+		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca,
+		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5,
+		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1,
+		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2,
+		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc,
+		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9,
+		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7,
+		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe,
+		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba,
+		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5,
+		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1,
+		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2,
+		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc,
+		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9,
+		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57,
+		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e,
+		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a,
+		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55,
+		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51,
+		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52,
+		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c,
+		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59,
+		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97,
+		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e,
+		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a,
+		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95,
+		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91,
+		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92,
+		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c,
+		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99,
+		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97,
+		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e,
+		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a,
+		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95,
+		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91,
+		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92,
+		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c,
+		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99,
+		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57,
+		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e,
+		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a,
+		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55,
+		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51,
+		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52,
+		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c,
+		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59,
+		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07,
+		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e,
+		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a,
+		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05,
+		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01,
+		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02,
+		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c,
+		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09,
+		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37,
+		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e,
+		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a,
+		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35,
+		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31,
+		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32,
+		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c,
+		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39,
+		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77,
+		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e,
+		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a,
+		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75,
+		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71,
+		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72,
+		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c,
+		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79,
+		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87,
+		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e,
+		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a,
+		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85,
+		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81,
+		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82,
+		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c,
+		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89,
+		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47,
+		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e,
+		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a,
+		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45,
+		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41,
+		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42,
+		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c,
+		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49,
+		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7,
+		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe,
+		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa,
+		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5,
+		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1,
+		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2,
+		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc,
+		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9,
+		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17,
+		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e,
+		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a,
+		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15,
+		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11,
+		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12,
+		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c,
+		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19,
+		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7,
+		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce,
+		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca,
+		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5,
+		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1,
+		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2,
+		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc,
+		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9,
+		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7,
+		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee,
+		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea,
+		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5,
+		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1,
+		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2,
+		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec,
+		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9,
+		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87,
+		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e,
+		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a,
+		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85,
+		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81,
+		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82,
+		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c,
+		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89,
+		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87,
+		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e,
+		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a,
+		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85,
+		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81,
+		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82,
+		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c,
+		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89,
+		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27,
+		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e,
+		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a,
+		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25,
+		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21,
+		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22,
+		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c,
+		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29,
+		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7,
+		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde,
+		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda,
+		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5,
+		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1,
+		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2,
+		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc,
+		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9,
+		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47,
+		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e,
+		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a,
+		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45,
+		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41,
+		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42,
+		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c,
+		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49,
+		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67,
+		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e,
+		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a,
+		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65,
+		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61,
+		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62,
+		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c,
+		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69,
+		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97,
+		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e,
+		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a,
+		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95,
+		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91,
+		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92,
+		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c,
+		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99,
+		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27,
+		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e,
+		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a,
+		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25,
+		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21,
+		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22,
+		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c,
+		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29,
+		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17,
+		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e,
+		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a,
+		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15,
+		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11,
+		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12,
+		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c,
+		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19,
+		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7,
+		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe,
+		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba,
+		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5,
+		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1,
+		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2,
+		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc,
+		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9,
+		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77,
+		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e,
+		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a,
+		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75,
+		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71,
+		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72,
+		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c,
+		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79,
+		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7,
+		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe,
+		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa,
+		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5,
+		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1,
+		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2,
+		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc,
+		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9,
+		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57,
+		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e,
+		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a,
+		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55,
+		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51,
+		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52,
+		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c,
+		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59,
+		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7,
+		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce,
+		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca,
+		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5,
+		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1,
+		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2,
+		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc,
+		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9,
+		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7,
+		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe,
+		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba,
+		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5,
+		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1,
+		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2,
+		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc,
+		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9,
+		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97,
+		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e,
+		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a,
+		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95,
+		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91,
+		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92,
+		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c,
+		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99,
+		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37,
+		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e,
+		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a,
+		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35,
+		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31,
+		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32,
+		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c,
+		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39,
+		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77,
+		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e,
+		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a,
+		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75,
+		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71,
+		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72,
+		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c,
+		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79,
+		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7,
+		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee,
+		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea,
+		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5,
+		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1,
+		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2,
+		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec,
+		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9,
+		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37,
+		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e,
+		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a,
+		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35,
+		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31,
+		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32,
+		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c,
+		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39,
+		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7,
+		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae,
+		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa,
+		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5,
+		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1,
+		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2,
+		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac,
+		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9,
+		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7,
+		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae,
+		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa,
+		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5,
+		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1,
+		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2,
+		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac,
+		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9,
+		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07,
+		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e,
+		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a,
+		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05,
+		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01,
+		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02,
+		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c,
+		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09,
+		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57,
+		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e,
+		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a,
+		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55,
+		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51,
+		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52,
+		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c,
+		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59,
+		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67,
+		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e,
+		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a,
+		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65,
+		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61,
+		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62,
+		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c,
+		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69,
+		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07,
+		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e,
+		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a,
+		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05,
+		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01,
+		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02,
+		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c,
+		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09,
+		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7,
+		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde,
+		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda,
+		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5,
+		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1,
+		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2,
+		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc,
+		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9,
+	},{
+		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5,
+		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3,
+		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac,
+		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9,
+		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6,
+		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8,
+		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab,
+		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae,
+		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5,
+		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3,
+		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc,
+		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9,
+		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6,
+		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8,
+		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb,
+		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde,
+		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05,
+		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03,
+		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c,
+		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09,
+		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06,
+		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08,
+		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b,
+		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e,
+		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75,
+		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73,
+		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c,
+		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79,
+		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76,
+		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78,
+		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b,
+		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e,
+		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95,
+		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93,
+		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c,
+		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99,
+		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96,
+		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98,
+		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b,
+		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e,
+		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05,
+		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03,
+		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c,
+		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09,
+		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06,
+		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08,
+		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b,
+		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e,
+		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5,
+		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3,
+		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec,
+		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9,
+		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6,
+		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8,
+		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb,
+		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee,
+		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95,
+		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93,
+		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c,
+		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99,
+		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96,
+		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98,
+		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b,
+		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e,
+		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65,
+		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63,
+		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c,
+		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69,
+		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66,
+		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68,
+		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b,
+		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e,
+		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35,
+		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33,
+		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c,
+		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39,
+		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36,
+		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38,
+		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b,
+		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e,
+		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35,
+		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33,
+		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c,
+		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39,
+		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36,
+		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38,
+		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b,
+		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e,
+		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45,
+		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43,
+		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c,
+		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49,
+		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46,
+		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48,
+		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b,
+		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e,
+		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5,
+		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3,
+		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc,
+		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9,
+		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6,
+		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8,
+		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb,
+		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe,
+		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65,
+		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63,
+		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c,
+		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69,
+		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66,
+		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68,
+		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b,
+		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e,
+		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55,
+		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53,
+		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c,
+		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59,
+		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56,
+		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58,
+		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b,
+		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e,
+		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5,
+		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3,
+		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac,
+		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9,
+		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6,
+		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8,
+		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab,
+		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae,
+		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15,
+		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13,
+		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c,
+		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19,
+		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16,
+		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18,
+		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b,
+		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e,
+		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25,
+		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23,
+		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c,
+		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29,
+		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26,
+		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28,
+		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b,
+		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e,
+		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5,
+		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3,
+		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc,
+		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9,
+		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6,
+		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8,
+		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb,
+		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde,
+		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85,
+		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83,
+		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c,
+		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89,
+		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86,
+		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88,
+		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b,
+		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e,
+		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5,
+		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3,
+		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc,
+		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9,
+		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6,
+		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8,
+		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb,
+		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce,
+		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55,
+		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53,
+		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c,
+		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59,
+		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56,
+		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58,
+		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b,
+		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e,
+		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75,
+		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73,
+		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c,
+		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79,
+		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76,
+		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78,
+		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b,
+		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e,
+		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5,
+		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3,
+		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec,
+		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9,
+		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6,
+		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8,
+		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb,
+		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee,
+		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5,
+		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3,
+		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc,
+		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9,
+		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6,
+		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8,
+		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb,
+		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe,
+		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5,
+		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3,
+		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc,
+		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9,
+		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6,
+		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8,
+		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb,
+		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce,
+		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45,
+		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43,
+		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c,
+		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49,
+		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46,
+		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48,
+		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b,
+		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e,
+		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5,
+		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3,
+		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc,
+		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9,
+		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6,
+		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8,
+		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb,
+		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe,
+		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25,
+		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23,
+		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c,
+		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29,
+		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26,
+		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28,
+		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b,
+		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e,
+		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5,
+		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3,
+		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc,
+		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9,
+		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6,
+		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8,
+		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb,
+		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe,
+		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85,
+		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83,
+		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c,
+		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89,
+		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86,
+		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88,
+		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b,
+		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e,
+		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15,
+		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13,
+		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c,
+		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19,
+		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16,
+		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18,
+		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b,
+		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e,
+		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5,
+		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3,
+		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc,
+		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9,
+		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6,
+		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8,
+		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb,
+		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde,
+		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15,
+		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13,
+		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c,
+		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19,
+		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16,
+		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18,
+		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b,
+		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e,
+		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65,
+		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63,
+		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c,
+		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69,
+		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66,
+		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68,
+		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b,
+		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e,
+		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5,
+		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3,
+		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac,
+		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9,
+		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6,
+		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8,
+		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab,
+		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae,
+		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45,
+		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43,
+		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c,
+		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49,
+		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46,
+		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48,
+		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b,
+		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e,
+		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5,
+		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3,
+		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc,
+		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9,
+		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6,
+		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8,
+		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb,
+		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde,
+		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95,
+		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93,
+		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c,
+		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99,
+		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96,
+		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98,
+		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b,
+		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e,
+		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05,
+		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03,
+		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c,
+		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09,
+		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06,
+		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08,
+		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b,
+		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e,
+		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85,
+		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83,
+		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c,
+		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89,
+		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86,
+		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88,
+		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b,
+		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e,
+		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65,
+		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63,
+		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c,
+		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69,
+		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66,
+		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68,
+		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b,
+		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e,
+		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5,
+		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3,
+		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc,
+		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9,
+		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6,
+		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8,
+		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb,
+		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe,
+		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95,
+		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93,
+		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c,
+		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99,
+		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96,
+		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98,
+		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b,
+		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e,
+		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35,
+		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33,
+		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c,
+		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39,
+		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36,
+		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38,
+		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b,
+		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e,
+		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85,
+		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83,
+		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c,
+		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89,
+		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86,
+		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88,
+		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b,
+		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e,
+		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05,
+		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03,
+		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c,
+		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09,
+		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06,
+		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08,
+		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b,
+		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e,
+		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75,
+		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73,
+		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c,
+		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79,
+		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76,
+		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78,
+		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b,
+		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e,
+		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5,
+		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3,
+		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc,
+		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9,
+		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6,
+		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8,
+		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb,
+		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe,
+		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45,
+		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43,
+		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c,
+		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49,
+		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46,
+		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48,
+		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b,
+		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e,
+		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15,
+		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13,
+		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c,
+		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19,
+		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16,
+		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18,
+		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b,
+		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e,
+		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5,
+		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3,
+		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc,
+		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9,
+		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6,
+		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8,
+		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb,
+		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe,
+		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25,
+		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23,
+		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c,
+		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29,
+		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26,
+		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28,
+		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b,
+		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e,
+		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5,
+		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3,
+		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec,
+		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9,
+		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6,
+		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8,
+		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb,
+		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee,
+		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5,
+		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3,
+		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc,
+		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9,
+		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6,
+		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8,
+		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb,
+		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce,
+		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35,
+		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33,
+		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c,
+		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39,
+		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36,
+		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38,
+		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b,
+		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e,
+		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55,
+		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53,
+		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c,
+		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59,
+		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56,
+		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58,
+		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b,
+		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e,
+		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5,
+		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3,
+		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc,
+		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9,
+		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6,
+		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8,
+		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb,
+		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe,
+		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5,
+		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3,
+		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac,
+		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9,
+		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6,
+		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8,
+		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab,
+		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae,
+		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55,
+		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53,
+		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c,
+		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59,
+		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56,
+		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58,
+		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b,
+		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e,
+		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5,
+		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3,
+		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec,
+		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9,
+		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6,
+		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8,
+		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb,
+		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee,
+		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25,
+		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23,
+		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c,
+		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29,
+		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26,
+		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28,
+		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b,
+		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e,
+		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75,
+		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73,
+		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c,
+		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79,
+		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76,
+		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78,
+		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b,
+		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e,
+		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5,
+		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3,
+		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc,
+		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9,
+		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6,
+		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8,
+		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb,
+		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce,
+	},{
+		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22,
+		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25,
+		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e,
+		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28,
+		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c,
+		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a,
+		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27,
+		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d,
+		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2,
+		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5,
+		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee,
+		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8,
+		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec,
+		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea,
+		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7,
+		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed,
+		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2,
+		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5,
+		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce,
+		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8,
+		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc,
+		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca,
+		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7,
+		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd,
+		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2,
+		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5,
+		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe,
+		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8,
+		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc,
+		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba,
+		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7,
+		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd,
+		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42,
+		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45,
+		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e,
+		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48,
+		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c,
+		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a,
+		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47,
+		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d,
+		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22,
+		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25,
+		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e,
+		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28,
+		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c,
+		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a,
+		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27,
+		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d,
+		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12,
+		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15,
+		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e,
+		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18,
+		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c,
+		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a,
+		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17,
+		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d,
+		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2,
+		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5,
+		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce,
+		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8,
+		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc,
+		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca,
+		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7,
+		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd,
+		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72,
+		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75,
+		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e,
+		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78,
+		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c,
+		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a,
+		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77,
+		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d,
+		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42,
+		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45,
+		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e,
+		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48,
+		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c,
+		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a,
+		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47,
+		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d,
+		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2,
+		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5,
+		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae,
+		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8,
+		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac,
+		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa,
+		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7,
+		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad,
+		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72,
+		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75,
+		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e,
+		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78,
+		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c,
+		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a,
+		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77,
+		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d,
+		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2,
+		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5,
+		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe,
+		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8,
+		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc,
+		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba,
+		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7,
+		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd,
+		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2,
+		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5,
+		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde,
+		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8,
+		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc,
+		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda,
+		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7,
+		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd,
+		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62,
+		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65,
+		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e,
+		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68,
+		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c,
+		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a,
+		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67,
+		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d,
+		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12,
+		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15,
+		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e,
+		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18,
+		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c,
+		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a,
+		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17,
+		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d,
+		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82,
+		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85,
+		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e,
+		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88,
+		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c,
+		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a,
+		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87,
+		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d,
+		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52,
+		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55,
+		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e,
+		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58,
+		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c,
+		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a,
+		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57,
+		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d,
+		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52,
+		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55,
+		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e,
+		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58,
+		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c,
+		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a,
+		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57,
+		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d,
+		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02,
+		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05,
+		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e,
+		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08,
+		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c,
+		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a,
+		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07,
+		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d,
+		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32,
+		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35,
+		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e,
+		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38,
+		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c,
+		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a,
+		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37,
+		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d,
+		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2,
+		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5,
+		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe,
+		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8,
+		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc,
+		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa,
+		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7,
+		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd,
+		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2,
+		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5,
+		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe,
+		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8,
+		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc,
+		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa,
+		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7,
+		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd,
+		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2,
+		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5,
+		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae,
+		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8,
+		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac,
+		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa,
+		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7,
+		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad,
+		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2,
+		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5,
+		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde,
+		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8,
+		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc,
+		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda,
+		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7,
+		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd,
+		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32,
+		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35,
+		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e,
+		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38,
+		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c,
+		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a,
+		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37,
+		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d,
+		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02,
+		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05,
+		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e,
+		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08,
+		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c,
+		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a,
+		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07,
+		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d,
+		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92,
+		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95,
+		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e,
+		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98,
+		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c,
+		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a,
+		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97,
+		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d,
+		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2,
+		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5,
+		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee,
+		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8,
+		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec,
+		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea,
+		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7,
+		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed,
+		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82,
+		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85,
+		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e,
+		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88,
+		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c,
+		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a,
+		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87,
+		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d,
+		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92,
+		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95,
+		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e,
+		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98,
+		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c,
+		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a,
+		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97,
+		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d,
+		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62,
+		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65,
+		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e,
+		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68,
+		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c,
+		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a,
+		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67,
+		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d,
+		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42,
+		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45,
+		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e,
+		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48,
+		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c,
+		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a,
+		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47,
+		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d,
+		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2,
+		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5,
+		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe,
+		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8,
+		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc,
+		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba,
+		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7,
+		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd,
+		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22,
+		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25,
+		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e,
+		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28,
+		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c,
+		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a,
+		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27,
+		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d,
+		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82,
+		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85,
+		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e,
+		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88,
+		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c,
+		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a,
+		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87,
+		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d,
+		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12,
+		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15,
+		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e,
+		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18,
+		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c,
+		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a,
+		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17,
+		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d,
+		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2,
+		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5,
+		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce,
+		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8,
+		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc,
+		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca,
+		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7,
+		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd,
+		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2,
+		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5,
+		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe,
+		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8,
+		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc,
+		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba,
+		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7,
+		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd,
+		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72,
+		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75,
+		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e,
+		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78,
+		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c,
+		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a,
+		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77,
+		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d,
+		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2,
+		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5,
+		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae,
+		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8,
+		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac,
+		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa,
+		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7,
+		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad,
+		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12,
+		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15,
+		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e,
+		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18,
+		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c,
+		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a,
+		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17,
+		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d,
+		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2,
+		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5,
+		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde,
+		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8,
+		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc,
+		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda,
+		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7,
+		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd,
+		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2,
+		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5,
+		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee,
+		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8,
+		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec,
+		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea,
+		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7,
+		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed,
+		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72,
+		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75,
+		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e,
+		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78,
+		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c,
+		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a,
+		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77,
+		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d,
+		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22,
+		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25,
+		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e,
+		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28,
+		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c,
+		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a,
+		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27,
+		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d,
+		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82,
+		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85,
+		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e,
+		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88,
+		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c,
+		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a,
+		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87,
+		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d,
+		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2,
+		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5,
+		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde,
+		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8,
+		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc,
+		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda,
+		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7,
+		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd,
+		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2,
+		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5,
+		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe,
+		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8,
+		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc,
+		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa,
+		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7,
+		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd,
+		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62,
+		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65,
+		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e,
+		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68,
+		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c,
+		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a,
+		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67,
+		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d,
+		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92,
+		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95,
+		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e,
+		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98,
+		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c,
+		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a,
+		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97,
+		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d,
+		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2,
+		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5,
+		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe,
+		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8,
+		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc,
+		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa,
+		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7,
+		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd,
+		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2,
+		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5,
+		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce,
+		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8,
+		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc,
+		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca,
+		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7,
+		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd,
+		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02,
+		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05,
+		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e,
+		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08,
+		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c,
+		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a,
+		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07,
+		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d,
+		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52,
+		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55,
+		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e,
+		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58,
+		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c,
+		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a,
+		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57,
+		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d,
+		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92,
+		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95,
+		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e,
+		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98,
+		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c,
+		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a,
+		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97,
+		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d,
+		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62,
+		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65,
+		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e,
+		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68,
+		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c,
+		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a,
+		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67,
+		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d,
+		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2,
+		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5,
+		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae,
+		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8,
+		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac,
+		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa,
+		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7,
+		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad,
+		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32,
+		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35,
+		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e,
+		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38,
+		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c,
+		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a,
+		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37,
+		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d,
+		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42,
+		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45,
+		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e,
+		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48,
+		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c,
+		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a,
+		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47,
+		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d,
+		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02,
+		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05,
+		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e,
+		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08,
+		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c,
+		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a,
+		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07,
+		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d,
+		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52,
+		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55,
+		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e,
+		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58,
+		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c,
+		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a,
+		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57,
+		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d,
+		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2,
+		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5,
+		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee,
+		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8,
+		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec,
+		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea,
+		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7,
+		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed,
+		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32,
+		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35,
+		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e,
+		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38,
+		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c,
+		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a,
+		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37,
+		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d,
+	},{
+		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48,
+		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44,
+		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b,
+		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42,
+		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47,
+		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d,
+		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40,
+		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b,
+		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8,
+		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4,
+		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb,
+		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2,
+		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7,
+		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd,
+		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0,
+		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb,
+		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8,
+		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4,
+		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb,
+		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2,
+		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7,
+		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd,
+		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0,
+		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb,
+		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08,
+		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04,
+		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b,
+		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02,
+		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07,
+		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d,
+		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00,
+		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b,
+		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28,
+		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24,
+		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b,
+		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22,
+		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27,
+		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d,
+		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20,
+		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b,
+		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8,
+		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4,
+		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb,
+		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2,
+		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7,
+		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd,
+		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0,
+		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb,
+		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8,
+		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4,
+		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb,
+		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2,
+		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7,
+		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed,
+		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0,
+		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb,
+		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78,
+		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74,
+		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b,
+		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72,
+		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77,
+		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d,
+		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70,
+		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b,
+		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8,
+		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4,
+		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb,
+		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2,
+		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7,
+		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd,
+		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0,
+		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb,
+		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48,
+		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44,
+		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b,
+		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42,
+		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47,
+		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d,
+		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40,
+		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b,
+		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08,
+		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04,
+		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b,
+		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02,
+		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07,
+		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d,
+		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00,
+		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b,
+		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98,
+		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94,
+		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b,
+		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92,
+		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97,
+		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d,
+		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90,
+		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b,
+		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88,
+		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84,
+		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b,
+		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82,
+		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87,
+		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d,
+		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80,
+		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b,
+		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18,
+		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14,
+		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b,
+		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12,
+		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17,
+		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d,
+		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10,
+		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b,
+		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8,
+		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4,
+		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb,
+		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2,
+		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7,
+		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd,
+		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0,
+		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb,
+		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8,
+		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4,
+		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab,
+		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2,
+		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7,
+		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad,
+		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0,
+		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab,
+		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38,
+		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34,
+		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b,
+		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32,
+		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37,
+		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d,
+		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30,
+		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b,
+		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8,
+		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4,
+		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb,
+		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2,
+		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7,
+		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed,
+		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0,
+		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb,
+		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8,
+		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4,
+		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb,
+		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2,
+		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7,
+		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd,
+		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0,
+		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb,
+		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38,
+		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34,
+		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b,
+		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32,
+		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37,
+		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d,
+		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30,
+		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b,
+		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98,
+		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94,
+		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b,
+		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92,
+		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97,
+		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d,
+		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90,
+		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b,
+		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58,
+		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54,
+		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b,
+		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52,
+		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57,
+		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d,
+		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50,
+		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b,
+		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78,
+		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74,
+		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b,
+		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72,
+		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77,
+		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d,
+		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70,
+		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b,
+		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8,
+		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4,
+		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb,
+		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2,
+		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7,
+		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd,
+		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0,
+		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb,
+		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58,
+		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54,
+		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b,
+		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52,
+		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57,
+		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d,
+		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50,
+		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b,
+		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28,
+		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24,
+		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b,
+		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22,
+		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27,
+		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d,
+		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20,
+		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b,
+		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8,
+		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4,
+		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab,
+		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2,
+		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7,
+		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad,
+		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0,
+		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab,
+		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8,
+		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4,
+		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb,
+		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2,
+		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7,
+		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd,
+		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0,
+		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb,
+		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68,
+		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64,
+		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b,
+		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62,
+		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67,
+		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d,
+		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60,
+		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b,
+		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88,
+		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84,
+		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b,
+		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82,
+		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87,
+		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d,
+		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80,
+		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b,
+		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18,
+		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14,
+		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b,
+		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12,
+		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17,
+		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d,
+		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10,
+		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b,
+		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68,
+		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64,
+		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b,
+		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62,
+		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67,
+		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d,
+		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60,
+		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b,
+		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18,
+		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14,
+		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b,
+		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12,
+		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17,
+		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d,
+		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10,
+		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b,
+		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68,
+		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64,
+		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b,
+		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62,
+		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67,
+		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d,
+		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60,
+		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b,
+		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48,
+		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44,
+		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b,
+		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42,
+		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47,
+		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d,
+		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40,
+		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b,
+		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8,
+		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4,
+		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb,
+		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2,
+		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7,
+		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd,
+		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0,
+		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb,
+		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8,
+		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4,
+		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb,
+		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2,
+		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7,
+		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd,
+		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0,
+		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb,
+		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8,
+		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4,
+		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb,
+		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2,
+		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7,
+		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd,
+		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0,
+		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb,
+		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8,
+		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4,
+		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb,
+		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2,
+		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7,
+		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd,
+		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0,
+		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb,
+		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88,
+		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84,
+		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b,
+		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82,
+		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87,
+		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d,
+		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80,
+		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b,
+		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8,
+		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4,
+		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb,
+		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2,
+		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7,
+		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd,
+		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0,
+		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb,
+		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18,
+		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14,
+		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b,
+		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12,
+		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17,
+		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d,
+		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10,
+		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b,
+		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38,
+		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34,
+		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b,
+		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32,
+		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37,
+		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d,
+		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30,
+		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b,
+		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48,
+		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44,
+		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b,
+		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42,
+		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47,
+		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d,
+		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40,
+		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b,
+		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78,
+		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74,
+		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b,
+		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72,
+		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77,
+		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d,
+		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70,
+		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b,
+		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8,
+		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4,
+		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab,
+		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2,
+		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7,
+		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad,
+		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0,
+		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab,
+		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8,
+		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4,
+		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb,
+		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2,
+		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7,
+		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed,
+		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0,
+		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb,
+		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78,
+		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74,
+		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b,
+		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72,
+		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77,
+		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d,
+		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70,
+		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b,
+		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8,
+		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4,
+		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab,
+		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2,
+		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7,
+		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad,
+		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0,
+		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab,
+		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98,
+		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94,
+		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b,
+		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92,
+		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97,
+		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d,
+		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90,
+		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b,
+		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8,
+		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4,
+		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb,
+		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2,
+		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7,
+		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd,
+		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0,
+		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb,
+		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58,
+		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54,
+		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b,
+		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52,
+		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57,
+		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d,
+		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50,
+		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b,
+		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68,
+		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64,
+		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b,
+		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62,
+		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67,
+		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d,
+		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60,
+		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b,
+		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08,
+		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04,
+		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b,
+		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02,
+		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07,
+		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d,
+		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00,
+		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b,
+		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88,
+		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84,
+		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b,
+		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82,
+		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87,
+		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d,
+		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80,
+		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b,
+		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8,
+		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4,
+		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb,
+		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2,
+		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7,
+		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd,
+		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0,
+		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb,
+		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08,
+		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04,
+		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b,
+		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02,
+		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07,
+		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d,
+		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00,
+		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b,
+		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8,
+		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4,
+		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb,
+		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2,
+		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7,
+		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed,
+		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0,
+		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb,
+		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58,
+		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54,
+		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b,
+		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52,
+		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57,
+		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d,
+		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50,
+		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b,
+		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28,
+		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24,
+		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b,
+		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22,
+		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27,
+		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d,
+		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20,
+		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b,
+		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98,
+		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94,
+		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b,
+		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92,
+		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97,
+		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d,
+		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90,
+		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b,
+		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38,
+		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34,
+		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b,
+		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32,
+		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37,
+		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d,
+		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30,
+		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b,
+		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28,
+		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24,
+		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b,
+		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22,
+		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27,
+		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d,
+		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20,
+		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b,
+		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8,
+		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4,
+		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb,
+		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2,
+		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7,
+		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd,
+		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0,
+		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb,
+	},
+};
+
+static const uint8_t key_perm[56] = {
+	57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
+	10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
+	63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
+	14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
+};
+
+static const uint8_t key_shifts[16] = {
+	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static const uint8_t comp_perm[48] = {
+	14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
+	23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
+	41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+	44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+static const uint8_t pbox[32] = {
+	16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
+	 2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25
+};
+
+static int
+ascii_to_bin(char ch)
+{
+	if (ch > 'z')
+		return 0;
+	if (ch >= 'a')
+		return (ch - 'a' + 38);
+	if (ch > 'Z')
+		return 0;
+	if (ch >= 'A')
+		return (ch - 'A' + 12);
+	if (ch > '9')
+		return 0;
+	if (ch >= '.')
+		return (ch - '.');
+	return 0;
+}
+
+
+
+struct des_ctx {
+	uint32_t saltbits; /* referenced 5 times */
+	uint8_t	un_pbox[32]; /* 2 times */
+	uint8_t	inv_comp_perm[56]; /* 3 times */
+	uint8_t	inv_key_perm[64]; /* 3 times */
+	uint32_t en_keysl[16], en_keysr[16]; /* 2 times each */
+	uint32_t fp_maskl[8][256], fp_maskr[8][256]; /* 9 times each */
+	uint32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; /* 9 times */
+	uint32_t comp_maskl[8][128], comp_maskr[8][128]; /* 9 times each */
+	uint32_t psbox[4][256]; /* 5 times */
+};
+#define D (*ctx)
+#define saltbits        (D.saltbits       )
+#define old_salt        (D.old_salt       )
+#define old_rawkey0     (D.old_rawkey0    )
+#define old_rawkey1     (D.old_rawkey1    )
+#define un_pbox         (D.un_pbox        )
+#define inv_comp_perm   (D.inv_comp_perm  )
+#define inv_key_perm    (D.inv_key_perm   )
+#define en_keysl        (D.en_keysl       )
+#define en_keysr        (D.en_keysr       )
+#define de_keysl        (D.de_keysl       )
+#define de_keysr        (D.de_keysr       )
+#define ip_maskl        (D.ip_maskl       )
+#define ip_maskr        (D.ip_maskr       )
+#define fp_maskl        (D.fp_maskl       )
+#define fp_maskr        (D.fp_maskr       )
+#define key_perm_maskl  (D.key_perm_maskl )
+#define key_perm_maskr  (D.key_perm_maskr )
+#define comp_maskl      (D.comp_maskl     )
+#define comp_maskr      (D.comp_maskr     )
+#define psbox           (D.psbox          )
+
+static struct des_ctx *des_init(struct des_ctx *ctx)
+{
+	int i, j, b, k, inbit, obit;
+	uint32_t p;
+
+	saltbits = 0;
+
+	/* Initialise the inverted key permutation. */
+	for (i = 0; i < 64; i++) {
+		inv_key_perm[i] = 255;
+	}
+
+	/*
+	 * Invert the key permutation and initialise the inverted key
+	 * compression permutation.
+	 */
+	for (i = 0; i < 56; i++) {
+		inv_key_perm[key_perm[i] - 1] = (uint8_t)i;
+		inv_comp_perm[i] = 255;
+	}
+
+	/* Invert the key compression permutation. */
+	for (i = 0; i < 48; i++) {
+		inv_comp_perm[comp_perm[i] - 1] = (uint8_t)i;
+	}
+
+	/*
+	 * Set up the OR-mask arrays for the initial and final permutations,
+	 * and for the key initial and compression permutations.
+	 */
+	for (k = 0; k < 8; k++) {
+		uint32_t il, ir;
+		uint32_t fl, fr;
+		for (i = 0; i < 256; i++) {
+			fl = 0;
+			fr = 0;
+			for (j = 0; j < 8; j++) {
+				inbit = 8 * k + j;
+				if (i & (0x80>>j)) {
+					obit = final_perm[inbit];
+					if (obit < 32)
+						fl |= 0x80000000UL >> obit;
+					else
+						fr |= 0x80000000UL >> obit-32;
+				}
+			}
+			fp_maskl[k][i] = fl;
+			fp_maskr[k][i] = fr;
+		}
+		for (i = 0; i < 128; i++) {
+			il = 0;
+			ir = 0;
+			for (j = 0; j < 7; j++) {
+				inbit = 8 * k + j;
+				if (i & (0x80 >> j + 1)) {
+					obit = inv_key_perm[inbit];
+					if (obit == 255)
+						continue;
+					if (obit < 28)
+						il |= 0x8000000UL >> obit;
+					else
+						ir |= 0x8000000UL >> obit-28;
+				}
+			}
+			key_perm_maskl[k][i] = il;
+			key_perm_maskr[k][i] = ir;
+			il = 0;
+			ir = 0;
+			for (j = 0; j < 7; j++) {
+				inbit = 7 * k + j;
+				if (i & (0x80 >> j + 1)) {
+					obit = inv_comp_perm[inbit];
+					if (obit == 255)
+						continue;
+					if (obit < 24)
+						il |= 0x800000UL >> obit;
+					else
+						ir |= 0x800000UL >> obit-24;
+				}
+			}
+			comp_maskl[k][i] = il;
+			comp_maskr[k][i] = ir;
+		}
+	}
+
+	/*
+	 * Invert the P-box permutation, and convert into OR-masks for
+	 * handling the output of the S-box arrays setup above.
+	 */
+	for (i = 0; i < 32; i++)
+		un_pbox[pbox[i] - 1] = (uint8_t)i;
+
+	for (b = 0; b < 4; b++) {
+		for (i = 0; i < 256; i++) {
+			p = 0;
+			for (j = 0; j < 8; j++) {
+				if (i & (0x80 >> j))
+					p |= 0x80000000>>un_pbox[8 * b + j];
+			}
+			psbox[b][i] = p;
+		}
+	}
+
+	return ctx;
+}
+
+
+static void setup_salt(struct des_ctx *ctx, uint32_t salt)
+{
+	uint32_t obit, saltbit;
+	int i;
+
+	saltbits = 0;
+	saltbit = 1;
+	obit = 0x800000;
+	for (i = 0; i < 24; i++) {
+		if (salt & saltbit)
+			saltbits |= obit;
+		saltbit <<= 1;
+		obit >>= 1;
+	}
+}
+
+static void des_setkey(struct des_ctx *ctx, const unsigned char *key)
+{
+	uint32_t k0, k1, rawkey0, rawkey1;
+	int shifts, round;
+
+	rawkey0 = key[0]<<24 | key[1]<<16 | key[2]<<8 | key[3];
+	rawkey1 = key[4]<<24 | key[5]<<16 | key[6]<<8 | key[7];
+
+	/*
+	 * Do key permutation and split into two 28-bit subkeys.
+	 */
+	k0 = key_perm_maskl[0][rawkey0 >> 25]
+	   | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+	   | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+	   | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+	   | key_perm_maskl[4][rawkey1 >> 25]
+	   | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+	   | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+	   | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+	k1 = key_perm_maskr[0][rawkey0 >> 25]
+	   | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+	   | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+	   | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+	   | key_perm_maskr[4][rawkey1 >> 25]
+	   | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+	   | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+	   | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+	/*
+	 * Rotate subkeys and do compression permutation.
+	 */
+	shifts = 0;
+	for (round = 0; round < 16; round++) {
+		uint32_t t0, t1;
+
+		shifts += key_shifts[round];
+
+		t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+		t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+		en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+				| comp_maskl[1][(t0 >> 14) & 0x7f]
+				| comp_maskl[2][(t0 >> 7) & 0x7f]
+				| comp_maskl[3][t0 & 0x7f]
+				| comp_maskl[4][(t1 >> 21) & 0x7f]
+				| comp_maskl[5][(t1 >> 14) & 0x7f]
+				| comp_maskl[6][(t1 >> 7) & 0x7f]
+				| comp_maskl[7][t1 & 0x7f];
+
+		en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
+				| comp_maskr[1][(t0 >> 14) & 0x7f]
+				| comp_maskr[2][(t0 >> 7) & 0x7f]
+				| comp_maskr[3][t0 & 0x7f]
+				| comp_maskr[4][(t1 >> 21) & 0x7f]
+				| comp_maskr[5][(t1 >> 14) & 0x7f]
+				| comp_maskr[6][(t1 >> 7) & 0x7f]
+				| comp_maskr[7][t1 & 0x7f];
+	}
+}
+
+
+static void do_des(struct des_ctx *ctx, uint32_t *l_out, uint32_t *r_out, int count)
+{
+	uint32_t l, r, *kl, *kr;
+	uint32_t f = f; /* silence gcc */
+	uint32_t r48l, r48r;
+	int round;
+
+	/* Do initial permutation (IP). */
+	l = r = 0;
+
+	do {
+		/* Do each round. */
+		kl = en_keysl;
+		kr = en_keysr;
+		round = 16;
+		do {
+			/* Expand R to 48 bits (simulate the E-box). */
+			r48l	= ((r & 0x00000001) << 23)
+				| ((r & 0xf8000000) >> 9)
+				| ((r & 0x1f800000) >> 11)
+				| ((r & 0x01f80000) >> 13)
+				| ((r & 0x001f8000) >> 15);
+
+			r48r	= ((r & 0x0001f800) << 7)
+				| ((r & 0x00001f80) << 5)
+				| ((r & 0x000001f8) << 3)
+				| ((r & 0x0000001f) << 1)
+				| ((r & 0x80000000) >> 31);
+			/*
+			 * Do salting for crypt() and friends, and
+			 * XOR with the permuted key.
+			 */
+			f = (r48l ^ r48r) & saltbits;
+			r48l ^= f ^ *kl++;
+			r48r ^= f ^ *kr++;
+			/*
+			 * Do sbox lookups (which shrink it back to 32 bits)
+			 * and do the pbox permutation at the same time.
+			 */
+			f = psbox[0][m_sbox[0][r48l >> 12]]
+			  | psbox[1][m_sbox[1][r48l & 0xfff]]
+			  | psbox[2][m_sbox[2][r48r >> 12]]
+			  | psbox[3][m_sbox[3][r48r & 0xfff]];
+			/* Now that we've permuted things, complete f(). */
+			f ^= l;
+			l = r;
+			r = f;
+		} while (--round);
+		r = l;
+		l = f;
+	} while (--count);
+
+	/* Do final permutation (inverse of IP). */
+	*l_out	= fp_maskl[0][l >> 24]
+		| fp_maskl[1][(l >> 16) & 0xff]
+		| fp_maskl[2][(l >> 8) & 0xff]
+		| fp_maskl[3][l & 0xff]
+		| fp_maskl[4][r >> 24]
+		| fp_maskl[5][(r >> 16) & 0xff]
+		| fp_maskl[6][(r >> 8) & 0xff]
+		| fp_maskl[7][r & 0xff];
+	*r_out	= fp_maskr[0][l >> 24]
+		| fp_maskr[1][(l >> 16) & 0xff]
+		| fp_maskr[2][(l >> 8) & 0xff]
+		| fp_maskr[3][l & 0xff]
+		| fp_maskr[4][r >> 24]
+		| fp_maskr[5][(r >> 16) & 0xff]
+		| fp_maskr[6][(r >> 8) & 0xff]
+		| fp_maskr[7][r & 0xff];
+}
+
+#define DES_OUT_BUFSIZE 21
+
+static void
+to64_msb_first(char *s, unsigned v)
+{
+	*s++ = i64c(v >> 18); /* bits 23..18 */
+	*s++ = i64c(v >> 12); /* bits 17..12 */
+	*s++ = i64c(v >> 6); /* bits 11..6 */
+	*s   = i64c(v); /* bits 5..0 */
+}
+
+static char *
+des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
+		const unsigned char *key, const unsigned char *setting)
+{
+	uint32_t salt, r0, r1, keybuf[2];
+	uint8_t *q;
+
+	/*
+	 * Copy the key, shifting each character up by one bit
+	 * and padding with zeros.
+	 */
+	q = (uint8_t *)keybuf;
+	while (q - (uint8_t *)keybuf != 8) {
+		*q = *key << 1;
+		if (*q)
+			key++;
+		q++;
+	}
+	des_setkey(ctx, (char *)keybuf);
+
+	/*
+	 * setting - 2 bytes of salt
+	 * key - up to 8 characters
+	 */
+	salt = (ascii_to_bin(setting[1]) << 6)
+	     |  ascii_to_bin(setting[0]);
+
+	output[0] = setting[0];
+	/*
+	 * If the encrypted password that the salt was extracted from
+	 * is only 1 character long, the salt will be corrupted.  We
+	 * need to ensure that the output string doesn't have an extra
+	 * NUL in it!
+	 */
+	output[1] = setting[1] ? setting[1] : output[0];
+
+	setup_salt(ctx, salt);
+	/* Do it. */
+	do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
+
+	/* Now encode the result. */
+	/* Each call takes low-order 24 bits and stores 4 chars */
+	/* bits 31..8 of r0 */
+	to64_msb_first(output + 2, (r0 >> 8));
+	/* bits 7..0 of r0 and 31..16 of r1 */
+	to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16));
+	/* bits 15..0 of r1 and two zero bits (plus extra zero byte) */
+	to64_msb_first(output + 10, (r1 << 8));
+	/* extra zero byte is encoded as '.', fixing it */
+	output[13] = '\0';
+
+	return output;
+}
+
+#undef C
+#undef init_perm
+#undef final_perm
+#undef m_sbox
+#undef D
+#undef const_ctx
+#undef saltbits
+#undef old_salt
+#undef old_rawkey0
+#undef old_rawkey1
+#undef un_pbox
+#undef inv_comp_perm
+#undef inv_key_perm
+#undef en_keysl
+#undef en_keysr
+#undef de_keysl
+#undef de_keysr
+#undef ip_maskl
+#undef ip_maskr
+#undef fp_maskl
+#undef fp_maskr
+#undef key_perm_maskl
+#undef key_perm_maskr
+#undef comp_maskl
+#undef comp_maskr
+#undef psbox
+
+struct crypt_data;
+
+char *__crypt_r(const char *clear, const char *salt, struct crypt_data *data)
+{
+	struct des_ctx des_ctx = { 0 };
+
+#if 0
+	/* MD5 or SHA? */
+	if (salt[0] == '$' && salt[1] && salt[2] == '$') {
+		if (salt[1] == '1')
+			return md5_crypt((char *)data, clear, salt);
+	}
+#endif
+
+	des_init(&des_ctx);
+	return des_crypt(&des_ctx, (char *)data, clear, salt);
+}
+
+weak_alias(__crypt_r, crypt_r);
+
+char *crypt(const char *clear, const char *salt)
+{
+	static char buf[128];
+	return __crypt_r(clear, salt, (void *)buf);
+}
diff --git a/src/misc/cuserid.c b/src/misc/cuserid.c
new file mode 100644
index 00000000..8ad0b9f3
--- /dev/null
+++ b/src/misc/cuserid.c
@@ -0,0 +1,13 @@
+#include <pwd.h>
+#include <stdio.h>
+#include <unistd.h>
+
+char *cuserid(char *buf)
+{
+	struct passwd pw, *ppw;
+	long pwb[256];
+	if (getpwuid_r(geteuid(), &pw, (void *)pwb, sizeof pwb, &ppw))
+		return 0;
+	snprintf(buf, L_cuserid, "%s", pw.pw_name);
+	return buf;
+}
diff --git a/src/misc/dirname.c b/src/misc/dirname.c
new file mode 100644
index 00000000..8f70dbb1
--- /dev/null
+++ b/src/misc/dirname.c
@@ -0,0 +1,15 @@
+#include <string.h>
+#include <libgen.h>
+
+char *dirname(char *s)
+{
+	size_t i;
+	if (!s || !*s || !strchr(s, '/')) return ".";
+	i = strlen(s)-1;
+	for (; i&&s[i]=='/'; i--);
+	for (; i&&s[i-1]!='/'; i--);
+	for (; i&&s[i-1]=='/'; i--);
+	if (!i && *s=='/') i++;
+	s[i] = 0;
+	return s;
+}
diff --git a/src/misc/ffs.c b/src/misc/ffs.c
new file mode 100644
index 00000000..2f7cb321
--- /dev/null
+++ b/src/misc/ffs.c
@@ -0,0 +1,9 @@
+#include <strings.h>
+
+int ffs(int i)
+{
+	unsigned int j = i;
+	for (i=1; j && !(j&1); j>>=1, i++);
+	if (j) return i;
+	return 0;
+}
diff --git a/src/misc/ftw.c b/src/misc/ftw.c
new file mode 100644
index 00000000..de01e39c
--- /dev/null
+++ b/src/misc/ftw.c
@@ -0,0 +1,9 @@
+#include <ftw.h>
+#include "libc.h"
+
+int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int fd_limit)
+{
+	return nftw(path, (void *)fn, fd_limit, FTW_PHYS);
+}
+
+LFS64(ftw);
diff --git a/src/misc/getdomainname.c b/src/misc/getdomainname.c
new file mode 100644
index 00000000..7eb113d7
--- /dev/null
+++ b/src/misc/getdomainname.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <string.h>
+
+int getdomainname(char *name, size_t len)
+{
+	*name = 0;
+	return 0;
+}
diff --git a/src/misc/getgrouplist.c b/src/misc/getgrouplist.c
new file mode 100644
index 00000000..88f273d7
--- /dev/null
+++ b/src/misc/getgrouplist.c
@@ -0,0 +1,11 @@
+#include <grp.h>
+
+/* FIXME */
+
+int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups)
+{
+	if (*ngroups<1) return -1;
+	*groups = gid;
+	*ngroups = 1;
+	return 0;
+}
diff --git a/src/misc/getopt.c b/src/misc/getopt.c
new file mode 100644
index 00000000..abf0e847
--- /dev/null
+++ b/src/misc/getopt.c
@@ -0,0 +1,63 @@
+#include <unistd.h>
+#include <wchar.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+
+char *optarg;
+int optind=1, opterr=1, optopt;
+static int optpos;
+
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+	int i;
+	wchar_t c, d;
+	int k, l;
+	char *optchar;
+
+	if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1])
+		return -1;
+	if (argv[optind][1] == '-' && !argv[optind][2])
+		return optind++, -1;
+
+	if (!optpos) optpos++;
+	if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
+		k = 1;
+		c = 0xfffd; /* replacement char */
+	}
+	optchar = argv[optind]+optpos;
+	optopt = c;
+	optpos += k;
+
+	if (!argv[optind][optpos]) {
+		optind++;
+		optpos = 0;
+	}
+
+	for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1);
+
+	if (d != c) {
+		if (optstring[0] != ':' && opterr) {
+			write(2, argv[0], strlen(argv[0]));
+			write(2, ": illegal option: ", 18);
+			write(2, optchar, k);
+			write(2, "\n", 1);
+		}
+		return '?';
+	}
+	if (optstring[i+1] == ':') {
+		if (optind >= argc) {
+			if (optstring[0] == ':') return ':';
+			if (opterr) {
+				write(2, argv[0], strlen(argv[0]));
+				write(2, ": option requires an argument: ", 31);
+				write(2, optchar, k);
+				write(2, "\n", 1);
+			}
+			return '?';
+		}
+		optarg = argv[optind++] + optpos;
+		optpos = 0;
+	}
+	return c;
+}
diff --git a/src/misc/getpriority.c b/src/misc/getpriority.c
new file mode 100644
index 00000000..2fb26b2b
--- /dev/null
+++ b/src/misc/getpriority.c
@@ -0,0 +1,9 @@
+#include <sys/resource.h>
+#include "syscall.h"
+
+int getpriority(int which, id_t who)
+{
+	int ret = syscall2(__NR_getpriority, which, who);
+	if (ret < 0) return ret;
+	return 20-ret;
+}
diff --git a/src/misc/getrlimit.c b/src/misc/getrlimit.c
new file mode 100644
index 00000000..db25943b
--- /dev/null
+++ b/src/misc/getrlimit.c
@@ -0,0 +1,15 @@
+#include <sys/resource.h>
+#include "syscall.h"
+#include "libc.h"
+
+int getrlimit(int resource, struct rlimit *rlim)
+{
+	long k_rlim[2];
+	if (syscall2(__NR_ugetrlimit, resource, (long)k_rlim) < 0)
+		return -1;
+	rlim->rlim_cur = k_rlim[0];
+	rlim->rlim_max = k_rlim[1];
+	return 0;
+}
+
+LFS64(getrlimit);
diff --git a/src/misc/getrusage.c b/src/misc/getrusage.c
new file mode 100644
index 00000000..1b8850f9
--- /dev/null
+++ b/src/misc/getrusage.c
@@ -0,0 +1,20 @@
+#include <sys/resource.h>
+#include <string.h>
+#include "syscall.h"
+
+/* this is a huge hack to make up for the kernel's stupid 32bit time_t
+ * without having to recopy the whole rusage structure ourselves.. */
+
+int getrusage(int who, struct rusage *ru)
+{
+	struct { long tv_sec, tv_usec; } ktv[2];
+	char *fakeaddr = ((char *)ru + sizeof(struct timeval [2]) - sizeof ktv);
+	if (syscall2(__NR_getrusage, who, (long)fakeaddr) < 0)
+		return -1;
+	memcpy(ktv, fakeaddr, sizeof ktv);
+	ru->ru_utime.tv_sec  = ktv[0].tv_sec;
+	ru->ru_utime.tv_usec = ktv[0].tv_usec;
+	ru->ru_stime.tv_sec  = ktv[1].tv_sec;
+	ru->ru_stime.tv_usec = ktv[1].tv_usec;
+	return 0;
+}
diff --git a/src/misc/getsubopt.c b/src/misc/getsubopt.c
new file mode 100644
index 00000000..dac9bf9e
--- /dev/null
+++ b/src/misc/getsubopt.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+#include <string.h>
+
+int getsubopt(char **opt, char *const *keys, char **val)
+{
+	char *s = *opt;
+	int i;
+
+	*val = NULL;
+	*opt = strchr(s, ',');
+	if (*opt) *(*opt)++ = 0;
+	else *opt = s + strlen(s);
+
+	for (i=0; keys[i]; i++) {
+		size_t l = strlen(keys[i]);
+		if (strncmp(keys[i], s, l)) continue;
+		if (s[l] == '=')
+			*val = s + l;
+		else if (s[l]) continue;
+		return i;
+	}
+	return -1;
+}
diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c
new file mode 100644
index 00000000..808b7c9c
--- /dev/null
+++ b/src/misc/ioctl.c
@@ -0,0 +1,13 @@
+#include <sys/ioctl.h>
+#include <stdarg.h>
+#include "syscall.h"
+
+int ioctl(int fd, int req, ...)
+{
+	void *arg;
+	va_list ap;
+	va_start(ap, req);
+	arg = va_arg(ap, void *);
+	va_end(ap);
+	return syscall3(__NR_ioctl, fd, req, (long)arg);
+}
diff --git a/src/misc/lockf.c b/src/misc/lockf.c
new file mode 100644
index 00000000..d8f82efd
--- /dev/null
+++ b/src/misc/lockf.c
@@ -0,0 +1,33 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "libc.h"
+
+int lockf(int fd, int op, off_t size)
+{
+	struct flock l = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_CUR,
+		.l_len = size,
+	};
+	switch (op) {
+	case F_TEST:
+		l.l_type = F_RDLCK;
+		if (fcntl(fd, F_GETLK, &l) < 0)
+			return -1;
+		if (l.l_type == F_UNLCK || l.l_pid == getpid())
+			return 0;
+		errno = EACCES;
+		return -1;
+	case F_ULOCK:
+		l.l_type = F_UNLCK;
+	case F_TLOCK:
+		return fcntl(fd, F_SETLK, &l);
+	case F_LOCK:
+		return fcntl(fd, F_SETLKW, &l);
+	}
+	errno = EINVAL;
+	return -1;
+}
+
+LFS64(lockf);
diff --git a/src/misc/nftw.c b/src/misc/nftw.c
new file mode 100644
index 00000000..1b94ac15
--- /dev/null
+++ b/src/misc/nftw.c
@@ -0,0 +1,121 @@
+#include <ftw.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include "libc.h"
+
+struct history
+{
+	struct history *chain;
+	dev_t dev;
+	ino_t ino;
+	int level;
+	int base;
+};
+
+#undef dirfd
+#define dirfd(d) (*(int *)d)
+
+static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags, struct history *h)
+{
+	size_t l = strlen(path), j = l && path[l-1]=='/' ? l-1 : l;
+	struct stat st;
+	struct history new;
+	int type;
+	int r;
+	struct FTW lev;
+	char *name;
+
+	if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {
+		if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))
+			type = FTW_SLN;
+		else if (errno != EACCES) return -1;
+		else type = FTW_NS;
+	} else if (S_ISDIR(st.st_mode)) {
+		if (access(path, R_OK) < 0) type = FTW_DNR;
+		else if (flags & FTW_DEPTH) type = FTW_DP;
+		else type = FTW_D;
+	} else if (S_ISLNK(st.st_mode)) {
+		if (flags & FTW_PHYS) type = FTW_SL;
+		else type = FTW_SLN;
+	} else {
+		type = FTW_F;
+	}
+
+	if ((flags & FTW_MOUNT) && h
+	 && (st.st_dev != h->dev || st.st_ino != h->ino))
+		return 0;
+	
+	new.chain = h;
+	new.dev = st.st_dev;
+	new.ino = st.st_ino;
+	new.level = h ? h->level+1 : 0;
+	new.base = l+1;
+	
+	lev.level = new.level;
+	lev.base = h ? h->base : (name=strrchr(path, '/')) ? name-path : 0;
+
+	if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
+		return r;
+
+	for (; h; h = h->chain)
+		if (h->dev == st.st_dev && h->ino == st.st_ino)
+			return 0;
+
+	if ((type == FTW_D || type == FTW_DP) && fd_limit) {
+		DIR *d = opendir(path);
+		if (d) {
+			struct dirent *de;
+			while ((de = readdir(d))) {
+				if (de->d_name[0] == '.'
+				 && (!de->d_name[1]
+				  || (de->d_name[1]=='.'
+				   && !de->d_name[2]))) continue;
+				if (strlen(de->d_name) >= PATH_MAX-l) {
+					errno = ENAMETOOLONG;
+					closedir(d);
+					return -1;
+				}
+				path[j]='/';
+				strcpy(path+j+1, de->d_name);
+				if ((r=do_nftw(path, fn, fd_limit-1, flags, &new))) {
+					closedir(d);
+					return r;
+				}
+			}
+			closedir(d);
+		} else if (errno != EACCES) {
+			return -1;
+		}
+	}
+
+	path[l] = 0;
+	if ((flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
+		return r;
+
+	return 0;
+}
+
+int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags)
+{
+	size_t l;
+	char pathbuf[PATH_MAX+1];
+
+	if (fd_limit <= 0) return 0;
+
+	l = strlen(path);
+	if (l > PATH_MAX) {
+		errno = ENAMETOOLONG;
+		return -1;
+	}
+	memcpy(pathbuf, path, l+1);
+	
+	return do_nftw(pathbuf, fn, fd_limit, flags, NULL);
+}
+
+LFS64(nftw);
diff --git a/src/misc/openpty.c b/src/misc/openpty.c
new file mode 100644
index 00000000..0b4eb221
--- /dev/null
+++ b/src/misc/openpty.c
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pty.h>
+#include <stdio.h>
+
+/* Nonstandard, but vastly superior to the standard functions */
+
+int openpty(int *m, int *s, char *name, const struct termios *tio, const struct winsize *ws)
+{
+	int n=0;
+	char buf[20];
+
+	*m = open("/dev/ptmx", O_RDWR|O_NOCTTY);
+	if (!*m) return -1;
+
+	if (ioctl(*m, TIOCSPTLCK, &n) || ioctl (*m, TIOCGPTN, &n)) {
+		close(*m);
+		return -1;
+	}
+
+	if (!name) name = buf;
+	snprintf(name, sizeof buf, "/dev/pts/%d", n);
+	if ((*s = open(name, O_RDWR|O_NOCTTY)) < 0) {
+		close(*m);
+		return -1;
+	}
+
+	if (tio) tcsetattr(*s, TCSANOW, tio);
+	if (ws) ioctl(*s, TIOCSWINSZ, ws);
+
+	return 0;
+}
diff --git a/src/misc/pty.c b/src/misc/pty.c
new file mode 100644
index 00000000..0d25a836
--- /dev/null
+++ b/src/misc/pty.c
@@ -0,0 +1,35 @@
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+int posix_openpt(int flags)
+{
+	return open("/dev/ptmx", flags);
+}
+
+int grantpt(int fd)
+{
+	return 0;
+}
+
+int unlockpt(int fd)
+{
+	int unlock = 0;
+	return ioctl(fd, TIOCSPTLCK, &unlock);
+}
+
+char *ptsname(int fd)
+{
+	static char buf[9 + sizeof(int)*3 + 1];
+	char *s = buf+sizeof(buf)-1;
+	int pty;
+	if (ioctl (fd, TIOCGPTN, &pty))
+		return NULL;
+	if (pty) for (; pty; pty/=10) *--s = '0' + pty%10;
+	else *--s = '0';
+	s -= 9;
+        s[0] = '/'; s[1] = 'd'; s[2] = 'e'; s[3] = 'v';
+	s[4] = '/'; s[5] = 'p'; s[6] = 't'; s[7] = 's'; s[8] = '/';
+	return s;
+}
diff --git a/src/misc/realpath.c b/src/misc/realpath.c
new file mode 100644
index 00000000..f6b55495
--- /dev/null
+++ b/src/misc/realpath.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+char *realpath(const char *filename, char *resolved)
+{
+	return 0;
+}
diff --git a/src/misc/sched_yield.c b/src/misc/sched_yield.c
new file mode 100644
index 00000000..8a68519e
--- /dev/null
+++ b/src/misc/sched_yield.c
@@ -0,0 +1,10 @@
+#include <sched.h>
+#include "syscall.h"
+#include "libc.h"
+
+int __yield()
+{
+	return syscall0(__NR_sched_yield);
+}
+
+weak_alias(__yield, sched_yield);
diff --git a/src/misc/setpriority.c b/src/misc/setpriority.c
new file mode 100644
index 00000000..26da4b83
--- /dev/null
+++ b/src/misc/setpriority.c
@@ -0,0 +1,7 @@
+#include <sys/resource.h>
+#include "syscall.h"
+
+int setpriority(int which, id_t who, int prio)
+{
+	return syscall3(__NR_getpriority, which, who, prio);
+}
diff --git a/src/misc/setrlimit.c b/src/misc/setrlimit.c
new file mode 100644
index 00000000..7fdfc4e5
--- /dev/null
+++ b/src/misc/setrlimit.c
@@ -0,0 +1,11 @@
+#include <sys/resource.h>
+#include "syscall.h"
+#include "libc.h"
+
+int setrlimit(int resource, const struct rlimit *rlim)
+{
+	long k_rlim[2] = { rlim->rlim_cur, rlim->rlim_max };
+	return syscall2(__NR_setrlimit, resource, (long)k_rlim);
+}
+
+LFS64(setrlimit);
diff --git a/src/misc/syslog.c b/src/misc/syslog.c
new file mode 100644
index 00000000..4809d2da
--- /dev/null
+++ b/src/misc/syslog.c
@@ -0,0 +1,115 @@
+#include <stdarg.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <time.h>
+#include <signal.h>
+#include <string.h>
+#include "libc.h"
+
+static int lock;
+static const char *log_ident;
+static int log_opt;
+static int log_facility = LOG_USER;
+static int log_mask = 0xff;
+static FILE *log_f;
+
+int setlogmask(int maskpri)
+{
+	int old = log_mask;
+	if (maskpri) log_mask = maskpri;
+	return old;
+}
+
+static const struct {
+	short sun_family;
+	char sun_path[9];
+} log_addr = {
+	AF_UNIX,
+	"/dev/log"
+};
+
+void closelog(void)
+{
+	LOCK(&lock);
+	if (log_f) fclose(log_f);
+	log_f = NULL;
+	UNLOCK(&lock);
+}
+
+static void __openlog(const char *ident, int opt, int facility)
+{
+	int fd;
+
+	log_ident = ident;
+	log_opt = opt;
+	log_facility = facility;
+
+	if (!(opt & LOG_NDELAY) || log_f) return;
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	fcntl(fd, F_SETFD, FD_CLOEXEC);
+	if (connect(fd, (void *)&log_addr, sizeof(short) + sizeof "/dev/log") < 0)
+		close(fd);
+	else log_f = fdopen(fd, "wb");
+}
+
+void openlog(const char *ident, int opt, int facility)
+{
+	LOCK(&lock);
+	__openlog(ident, opt, facility);
+	UNLOCK(&lock);
+}
+
+void syslog(int priority, const char *message, ...)
+{
+	struct sigaction sa;
+	va_list ap;
+	char timebuf[16];
+	time_t now;
+	struct tm tm;
+	//const char *fmt, *ident, *sep;
+	//int i;
+
+	if (!(log_mask & LOG_MASK(priority&7)) || (priority&~0x3ff)) return;
+
+	LOCK(&lock);
+
+	if (!log_f) __openlog(log_ident, log_opt | LOG_NDELAY, log_facility);
+	if (!log_f) {
+		UNLOCK(&lock);
+		return;
+	}
+
+	memset(&sa, 0, sizeof sa);
+	sa.sa_handler = SIG_IGN;
+	if (sigaction(SIGPIPE, &sa, &sa) < 0) {
+		// we must abandon logging or we might cause SIGPIPE
+		UNLOCK(&lock);
+		return;
+	}
+
+	now = time(NULL);
+	gmtime_r(&now, &tm);
+	strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
+
+	fprintf(log_f, "<%d>%s ", priority, timebuf);
+	if (log_ident) fprintf(log_f, "%s", log_ident);
+	if (log_opt & LOG_PID) fprintf(log_f, "[%d]", getpid());
+	if (log_ident) fprintf(log_f, ": ");
+
+	va_start(ap, message);
+	vfprintf(log_f, message, ap);
+	va_end(ap);
+	fputc(0, log_f);
+	fflush(log_f);
+
+	// Note: LOG_CONS is not supported because it is annoying!!
+	// syslogd will send messages to console if it deems them appropriate!
+
+	sigaction(SIGPIPE, &sa, NULL);
+
+	UNLOCK(&lock);
+}
diff --git a/src/misc/uname.c b/src/misc/uname.c
new file mode 100644
index 00000000..fbe86643
--- /dev/null
+++ b/src/misc/uname.c
@@ -0,0 +1,8 @@
+#include <sys/utsname.h>
+#include <string.h>
+#include "syscall.h"
+
+int uname(struct utsname *uts)
+{
+	return syscall1(__NR_uname, (long)uts);
+}
diff --git a/src/mman/madvise.c b/src/mman/madvise.c
new file mode 100644
index 00000000..f03647ca
--- /dev/null
+++ b/src/mman/madvise.c
@@ -0,0 +1,10 @@
+#include <sys/mman.h>
+#include "syscall.h"
+#include "libc.h"
+
+int __madvise(void *addr, size_t len, int advice)
+{
+	return syscall3(__NR_madvise, (long)addr, len, advice);
+}
+
+weak_alias(__madvise, madvise);
diff --git a/src/mman/mlock.c b/src/mman/mlock.c
new file mode 100644
index 00000000..3c7c653c
--- /dev/null
+++ b/src/mman/mlock.c
@@ -0,0 +1,7 @@
+#include <sys/mman.h>
+#include "syscall.h"
+
+int mlock(const void *addr, size_t len)
+{
+	return syscall2(__NR_mlock, (long)addr, len);
+}
diff --git a/src/mman/mlockall.c b/src/mman/mlockall.c
new file mode 100644
index 00000000..782fc9db
--- /dev/null
+++ b/src/mman/mlockall.c
@@ -0,0 +1,7 @@
+#include <sys/mman.h>
+#include "syscall.h"
+
+int mlockall(int flags)
+{
+	return syscall1(__NR_mlockall, flags);
+}
diff --git a/src/mman/mmap.c b/src/mman/mmap.c
new file mode 100644
index 00000000..93c76582
--- /dev/null
+++ b/src/mman/mmap.c
@@ -0,0 +1,18 @@
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <limits.h>
+#include "syscall.h"
+#include "libc.h"
+
+void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
+{
+	if (sizeof(off_t) > sizeof(long))
+		if (((long)off & 0xfff) | ((long)((unsigned long long)off>>(12 + 8*(sizeof(off_t)-sizeof(long))))))
+			start = (void *)-1;
+	return (void *)syscall6(__NR_mmap2, (long)start, len, prot, flags, fd, off>>12);
+}
+
+weak_alias(__mmap, mmap);
+
+LFS64(mmap);
diff --git a/src/mman/mprotect.c b/src/mman/mprotect.c
new file mode 100644
index 00000000..11d5e231
--- /dev/null
+++ b/src/mman/mprotect.c
@@ -0,0 +1,7 @@
+#include <sys/mman.h>
+#include "syscall.h"
+
+int mprotect(void *addr, size_t len, int prot)
+{
+	return syscall3(__NR_mprotect, (long)addr, len, prot);
+}
diff --git a/src/mman/mremap.c b/src/mman/mremap.c
new file mode 100644
index 00000000..78491ef4
--- /dev/null
+++ b/src/mman/mremap.c
@@ -0,0 +1,19 @@
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include "syscall.h"
+#include "libc.h"
+
+void *__mremap(void *old_addr, size_t old_len, size_t new_len, int flags, ...)
+{
+	va_list ap;
+	void *new_addr;
+	
+	va_start(ap, flags);
+	new_addr = va_arg(ap, void *);
+	va_end(ap);
+
+	return (void *)syscall5(__NR_mremap, (long)old_addr, old_len, new_len, flags, (long)new_addr);
+}
+
+weak_alias(__mremap, mremap);
diff --git a/src/mman/msync.c b/src/mman/msync.c
new file mode 100644
index 00000000..e0926470
--- /dev/null
+++ b/src/mman/msync.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <sys/mman.h>
+#include "syscall.h"
+
+int msync(void *start, size_t len, int flags)
+{
+	return syscall3(__NR_msync, (long)start, len, flags);
+}
diff --git a/src/mman/munlock.c b/src/mman/munlock.c
new file mode 100644
index 00000000..0db59815
--- /dev/null
+++ b/src/mman/munlock.c
@@ -0,0 +1,7 @@
+#include <sys/mman.h>
+#include "syscall.h"
+
+int munlock(const void *addr, size_t len)
+{
+	return syscall2(__NR_munlock, (long)addr, len);
+}
diff --git a/src/mman/munlockall.c b/src/mman/munlockall.c
new file mode 100644
index 00000000..ce3e86cc
--- /dev/null
+++ b/src/mman/munlockall.c
@@ -0,0 +1,7 @@
+#include <sys/mman.h>
+#include "syscall.h"
+
+int munlockall(void)
+{
+	return syscall0(__NR_munlockall);
+}
diff --git a/src/mman/munmap.c b/src/mman/munmap.c
new file mode 100644
index 00000000..c9661cda
--- /dev/null
+++ b/src/mman/munmap.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <sys/mman.h>
+#include "syscall.h"
+#include "libc.h"
+
+int __munmap(void *start, size_t len)
+{
+	return syscall2(__NR_munmap, (long)start, len);
+}
+
+weak_alias(__munmap, munmap);
diff --git a/src/mman/posix_madvise.c b/src/mman/posix_madvise.c
new file mode 100644
index 00000000..4727ad75
--- /dev/null
+++ b/src/mman/posix_madvise.c
@@ -0,0 +1,6 @@
+#include <sys/mman.h>
+
+int posix_madvise(void *addr, size_t len, int advice)
+{
+	return 0;
+}
diff --git a/src/multibyte/btowc.c b/src/multibyte/btowc.c
new file mode 100644
index 00000000..9d2c3b16
--- /dev/null
+++ b/src/multibyte/btowc.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <wchar.h>
+
+wint_t btowc(int c)
+{
+	return c<128U ? c : EOF;
+}
diff --git a/src/multibyte/decode.c b/src/multibyte/decode.c
new file mode 100644
index 00000000..8d3d3c0b
--- /dev/null
+++ b/src/multibyte/decode.c
@@ -0,0 +1,47 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+/* Decodes UTF-8 byte-by-byte. The c argument must be initialized to 0
+ * to begin decoding; when finished it will contain the Unicode scalar
+ * value decoded. Return value is 1 if finished, 0 if in-progress, and
+ * -1 if an invalid sequence was encountered. After an invalid sequence,
+ * the state (in c) automatically resets to 0 if a continuation byte was
+ * expected to facilitate a calling idiom of immediately retrying a
+ * failed decode call after processing the invalid sequence. If the
+ * second try fails, the byte is invalid as a starter as well.
+ *
+ * A trivial usage idiom is:
+ *       while (src<end && (n=decode(dst, *src))>=0) 1[dst+=n]=0, src++;
+ */
+
+int decode(unsigned *c, unsigned b)
+{
+	if (!*c) {
+		if (b < 0x80) {
+			*c = b;
+			return 1;
+		} else if (b-SA >= SB-SA) {
+			*c = FAILSTATE;
+			return -1;
+		}
+		*c = bittab[b-SA];
+		return 0;
+	}
+
+	if (OOB(*c,b)) {
+		*c = 0;
+		return -1;
+	}
+	*c = *c<<6 | b-0x80;
+	return !(*c&(1U<<31));
+}
diff --git a/src/multibyte/internal.c b/src/multibyte/internal.c
new file mode 100644
index 00000000..e9b938dd
--- /dev/null
+++ b/src/multibyte/internal.c
@@ -0,0 +1,60 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <inttypes.h>
+
+#include "internal.h"
+
+#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) )
+#define D(x) C((x+16))
+#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \
+                 x==0xd ? R(0x80,0xa0) : \
+                 R(0x80,0xc0) ) \
+             | ( R(0x80,0xc0) >> 6 ) \
+             | x )
+#ifdef I_FAILED_TO_RTFM_RFC3629
+#define F0(x) (( x==0 ? R(0x90,0xc0) : \
+                 R(0x80,0xc0) ) \
+             | ( R(0x80,0xc0) >> 6 ) \
+             | ( R(0x80,0xc0) >> 12 ) \
+             | x )
+#define F8(x) (( x==0 ? R(0xa0,0xc0) : \
+                 R(0x80,0xc0) ) \
+             | ( R(0x80,0xc0) >> 6 ) \
+             | ( R(0x80,0xc0) >> 12 ) \
+             | ( R(0x80,0xc0) >> 18 ) \
+             | x )
+#define FC(x) (( x==0 ? R(0x88,0xc0) : \
+                 R(0x80,0xc0) ) \
+             | ( R(0x80,0xc0) >> 6 ) \
+             | ( R(0x80,0xc0) >> 12 ) \
+             | ( R(0x80,0xc0) >> 18 ) \
+             | ( R(0x80,0xc0) >> 24 ) \
+             | x )
+#define F(x) ( x<8 ? F0(x) : x<12 ? F8((x&3)) : x<14 ? FC((x&1)) : -1 )
+#else
+#define F(x) ( ( x>=5 ? 0 : \
+                 x==0 ? R(0x90,0xc0) : \
+                 x==4 ? R(0x80,0xa0) : \
+                 R(0x80,0xc0) ) \
+             | ( R(0x80,0xc0) >> 6 ) \
+             | ( R(0x80,0xc0) >> 12 ) \
+             | x )
+#endif
+
+const uint32_t bittab[] = {
+	              C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7),
+	C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf),
+	D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7),
+	D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf),
+	E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7),
+	E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf),
+	F(0x0),F(0x1),F(0x2),F(0x3),F(0x4),
+#ifdef I_FAILED_TO_RTFM_RFC3629
+	                                   F(0x5),F(0x6),F(0x7),
+	F(0x8),F(0x9),F(0xa),F(0xb),F(0xc),F(0xd)
+#endif
+};
diff --git a/src/multibyte/internal.h b/src/multibyte/internal.h
new file mode 100644
index 00000000..427519a2
--- /dev/null
+++ b/src/multibyte/internal.h
@@ -0,0 +1,61 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#define LIBC
+#ifndef LIBC
+/* rename functions not to conflict with libc */
+#ifndef myprefix
+#define myprefix fsmu8_
+#endif
+#define concat2(a,b) a ## b
+#define concat(a,b) concat2(a,b)
+#define prefix(b) concat(myprefix,b)
+
+#undef mblen
+#undef mbrlen
+#undef mbrtowc
+#undef mbsinit
+#undef mbsnrtowcs
+#undef mbsrtowcs
+#undef wcrtomb
+#undef wcsrtombs
+#undef wcstombs
+#undef wctomb
+#define mblen prefix(mblen)
+#define mbrlen prefix(mbrlen)
+#define mbrtowc prefix(mbrtowc)
+#define mbsinit prefix(mbsinit)
+#define mbsnrtowcs prefix(mbsnrtowcs)
+#define mbsrtowcs prefix(mbsrtowcs)
+#define mbstowcs prefix(mbstowcs)
+#define wcrtomb prefix(wcrtomb)
+#define wcsnrtombs prefix(wcsnrtombs)
+#define wcsrtombs prefix(wcsrtombs)
+#define wcstombs prefix(wcstombs)
+#define wctomb prefix(wctomb)
+
+#define bittab prefix(bittab)
+#else
+#define bittab __fsmu8
+#endif
+
+extern const uint32_t bittab[];
+
+/* Upper 6 state bits are a negative integer offset to bound-check next byte */
+/*    equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f      */
+#define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7)
+
+/* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */
+#define R(a,b) ((uint32_t)((a==0x80 ? 0x40-b : -a) << 23))
+#define FAILSTATE R(0x80,0x80)
+
+#ifdef I_FAILED_TO_RTFM_RFC3629
+#define SA 0xc2
+#define SB 0xfe
+#else
+#define SA 0xc2
+#define SB 0xf5
+#endif
diff --git a/src/multibyte/mblen.c b/src/multibyte/mblen.c
new file mode 100644
index 00000000..26d35649
--- /dev/null
+++ b/src/multibyte/mblen.c
@@ -0,0 +1,17 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int mblen(const char *s, size_t n)
+{
+	return mbtowc(0, s, n);
+}
diff --git a/src/multibyte/mbrlen.c b/src/multibyte/mbrlen.c
new file mode 100644
index 00000000..c9a9f033
--- /dev/null
+++ b/src/multibyte/mbrlen.c
@@ -0,0 +1,18 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbrlen(const char *s, size_t n, mbstate_t *st)
+{
+	static unsigned internal;
+	return mbrtowc(0, s, n, st ? st : (mbstate_t *)&internal);
+}
diff --git a/src/multibyte/mbrtowc.c b/src/multibyte/mbrtowc.c
new file mode 100644
index 00000000..09badebe
--- /dev/null
+++ b/src/multibyte/mbrtowc.c
@@ -0,0 +1,58 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbrtowc(wchar_t *wc, const char *src, size_t n, mbstate_t *st)
+{
+	static unsigned internal_state;
+	unsigned c;
+	const unsigned char *s = src;
+	const unsigned N = n;
+
+	if (!st) st = (void *)&internal_state;
+	c = *(unsigned *)st;
+	
+	if (!s) {
+		s = "";
+		wc = (void *)&wc;
+		n = 1;
+	} else if (!wc) wc = (void *)&wc;
+
+	if (!n) return -2;
+	if (!c) {
+		if ((unsigned)*s < 0x80) return !!(*wc = *s);
+		if ((unsigned)*s-SA > SB-SA) goto ilseq;
+		c = bittab[*s++-SA]; n--;
+	}
+
+	if (n) {
+		if (OOB(c,*s)) goto ilseq;
+loop:
+		c = c<<6 | *s++-0x80; n--;
+		if (!(c&(1U<<31))) {
+			*(unsigned *)st = 0;
+			*wc = c;
+			return N-n;
+		}
+		if (n) {
+			if ((unsigned)*s-0x80 >= 0x40) goto ilseq;
+			goto loop;
+		}
+	}
+
+	*(unsigned *)st = c;
+	return -2;
+ilseq:
+	*(unsigned *)st = FAILSTATE;
+	errno = EILSEQ;
+	return -1;
+}
diff --git a/src/multibyte/mbsinit.c b/src/multibyte/mbsinit.c
new file mode 100644
index 00000000..d307e5a7
--- /dev/null
+++ b/src/multibyte/mbsinit.c
@@ -0,0 +1,17 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int mbsinit(const mbstate_t *st)
+{
+	return !*(unsigned *)st;
+}
diff --git a/src/multibyte/mbsnrtowcs.c b/src/multibyte/mbsnrtowcs.c
new file mode 100644
index 00000000..c6f0207f
--- /dev/null
+++ b/src/multibyte/mbsnrtowcs.c
@@ -0,0 +1,61 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "internal.h"
+
+size_t mbsnrtowcs(wchar_t *wcs, const char **src, size_t n, size_t wn, mbstate_t *st)
+{
+	size_t l, cnt=0, n2;
+	wchar_t *ws, wbuf[256];
+	const char *s = *src;
+
+	if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf;
+	else ws = wcs;
+
+	/* making sure output buffer size is at most n/4 will ensure
+	 * that mbsrtowcs never reads more than n input bytes. thus
+	 * we can use mbsrtowcs as long as it's practical.. */
+
+	while ( s && wn && ( (n2=n/4)>=wn || n2>32 ) ) {
+		if (n2>=wn) n2=wn;
+		n -= n2;
+		l = mbsrtowcs(ws, &s, n2, st);
+		if (!(l+1)) {
+			cnt = l;
+			wn = 0;
+			break;
+		}
+		if (ws != wbuf) {
+			ws += l;
+			wn -= l;
+		}
+		cnt += l;
+	}
+	if (s) while (wn && n) {
+		l = mbrtowc(ws, s, n, st);
+		if (l+2<=2) {
+			if (!(l+1)) {
+				cnt = l;
+				break;
+			}
+			/* have to roll back partial character */
+			*(unsigned *)st = 0;
+			break;
+		}
+		s += l; n -= l;
+		/* safe - this loop runs fewer than sizeof(wbuf)/8 times */
+		ws++; wn--;
+		cnt++;
+	}
+	if (wcs) *src = s;
+	return cnt;
+}
diff --git a/src/multibyte/mbsrtowcs.c b/src/multibyte/mbsrtowcs.c
new file mode 100644
index 00000000..e2b43480
--- /dev/null
+++ b/src/multibyte/mbsrtowcs.c
@@ -0,0 +1,121 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbsrtowcs(wchar_t *ws, const char **src, size_t wn, mbstate_t *st)
+{
+	unsigned c;
+	const unsigned char *s = *src;
+	const wchar_t *wsorig = ws;
+
+	if (!st) st = (void *)&c, c = 0;
+	else c = *(unsigned *)st;
+
+	if (c) {
+		*(unsigned *)st = 0;
+		if (!ws) {
+			wn = 0;
+			goto resume0;
+		}
+		goto resume;
+	}
+
+	if (!ws) for (wn=0;;) {
+		if ((unsigned)*s-SA >= SB-SA) {
+			while (((unsigned)s&3) && (unsigned)*s-1<0x7f) s++, wn++;
+			while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) s+=4, wn+=4;
+			while ((unsigned)*s-1<0x7f) s++, wn++;
+			if (!*s) return wn;
+			if ((unsigned)*s-SA >= SB-SA) goto ilseq2;
+		}
+		c = bittab[*s++-SA];
+		do {
+resume0:
+			if (OOB(c,*s)) goto ilseq2; s++;
+			c <<= 6; if (!(c&(1U<<31))) break;
+#ifdef I_FAILED_TO_RTFM_RFC3629
+			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2;
+			c <<= 6; if (!(c&(1U<<31))) break;
+			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2;
+			c <<= 6; if (!(c&(1U<<31))) break;
+#endif
+			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2;
+			c <<= 6; if (!(c&(1U<<31))) break;
+			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2;
+		} while (0);
+		wn++; c = 0;
+	}
+
+	while (wn) {
+		if ((unsigned)*s-SA >= SB-SA) {
+			if (wn >= 7) {
+				while (((unsigned)s&3) && (unsigned)*s-1<0x7f) {
+					*ws++ = *s++;
+					wn--;
+				}
+				while (wn>=4 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
+					*ws++ = *s++;
+					*ws++ = *s++;
+					*ws++ = *s++;
+					*ws++ = *s++;
+					wn -= 4;
+				}
+			}
+			while (wn && (unsigned)*s-1<0x7f) {
+				*ws++ = *s++;
+				wn--;
+			}
+			if (!wn) break;
+			if (!*s) {
+				*ws = 0;
+				*src = 0;
+				return ws-wsorig;
+			}
+			if ((unsigned)*s-SA >= SB-SA) goto ilseq;
+		}
+		c = bittab[*s++-SA];
+		do {
+resume:
+			if (OOB(c,*s)) goto ilseq;
+			c = (c<<6) | *s++-0x80;
+			if (!(c&(1U<<31))) break;
+
+#ifdef I_FAILED_TO_RTFM_RFC3629
+			if ((unsigned)*s-0x80 >= 0x40) goto ilseq;
+			c = (c<<6) | *s++-0x80;
+			if (!(c&(1U<<31))) break;
+
+			if ((unsigned)*s-0x80 >= 0x40) goto ilseq;
+			c = (c<<6) | *s++-0x80;
+			if (!(c&(1U<<31))) break;
+#endif
+
+			if ((unsigned)*s-0x80 >= 0x40) goto ilseq;
+			c = (c<<6) | *s++-0x80;
+			if (!(c&(1U<<31))) break;
+
+			if ((unsigned)*s-0x80 >= 0x40) goto ilseq;
+			c = (c<<6) | *s++-0x80;
+		} while (0);
+
+		*ws++ = c; wn--; c = 0;
+	}
+	*src = s;
+	return ws-wsorig;
+ilseq:
+	*src = s;
+ilseq2:
+	/* enter permanently failing state */
+	*(unsigned *)st = FAILSTATE;
+	errno = EILSEQ;
+	return -1;
+}
diff --git a/src/multibyte/mbstowcs.c b/src/multibyte/mbstowcs.c
new file mode 100644
index 00000000..23e1d925
--- /dev/null
+++ b/src/multibyte/mbstowcs.c
@@ -0,0 +1,18 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t mbstowcs(wchar_t *ws, const char *s, size_t wn)
+{
+	mbstate_t st = { 0 };
+	return mbsrtowcs(ws, (void*)&s, wn, &st);
+}
diff --git a/src/multibyte/mbtowc.c b/src/multibyte/mbtowc.c
new file mode 100644
index 00000000..bdcaeb3c
--- /dev/null
+++ b/src/multibyte/mbtowc.c
@@ -0,0 +1,19 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int mbtowc(wchar_t *wc, const char *s, size_t n)
+{
+	mbstate_t st = { 0 };
+	n = mbrtowc(wc, s, n, &st);
+	return n+2 ? n : -1;
+}
diff --git a/src/multibyte/wcrtomb.c b/src/multibyte/wcrtomb.c
new file mode 100644
index 00000000..36180c8f
--- /dev/null
+++ b/src/multibyte/wcrtomb.c
@@ -0,0 +1,38 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcrtomb(char *s, wchar_t wc, mbstate_t *st)
+{
+	if (!s) return 1;
+	if ((unsigned)wc < 0x80) {
+		*s = wc;
+		return 1;
+	} else if ((unsigned)wc < 0x800) {
+		*s++ = 0xc0 | (wc>>6);
+		*s = 0x80 | (wc&0x3f);
+		return 2;
+	} else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) {
+		*s++ = 0xe0 | (wc>>12);
+		*s++ = 0x80 | ((wc>>6)&0x3f);
+		*s = 0x80 | (wc&0x3f);
+		return 3;
+	} else if ((unsigned)wc-0x10000 < 0x100000) {
+		*s++ = 0xf0 | (wc>>18);
+		*s++ = 0x80 | ((wc>>12)&0x3f);
+		*s++ = 0x80 | ((wc>>6)&0x3f);
+		*s = 0x80 | (wc&0x3f);
+		return 4;
+	}
+	errno = EILSEQ;
+	return -1;
+}
diff --git a/src/multibyte/wcsnrtombs.c b/src/multibyte/wcsnrtombs.c
new file mode 100644
index 00000000..666f6f3f
--- /dev/null
+++ b/src/multibyte/wcsnrtombs.c
@@ -0,0 +1,51 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcsnrtombs(char *dst, const wchar_t **wcs, size_t wn, size_t n, mbstate_t *st)
+{
+	size_t l, cnt=0, n2;
+	char *s, buf[256];
+	const wchar_t *ws = *wcs;
+
+	if (!dst) s = buf, n = sizeof buf;
+	else s = dst;
+
+	while ( n && ( (n2=wn)>=n || n2>32 ) ) {
+		if (n2>=n) n2=n;
+		wn -= n2;
+		l = wcsrtombs(s, &ws, n2, 0);
+		if (!(l+1)) {
+			cnt = l;
+			n = 0;
+			break;
+		}
+		if (s != buf) {
+			s += l;
+			n -= l;
+		}
+		cnt += l;
+	}
+	while (n && wn) {
+		l = wcrtomb(s, *ws, 0);
+		if (!(l+1)) {
+			cnt = l;
+			break;
+		}
+		ws++; wn--;
+		/* safe - this loop runs fewer than sizeof(buf) times */
+		s+=l; n-=l;
+		cnt++;
+	}
+	if (dst) *wcs = ws;
+	return cnt;
+}
diff --git a/src/multibyte/wcsrtombs.c b/src/multibyte/wcsrtombs.c
new file mode 100644
index 00000000..3c48d65b
--- /dev/null
+++ b/src/multibyte/wcsrtombs.c
@@ -0,0 +1,58 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcsrtombs(char *s, const wchar_t **ws, size_t n, mbstate_t *st)
+{
+	const wchar_t *ws2;
+	char buf[4];
+	size_t N = n, l;
+	if (!s) {
+		for (n=0, ws2=*ws; *ws2; ws2++) {
+			if (*ws2 >= 0x80) {
+				l = wcrtomb(buf, *ws2, 0);
+				if (!(l+1)) return -1;
+				n += l;
+			} else n++;
+		}
+		return n;
+	}
+	while (n>=4 && **ws) {
+		if (**ws >= 0x80) {
+			l = wcrtomb(s, **ws, 0);
+			if (!(l+1)) return -1;
+			s += l;
+			n -= l;
+		} else {
+			*s++ = **ws;
+			n--;
+		}
+		(*ws)++;
+	}
+	while (n && **ws) {
+		if (**ws >= 0x80) {
+			l = wcrtomb(buf, **ws, 0);
+			if (!(l+1)) return -1;
+			if (l>n) return N-n;
+			wcrtomb(s, **ws, 0);
+			s += l;
+			n -= l;
+		} else {
+			*s++ = **ws;
+			n--;
+		}
+		(*ws)++;
+	}
+	if (n) *s = 0;
+	*ws = 0;
+	return N-n;
+}
diff --git a/src/multibyte/wcstombs.c b/src/multibyte/wcstombs.c
new file mode 100644
index 00000000..b9c1b18a
--- /dev/null
+++ b/src/multibyte/wcstombs.c
@@ -0,0 +1,17 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+size_t wcstombs(char *s, const wchar_t *ws, size_t n)
+{
+	return wcsrtombs(s, &ws, n, 0);
+}
diff --git a/src/multibyte/wctob.c b/src/multibyte/wctob.c
new file mode 100644
index 00000000..d6353ee1
--- /dev/null
+++ b/src/multibyte/wctob.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include <wchar.h>
+
+int wctob(wint_t c)
+{
+	if (c < 128U) return c;
+	return EOF;
+}
diff --git a/src/multibyte/wctomb.c b/src/multibyte/wctomb.c
new file mode 100644
index 00000000..6910ef37
--- /dev/null
+++ b/src/multibyte/wctomb.c
@@ -0,0 +1,18 @@
+/* 
+ * This code was written by Rich Felker in 2010; no copyright is claimed.
+ * This code is in the public domain. Attribution is appreciated but
+ * unnecessary.
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <wchar.h>
+#include <errno.h>
+
+#include "internal.h"
+
+int wctomb(char *s, wchar_t wc)
+{
+	if (!s) return 0;
+	return wcrtomb(s, wc, 0);
+}
diff --git a/src/network/__dns.c b/src/network/__dns.c
new file mode 100644
index 00000000..73ec422d
--- /dev/null
+++ b/src/network/__dns.c
@@ -0,0 +1,267 @@
+#include <stdint.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "__dns.h"
+#include "stdio_impl.h"
+
+#define TIMEOUT 5
+#define RETRY 1
+#define PACKET_MAX 512
+#define PTR_MAX (64 + sizeof ".in-addr.arpa")
+
+int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)
+{
+	time_t t0 = time(0);
+	int fd;
+	FILE *f, _f;
+	unsigned char _buf[64];
+	char line[64], *s, *z;
+	union {
+		struct sockaddr_in sin;
+		struct sockaddr_in6 sin6;
+	} sa = {0}, ns[3] = {{0}};
+	socklen_t sl;
+	int nns;
+	int family;
+	unsigned char q[280] = "", *r = dest;
+	int ql;
+	int rlen;
+	int got = 0, failed = 0;
+	int errcode = EAI_AGAIN;
+	int i, j;
+	struct timeval tv;
+	fd_set fds;
+	int id;
+
+	/* Construct query template - RR and ID will be filled later */
+	if (strlen(name)-1 >= 254U) return -1;
+	q[2] = q[5] = 1;
+	strcpy(q+13, name);
+	for (i=13; q[i]; i=j+1) {
+		for (j=i; q[j] && q[j] != '.'; j++);
+		if (j-i-1u > 62u) return -1;
+		q[i-1] = j-i;
+	}
+	q[i+3] = 1;
+	ql = i+4;
+
+	/* Make a reasonably unpredictable id */
+	gettimeofday(&tv, 0);
+	id = tv.tv_usec + tv.tv_usec/256 & 0xffff;
+
+	/* Get nameservers from resolv.conf, fallback to localhost */
+	f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
+	if (f) for (nns=0; nns<3 && fgets(line, sizeof line, f); ) {
+		if (strncmp(line, "nameserver", 10) || !isspace(line[10]))
+			continue;
+		for (s=line+11; isspace(*s); s++);
+		for (z=s; *z && !isspace(*z); z++);
+		*z=0;
+		if (__ipparse(ns+nns, family, s) < 0) continue;
+		ns[nns].sin.sin_port = htons(53);
+		family = ns[nns++].sin.sin_family;
+		sl = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+	}
+	if (f) __fclose_ca(f);
+	if (!nns) {
+		ns[0].sin.sin_family = AF_INET;
+		ns[0].sin.sin_port = htons(53);
+		nns=1;
+		sl = sizeof sa.sin;
+	}
+
+	/* Get local address and open/bind a socket */
+	sa.sin.sin_family = family;
+	fd = socket(family, SOCK_DGRAM, 0);
+	if (bind(fd, (void *)&sa, sl) < 0) {
+		close(fd);
+		return -1;
+	}
+	/* Nonblocking to work around Linux UDP select bug */
+	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+	/* Loop until we timeout; break early on success */
+	for (; time(0)-t0 < TIMEOUT; ) {
+
+		/* Query all configured namservers in parallel */
+		for (i=0; i<rrcnt; i++) if (rr[i]) for (j=0; j<nns; j++) {
+			q[0] = id+i >> 8;
+			q[1] = id+i;
+			q[ql-3] = rr[i];
+			sendto(fd, q, ql, MSG_NOSIGNAL, (void *)&ns[j], sl);
+		}
+
+		/* Wait for a response, or until time to retry */
+		FD_ZERO(&fds);
+		FD_SET(fd, &fds);
+		tv.tv_sec = RETRY;
+		tv.tv_usec = 0;
+		if (select(fd+1, &fds, 0, 0, &tv) <= 0) continue;
+
+		/* Process any and all replies */
+		while (got+failed < rrcnt && (rlen = recvfrom(fd, r, 512, 0,
+			(void *)&sa, (socklen_t[1]){sl})) >= 2)
+		{
+			/* Ignore replies from addresses we didn't send to */
+			for (i=0; i<nns; i++) if (!memcmp(ns+i, &sa, sl)) break;
+			if (i==nns) continue;
+
+			/* Compute index of the query from id */
+			i = r[0]*256+r[1] - id & 0xffff;
+			if ((unsigned)i >= rrcnt || !rr[i]) continue;
+
+			/* Interpret the result code */
+			switch (r[3] & 15) {
+			case 0:
+				got++;
+				break;
+			case 3:
+				if (1) errcode = EAI_NONAME; else
+			default:
+				errcode = EAI_FAIL;
+				failed++;
+			}
+
+			/* Mark this record as answered */
+			rr[i] = 0;
+			r += 512;
+		}
+
+		/* Check to see if we have answers to all queries */
+		if (got+failed == rrcnt) break;
+	}
+	close(fd);
+
+	/* Return the number of results, or an error code if none */
+	if (got) return got;
+	return errcode;
+}
+
+static void mkptr4(char *s, const unsigned char *ip)
+{
+	sprintf(s, "%d.%d.%d.%d.in-addr.arpa",
+		ip[3], ip[2], ip[1], ip[0]);
+}
+
+static void mkptr6(char *s, const unsigned char *ip)
+{
+	static const char xdigits[] = "0123456789abcdef";
+	int i;
+	for (i=15; i>=0; i--) {
+		*s++ = xdigits[ip[i]&15]; *s++ = '.';
+		*s++ = xdigits[ip[i]>>4]; *s++ = '.';
+	}
+	strcpy(s, "ip6.arpa");
+}
+
+int __dns_query(unsigned char *r, const void *a, int family, int ptr)
+{
+	char buf[PTR_MAX];
+	int rr[2], rrcnt = 1;
+
+	if (ptr) {
+		if (family == AF_INET6) mkptr6(buf, a);
+		else mkptr4(buf, a);
+		rr[0] = RR_PTR;
+		a = buf;
+	} else if (family == AF_INET6) {
+		rr[0] = RR_AAAA;
+	} else {
+		rr[0] = RR_A;
+		if (family != AF_INET) rr[rrcnt++] = RR_AAAA;
+	}
+
+	return __dns_doqueries(r, a, rr, rrcnt);
+}
+
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+static int decname(char *s, const unsigned char *b, const unsigned char *p)
+{
+	/* Remember jump destinations to detect loops and abort */
+	size_t seen[PACKET_MAX/8/sizeof(size_t)] = { 0 };
+	char *sz = s + HOST_NAME_MAX;
+	const unsigned char *pz = b+512;
+	for (;;) {
+		if (p>=pz) return -1;
+		else if (*p&0xc0) {
+			int j = (p[0]&1) | p[1];
+			if (BITOP(seen, j, &)) return -1;
+			BITOP(seen, j, |=);
+			p = b + j;
+		} else if (*p) {
+			if (p+*p+1>=pz || s+*p>=sz) return -1;
+			memcpy(s, p+1, *p);
+			s += *p+1;
+			p += *p+1;
+			s[-1] = *p ? '.' : 0;
+		} else return 0;
+	}
+}
+
+int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const unsigned char *r, int rr, int dec)
+{
+	int qdcount, ancount;
+	const unsigned char *p;
+	char tmp[256];
+	int found = 0;
+	int len;
+
+	if ((r[3]&15)) return 0;
+	p = r+12;
+	qdcount = r[4]*256 + r[5];
+	ancount = r[6]*256 + r[7];
+	if (qdcount+ancount > 64) return -1;
+	while (qdcount--) {
+		while (p-r < 512 && *p-1U < 127) p++;
+		if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
+			return -1;
+		p += 5 + !!*p;
+	}
+	while (ancount--) {
+		while (p-r < 512 && *p-1U < 127) p++;
+		if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
+			return -1;
+		p += 1 + !!*p;
+		len = p[8]*256 + p[9];
+		if (p+len > r+512) return -1;
+		if (p[1]==rr && len <= maxlen) {
+			if (dec && decname(tmp, r, p+10)<0) return -1;
+			if (dest && limit) {
+				if (dec) strcpy(dest, tmp);
+				else memcpy(dest, p+10, len);
+				dest = (char *)dest + stride;
+				limit--;
+			}
+			found++;
+		}
+		p += 10 + len;
+	}
+	return found;
+}
+
+int __dns_count_addrs(const unsigned char *r, int cnt)
+{
+	int found=0, res, i;
+	static const int p[2][2] = { { 4, RR_A }, { 16, RR_AAAA } };
+
+	while (cnt--) for (i=0; i<2; i++) {
+		res = __dns_get_rr(0, 0, p[i][0], -1, r, p[i][1], 0);
+		if (res < 0) return res;
+		found += res;
+		r += 512;
+	}
+	return found;
+}
diff --git a/src/network/__dns.h b/src/network/__dns.h
new file mode 100644
index 00000000..9a3f7402
--- /dev/null
+++ b/src/network/__dns.h
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+#define RR_A 1
+#define RR_CNAME 5
+#define RR_PTR 12
+#define RR_AAAA 28
+
+int __dns_count_addrs(const unsigned char *, int);
+int __dns_get_rr(void *, size_t, size_t, size_t, const unsigned char *, int, int);
+
+int __dns_query(unsigned char *, const void *, int, int);
+int __ipparse(void *, int, const char *);
+
+int __dns_doqueries(unsigned char *, const char *, int *, int);
diff --git a/src/network/__ipparse.c b/src/network/__ipparse.c
new file mode 100644
index 00000000..ca9e5890
--- /dev/null
+++ b/src/network/__ipparse.c
@@ -0,0 +1,40 @@
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "__dns.h"
+#include <stdio.h>
+
+int __ipparse(void *dest, int family, const char *s)
+{
+	unsigned char *d = dest;
+	unsigned long a[16] = { 0 };
+	const char *z;
+	int i;
+
+	if (family == AF_INET6) goto not_v4;
+
+	for (i=0; i<4 && *s; i++) {
+		a[i] = strtoul(s, (char **)&z, 0);
+		if (z==s || (*z && *z != '.')) goto not_v4;
+		s=z+1;
+	}
+	switch (i) {
+	case 0:
+		a[1] = a[0] & 0xffffff;
+		a[0] >>= 24;
+	case 1:
+		a[2] = a[1] & 0xffff;
+		a[1] >>= 16;
+	case 2:
+		a[3] = a[2] & 0xff;
+		a[2] >>= 8;
+	}
+	((struct sockaddr_in *)d)->sin_family = AF_INET;
+	d = (void *)&((struct sockaddr_in *)d)->sin_addr;
+	for (i=0; i<4; i++) d[i] = a[i];
+	return 0;
+
+not_v4:
+	return -1;
+}
diff --git a/src/network/accept.c b/src/network/accept.c
new file mode 100644
index 00000000..83704096
--- /dev/null
+++ b/src/network/accept.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+int accept(int fd, struct sockaddr *addr, socklen_t *len)
+{
+	unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len };
+	int ret;
+	CANCELPT_BEGIN;
+	ret = syscall2(__NR_socketcall, SYS_ACCEPT, (long)args);
+	CANCELPT_END;
+	return ret;
+}
diff --git a/src/network/bind.c b/src/network/bind.c
new file mode 100644
index 00000000..3bef382c
--- /dev/null
+++ b/src/network/bind.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int bind(int fd, const struct sockaddr *addr, socklen_t len)
+{
+	unsigned long args[] = { fd, (unsigned long)addr, len };
+	return syscall2(__NR_socketcall, SYS_BIND, (long)args);
+}
diff --git a/src/network/connect.c b/src/network/connect.c
new file mode 100644
index 00000000..6074122e
--- /dev/null
+++ b/src/network/connect.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+int connect(int fd, const struct sockaddr *addr, socklen_t len)
+{
+	unsigned long args[] = { fd, (unsigned long)addr, len };
+	int ret;
+	CANCELPT_BEGIN;
+	ret = syscall2(__NR_socketcall, SYS_CONNECT, (long)args);
+	CANCELPT_END;
+	return ret;
+}
diff --git a/src/network/dn_expand.c b/src/network/dn_expand.c
new file mode 100644
index 00000000..01b449bb
--- /dev/null
+++ b/src/network/dn_expand.c
@@ -0,0 +1,28 @@
+#include <resolv.h>
+#include <string.h>
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+int dn_expand(unsigned char *b, unsigned char *pz, unsigned char *p, unsigned char *s, int outlen)
+{
+	/* Remember jump destinations to detect loops and abort */
+	size_t seen[512/8/sizeof(size_t)] = { 0 };
+	unsigned char *sz = s + outlen;
+	if (pz-b > 512) return -1;
+	for (;;) {
+		if (p>=pz) return -1;
+		else if (*p&0xc0) {
+			int j = (p[0]&1) | p[1];
+			if (BITOP(seen, j, &)) return -1;
+			BITOP(seen, j, |=);
+			p = b + j;
+		} else if (*p) {
+			if (p+*p+1>=pz || s+*p>=sz) return -1;
+			memcpy(s, p+1, *p);
+			s += *p+1;
+			p += *p+1;
+			s[-1] = *p ? '.' : 0;
+		} else return 0;
+	}
+}
diff --git a/src/network/ent.c b/src/network/ent.c
new file mode 100644
index 00000000..4c2f24b5
--- /dev/null
+++ b/src/network/ent.c
@@ -0,0 +1,26 @@
+#include "libc.h"
+
+void sethostent(int x)
+{
+}
+
+void *gethostent()
+{
+	return 0;
+}
+
+void endhostent(void)
+{
+}
+
+weak_alias(sethostent, setnetent);
+weak_alias(gethostent, getnetent);
+weak_alias(endhostent, endnetent);
+
+weak_alias(sethostent, setservent);
+weak_alias(gethostent, getservent);
+weak_alias(endhostent, endservent);
+
+weak_alias(sethostent, setprotoent);
+weak_alias(gethostent, getprotoent);
+weak_alias(endhostent, endprotoent);
diff --git a/src/network/freeaddrinfo.c b/src/network/freeaddrinfo.c
new file mode 100644
index 00000000..df3798ae
--- /dev/null
+++ b/src/network/freeaddrinfo.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+#include <netdb.h>
+
+void freeaddrinfo(struct addrinfo *p)
+{
+	free(p);
+}
diff --git a/src/network/gai_strerror.c b/src/network/gai_strerror.c
new file mode 100644
index 00000000..ea00bed7
--- /dev/null
+++ b/src/network/gai_strerror.c
@@ -0,0 +1,21 @@
+#include <netdb.h>
+
+static const char msgs[] =
+	"Invalid flags\0"
+	"Name does not resolve\0"
+	"Try again\0"
+	"Non-recoverable error\0"
+	"Unrecognized address family or invalid length\0"
+	"Unrecognized socket type\0"
+	"Unrecognized service\0"
+	"Out of memory\0"
+	"System error\0"
+	"Overflow\0"
+	"\0Unknown error";
+
+const char *gai_strerror(int ecode)
+{
+	const char *s;
+	for (s=msgs, ecode++; ecode && *s; ecode++, s++) for (; *s; s++);
+	return *s ? s : s+1;
+}
diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c
new file mode 100644
index 00000000..90e85f6a
--- /dev/null
+++ b/src/network/getaddrinfo.c
@@ -0,0 +1,224 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include "__dns.h"
+#include "stdio_impl.h"
+
+static int is_valid(const char *host)
+{
+	const unsigned char *s;
+	if (strlen(host)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0;
+	for (s=host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
+	return !*s;
+}
+
+#if 0
+static int have_af(int family)
+{
+	struct sockaddr_in6 sin6 = { .sin6_family = family };
+	socklen_t sl = family == AF_INET
+		? sizeof(struct sockaddr_in)
+		: sizeof(struct sockaddr_in6);
+	int sock = socket(family, SOCK_STREAM, 0);
+	int have = !bind(sock, (void *)&sin6, sl);
+	close(sock);
+	return have;
+}
+#endif
+
+#include <stdlib.h>
+#include <netdb.h>
+
+union sa {
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
+};
+
+struct aibuf {
+	struct addrinfo ai;
+	union sa sa;
+};
+
+/* Extra slots needed for storing canonical name */
+#define EXTRA ((256+sizeof(struct aibuf)-1)/sizeof(struct aibuf))
+
+int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint, struct addrinfo **res)
+{
+	int flags = hint ? hint->ai_flags : 0;
+	int family = hint ? hint->ai_family : AF_UNSPEC;
+	int type = hint ? hint->ai_socktype : 0;
+	int proto = hint ? hint->ai_protocol : 0;
+	unsigned long port = 0;
+	struct aibuf *buf;
+	union sa sa = {{0}};
+	unsigned char reply[1024];
+	int i, j;
+	//char hostbuf[256];
+	char line[512];
+	FILE *f, _f;
+	unsigned char _buf[64];
+	char *z;
+	int result;
+	int cnt;
+
+	if (host && strlen(host)>255) return EAI_NONAME;
+	if (serv && strlen(serv)>32) return EAI_SERVICE;
+
+	if (type && !proto)
+		proto = type==SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
+	if (!type && proto)
+		type = proto==IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
+
+	if (serv) {
+		port = strtoul(serv, &z, 0);
+		if (!*z && port > 65535) return EAI_SERVICE;
+		if (!port) {
+			if (flags & AI_NUMERICSERV) return EAI_SERVICE;
+
+			//f = fopen("/etc/services", "rb");
+			return EAI_SERVICE;
+		}
+		port = htons(port);
+	}
+
+	if (!host) {
+		if (family == AF_UNSPEC) family = AF_INET;
+		buf = calloc(sizeof *buf, 1+EXTRA);
+		if (!buf) return EAI_MEMORY;
+		buf->ai.ai_protocol = proto;
+		buf->ai.ai_socktype = type;
+		buf->ai.ai_addr = (void *)&buf->sa;
+		buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+		buf->ai.ai_family = family;
+		buf->sa.sin.sin_family = family;
+		buf->sa.sin.sin_port = port;
+		if (!(flags & AI_PASSIVE)) {
+			if (family == AF_INET) {
+				0[(uint8_t*)&buf->sa.sin.sin_addr.s_addr]=127;
+				3[(uint8_t*)&buf->sa.sin.sin_addr.s_addr]=1;
+			} else buf[0].sa.sin6.sin6_addr.s6_addr[15] = 1;
+		}
+		*res = &buf->ai;
+		return 0;
+	}
+
+	/* Try as a numeric address */
+	if (__ipparse(&sa, family, host) >= 0) {
+		buf = calloc(sizeof *buf, 1+EXTRA);
+		if (!buf) return EAI_MEMORY;
+		family = sa.sin.sin_family;
+		buf->ai.ai_protocol = proto;
+		buf->ai.ai_socktype = type;
+		buf->ai.ai_addr = (void *)&buf->sa;
+		buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+		buf->ai.ai_family = family;
+		buf->sa = sa;
+		buf->sa.sin.sin_port = port;
+		*res = &buf->ai;
+		return 0;
+	}
+
+	if (flags & AI_NUMERICHOST) return EAI_NONAME;
+
+	f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
+	if (f) while (fgets(line, sizeof line, f)) {
+		char *p;
+		size_t l = strlen(host);
+
+		if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+		for(p=line+1; (p=strstr(p, host)) &&
+			(!isspace(p[-1]) || !isspace(p[l])); p++);
+		if (!p) continue;
+		__fclose_ca(f);
+
+		/* Isolate IP address to parse */
+		for (p=line; *p && !isspace(*p); p++);
+		*p++ = 0;
+		if (__ipparse(&sa, family, line) < 0) return EAI_NONAME;
+
+		/* Allocate and fill result buffer */
+		buf = calloc(sizeof *buf, 1+EXTRA);
+		if (!buf) return EAI_MEMORY;
+		family = sa.sin.sin_family;
+		buf->ai.ai_protocol = proto;
+		buf->ai.ai_socktype = type;
+		buf->ai.ai_addr = (void *)&buf->sa;
+		buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+		buf->ai.ai_family = family;
+		buf->sa = sa;
+		buf->sa.sin.sin_port = port;
+
+		/* Extract first name as canonical name */
+		for (; *p && isspace(*p); p++);
+		buf->ai.ai_canonname = (void *)(buf+1);
+		snprintf(buf->ai.ai_canonname, 256, "%s", p);
+		for (p=buf->ai.ai_canonname; *p && !isspace(*p); p++);
+		*p = 0;
+		if (!is_valid(buf->ai.ai_canonname))
+			buf->ai.ai_canonname = 0;
+
+		*res = &buf->ai;
+		return 0;
+	}
+	if (f) __fclose_ca(f);
+
+#if 0
+	f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
+	if (f) while (fgets(line, sizeof line, f)) {
+		if (!isspace(line[10]) || (strncmp(line, "search", 6)
+			&& strncmp(line, "domain", 6))) continue;
+	}
+	if (f) __fclose_ca(f);
+#endif
+
+	/* Perform one or more DNS queries for host */
+	memset(reply, 0, sizeof reply);
+	result = __dns_query(reply, host, family, 0);
+	if (result < 0) return result;
+
+	cnt = __dns_count_addrs(reply, result);
+	if (cnt <= 0) return EAI_NONAME;
+
+	buf = calloc(sizeof *buf, cnt+EXTRA);
+	if (!buf) return EAI_MEMORY;
+
+	i = 0;
+	if (family != AF_INET6) {
+		j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply, RR_A, 0);
+		while (j--) buf[i++].sa.sin.sin_family = AF_INET;
+	}
+	if (family != AF_INET) {
+		j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply, RR_AAAA, 0);
+		while (j--) buf[i++].sa.sin.sin_family = AF_INET6;
+	}
+	if (result>1) {
+		j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply+512, RR_A, 0);
+		while (j--) buf[i++].sa.sin.sin_family = AF_INET;
+		j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply+512, RR_AAAA, 0);
+		while (j--) buf[i++].sa.sin.sin_family = AF_INET6;
+	}
+
+	if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) < 0)
+		strcpy((void *)&buf[cnt], host);
+
+	for (i=0; i<cnt; i++) {
+		buf[i].ai.ai_protocol = proto;
+		buf[i].ai.ai_socktype = type;
+		buf[i].ai.ai_addr = (void *)&buf[i].sa;
+		buf[i].ai.ai_addrlen = buf[i].sa.sin.sin_family==AF_INET6
+			? sizeof sa.sin6 : sizeof sa.sin;
+		buf[i].ai.ai_family = buf[i].sa.sin.sin_family;
+		buf[i].sa.sin.sin_port = port;
+		buf[i].ai.ai_next = &buf[i+1].ai;
+		buf[i].ai.ai_canonname = (void *)&buf[cnt];
+	}
+	buf[cnt-1].ai.ai_next = 0;
+	*res = &buf->ai;
+
+	return 0;
+}
diff --git a/src/network/gethostbyaddr.c b/src/network/gethostbyaddr.c
new file mode 100644
index 00000000..51e1c569
--- /dev/null
+++ b/src/network/gethostbyaddr.c
@@ -0,0 +1,15 @@
+#define _GNU_SOURCE
+
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+
+struct hostent *gethostbyaddr(const void *a, socklen_t l, int af)
+{
+	static struct hostent h;
+	static long buf[512/sizeof(long)];
+	struct hostent *res;
+	if (gethostbyaddr_r(a, l, af, &h,
+		(void *)buf, sizeof buf, &res, &h_errno)) return 0;
+	return &h;
+}
diff --git a/src/network/gethostbyaddr_r.c b/src/network/gethostbyaddr_r.c
new file mode 100644
index 00000000..cdb1d503
--- /dev/null
+++ b/src/network/gethostbyaddr_r.c
@@ -0,0 +1,71 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <inttypes.h>
+
+int gethostbyaddr_r(const void *a, socklen_t l, int af,
+	struct hostent *h, char *buf, size_t buflen,
+	struct hostent **res, int *err)
+{
+	union {
+		struct sockaddr_in sin;
+		struct sockaddr_in6 sin6;
+	} sa = { .sin.sin_family = af };
+	socklen_t sl = af==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+	int i;
+
+	/* Load address argument into sockaddr structure */
+	if (af==AF_INET6 && l==16) memcpy(&sa.sin6.sin6_addr, a, 16);
+	else if (af==AF_INET && l==4) memcpy(&sa.sin.sin_addr, a, 4);
+	else {
+		*err = NO_RECOVERY;
+		return -1;
+	}
+
+	/* Align buffer and check for space for pointers and ip address */
+	i = (uintptr_t)buf & sizeof(char *)-1;
+	if (!i) i = sizeof(char *);
+	if (buflen <= 5*sizeof(char *)-i + l) {
+		errno = ERANGE;
+		return -1;
+	}
+	buf += sizeof(char *)-i;
+	buflen -= 5*sizeof(char *)-i + l;
+
+	h->h_addr_list = (void *)buf;
+	buf += 2*sizeof(char *);
+	h->h_aliases = (void *)buf;
+	buf += 2*sizeof(char *);
+
+	h->h_addr_list[0] = buf;
+	memcpy(h->h_addr_list[0], a, l);
+	buf += l;
+	h->h_addr_list[1] = 0;
+	h->h_aliases[0] = buf;
+	h->h_aliases[1] = 0;
+
+	switch (getnameinfo((void *)&sa, sl, buf, buflen, 0, 0, 0)) {
+	case EAI_AGAIN:
+		*err = TRY_AGAIN;
+		return -1;
+	case EAI_OVERFLOW:
+		errno = ERANGE;
+	default:
+	case EAI_MEMORY:
+	case EAI_SYSTEM:
+	case EAI_FAIL:
+		*err = NO_RECOVERY;
+		return -1;
+	case 0:
+		break;
+	}
+
+	h->h_addrtype = af;
+	h->h_name = h->h_aliases[0];
+	*res = h;
+	return 0;
+}
diff --git a/src/network/gethostbyname.c b/src/network/gethostbyname.c
new file mode 100644
index 00000000..5088a51e
--- /dev/null
+++ b/src/network/gethostbyname.c
@@ -0,0 +1,63 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+
+struct hostent *gethostbyname(const char *name)
+{
+	return gethostbyname2(name, AF_INET);
+}
+
+#if 0
+struct hostent *gethostbyname(const char *name)
+{
+	static struct hostent h;
+	static char *h_aliases[3];
+	static char h_canon[256];
+	static char *h_addr_list[10];
+	static char h_addr_data[10][4];
+	static const struct addrinfo hint = {
+		.ai_family = AF_INET, .ai_flags = AI_CANONNAME
+	};
+	struct addrinfo *ai, *p;
+	int i;
+
+	switch (getaddrinfo(name, 0, &hint, &ai)) {
+	case EAI_NONAME:
+		h_errno = HOST_NOT_FOUND;
+		break;
+	case EAI_AGAIN:
+		h_errno = TRY_AGAIN;
+		break;
+	case EAI_FAIL:
+		h_errno = NO_RECOVERY;
+		break;
+	default:
+	case EAI_MEMORY:
+	case EAI_SYSTEM:
+		h_errno = NO_DATA;
+		break;
+	case 0:
+		break;
+	}
+
+	strcpy(h_canon, ai->ai_canonname);
+	h.h_name = h_canon;
+	h.h_aliases = h_aliases;
+	h.h_aliases[0] = h_canon;
+	h.h_aliases[1] = strcmp(h_canon, name) ? (char *)name : 0;
+	h.h_length = 4;
+	h.h_addr_list = h_addr_list;
+	for (i=0, p=ai; i<sizeof h_addr_data/4 && p; i++, p=p->ai_next) {
+		h.h_addr_list[i] = h_addr_data[i];
+		memcpy(h.h_addr_list[i],
+			&((struct sockaddr_in *)p->ai_addr)->sin_addr, 4);
+	}
+	h.h_addr_list[i] = 0;
+	h.h_addrtype = AF_INET;
+	freeaddrinfo(ai);
+	return &h;
+}
+#endif
diff --git a/src/network/gethostbyname2.c b/src/network/gethostbyname2.c
new file mode 100644
index 00000000..9fbe2647
--- /dev/null
+++ b/src/network/gethostbyname2.c
@@ -0,0 +1,16 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+
+struct hostent *gethostbyname2(const char *name, int af)
+{
+	static struct hostent h;
+	static long buf[512/sizeof(long)];
+	struct hostent *res;
+	if (gethostbyname2_r(name, af, &h,
+		(void *)buf, sizeof buf, &res, &h_errno)) return 0;
+	return &h;
+}
diff --git a/src/network/gethostbyname2_r.c b/src/network/gethostbyname2_r.c
new file mode 100644
index 00000000..c2ed75b4
--- /dev/null
+++ b/src/network/gethostbyname2_r.c
@@ -0,0 +1,99 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <inttypes.h>
+
+int gethostbyname2_r(const char *name, int af,
+	struct hostent *h, char *buf, size_t buflen,
+	struct hostent **res, int *err)
+{
+	struct addrinfo hint = {
+		.ai_family = af==AF_INET6 ? af : AF_INET,
+		.ai_flags = AI_CANONNAME
+	};
+	struct addrinfo *ai, *p;
+	int i;
+	size_t need;
+	const char *canon;
+
+	af = hint.ai_family;
+
+	/* Align buffer */
+	i = (uintptr_t)buf & sizeof(char *)-1;
+	if (i) {
+		if (buflen < sizeof(char *)-i) {
+			errno = ERANGE;
+			return -1;
+		}
+		buf += sizeof(char *)-i;
+		buflen -= sizeof(char *)-i;
+	}
+
+	getaddrinfo(name, 0, &hint, &ai);
+	switch (getaddrinfo(name, 0, &hint, &ai)) {
+	case EAI_NONAME:
+		*err = HOST_NOT_FOUND;
+		return -1;
+	case EAI_AGAIN:
+		*err = TRY_AGAIN;
+		return -1;
+	default:
+	case EAI_MEMORY:
+	case EAI_SYSTEM:
+	case EAI_FAIL:
+		*err = NO_RECOVERY;
+		return -1;
+	case 0:
+		break;
+	}
+
+	h->h_addrtype = af;
+	h->h_length = af==AF_INET6 ? 16 : 4;
+
+	canon = ai->ai_canonname ? ai->ai_canonname : name;
+	need = 4*sizeof(char *);
+	for (i=0, p=ai; p; i++, p=p->ai_next)
+		need += sizeof(char *) + h->h_length;
+	need += strlen(name)+1;
+	need += strlen(canon)+1;
+
+	if (need > buflen) {
+		freeaddrinfo(ai);
+		errno = ERANGE;
+		return -1;
+	}
+
+	h->h_aliases = (void *)buf;
+	buf += 3*sizeof(char *);
+	h->h_addr_list = (void *)buf;
+	buf += (i+1)*sizeof(char *);
+
+	h->h_name = h->h_aliases[0] = buf;
+	strcpy(h->h_name, canon);
+	buf += strlen(h->h_name)+1;
+
+	if (strcmp(h->h_name, name)) {
+		h->h_aliases[1] = buf;
+		strcpy(h->h_aliases[1], name);
+		buf += strlen(h->h_aliases[1])+1;
+	} else h->h_aliases[1] = 0;
+
+	h->h_aliases[2] = 0;
+
+	for (i=0, p=ai; p; i++, p=p->ai_next) {
+		h->h_addr_list[i] = (void *)buf;
+		buf += h->h_length;
+		memcpy(h->h_addr_list[i],
+			&((struct sockaddr_in *)p->ai_addr)->sin_addr,
+			h->h_length);
+	}
+	h->h_addr_list[i] = 0;
+
+	*res = h;
+	freeaddrinfo(ai);
+	return 0;
+}
diff --git a/src/network/gethostbyname_r.c b/src/network/gethostbyname_r.c
new file mode 100644
index 00000000..cd872541
--- /dev/null
+++ b/src/network/gethostbyname_r.c
@@ -0,0 +1,11 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+int gethostbyname_r(const char *name,
+	struct hostent *h, char *buf, size_t buflen,
+	struct hostent **res, int *err)
+{
+	return gethostbyname2_r(name, AF_INET, h, buf, buflen, res, err);
+}
diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
new file mode 100644
index 00000000..0763ca88
--- /dev/null
+++ b/src/network/getnameinfo.c
@@ -0,0 +1,54 @@
+#include <netdb.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "__dns.h"
+
+int getnameinfo(const struct sockaddr *sa, socklen_t sl,
+	char *node, socklen_t nodelen,
+	char *serv, socklen_t servlen,
+	int flags)
+{
+	char buf[256];
+	unsigned char reply[512];
+	int af = sa->sa_family;
+	unsigned char *a;
+
+	switch (af) {
+	case AF_INET:
+		a = (void *)&((struct sockaddr_in *)sa)->sin_addr;
+		if (sl != sizeof(struct sockaddr_in)) return EAI_FAMILY;
+		break;
+	case AF_INET6:
+		a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr;
+		if (sl != sizeof(struct sockaddr_in6)) return EAI_FAMILY;
+		break;
+	default:
+		return EAI_FAMILY;
+	}
+
+	if (node && nodelen) {
+		if ((flags & NI_NUMERICHOST)
+			|| __dns_query(reply, a, af, 1) <= 0
+			|| __dns_get_rr(buf, 0, 256, 1, reply, RR_PTR, 1) <= 0)
+		{
+			if (flags & NI_NAMEREQD) return EAI_NONAME;
+			inet_ntop(af, a, buf, sizeof buf);
+		}
+		if (strlen(buf) >= nodelen) return EAI_OVERFLOW;
+		strcpy(node, buf);
+	}
+
+	if (serv && servlen) {
+		if (snprintf(buf, sizeof buf, "%d",
+			ntohs(((struct sockaddr_in *)sa)->sin_port))>=servlen)
+			return EAI_OVERFLOW;
+		strcpy(serv, buf);
+	}
+
+	return 0;
+}
diff --git a/src/network/getpeername.c b/src/network/getpeername.c
new file mode 100644
index 00000000..7ecbe375
--- /dev/null
+++ b/src/network/getpeername.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int getpeername(int fd, struct sockaddr *addr, socklen_t *len)
+{
+	unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len };
+	return syscall2(__NR_socketcall, SYS_GETPEERNAME, (long)args);
+}
diff --git a/src/network/getservbyname.c b/src/network/getservbyname.c
new file mode 100644
index 00000000..0b00ce11
--- /dev/null
+++ b/src/network/getservbyname.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include <netdb.h>
+
+struct servent *getservbyname(const char *name, const char *prots)
+{
+	static struct servent se;
+	static long buf[32/sizeof(long)];
+	struct servent *res;
+	if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res))
+		return 0;
+	return &se;
+}
diff --git a/src/network/getservbyname_r.c b/src/network/getservbyname_r.c
new file mode 100644
index 00000000..5c025150
--- /dev/null
+++ b/src/network/getservbyname_r.c
@@ -0,0 +1,41 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <string.h>
+
+int getservbyname_r(const char *name, const char *prots,
+	struct servent *se, char *buf, size_t buflen, struct servent **res)
+{
+	struct addrinfo *ai, hint = { .ai_family = AF_INET };
+	int i;
+
+	/* Align buffer */
+	i = (uintptr_t)buf & sizeof(char *)-1;
+	if (!i) i = sizeof(char *);
+	if (buflen < 3*sizeof(char *)-i) {
+		errno = ERANGE;
+		return -1;
+	}
+	buf += sizeof(char *)-i;
+	buflen -= sizeof(char *)-i;
+
+	if (!strcmp(prots, "tcp")) hint.ai_protocol = IPPROTO_TCP;
+	else if (!strcmp(prots, "udp")) hint.ai_protocol = IPPROTO_UDP;
+	else return -1;
+
+	if (getaddrinfo(0, name, &hint, &ai) < 0) return -1;
+
+	se->s_name = (char *)name;
+	se->s_aliases = (void *)buf;
+	se->s_aliases[0] = se->s_name;
+	se->s_aliases[1] = 0;
+	se->s_port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+	se->s_proto = (char *)prots;
+
+	freeaddrinfo(ai);
+	*res = se;
+	return 0;
+}
diff --git a/src/network/getservbyport.c b/src/network/getservbyport.c
new file mode 100644
index 00000000..c9ecbb11
--- /dev/null
+++ b/src/network/getservbyport.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include <netdb.h>
+
+struct servent *getservbyport(int port, const char *prots)
+{
+	static struct servent se;
+	static long buf[32/sizeof(long)];
+	struct servent *res;
+	if (getservbyport_r(port, prots, &se, (void *)buf, sizeof buf, &res))
+		return 0;
+	return &se;
+}
diff --git a/src/network/getservbyport_r.c b/src/network/getservbyport_r.c
new file mode 100644
index 00000000..004a6168
--- /dev/null
+++ b/src/network/getservbyport_r.c
@@ -0,0 +1,43 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <string.h>
+
+int getservbyport_r(int port, const char *prots,
+	struct servent *se, char *buf, size_t buflen, struct servent **res)
+{
+	int i;
+	struct sockaddr_in sin = {
+		.sin_family = AF_INET,
+		.sin_port = port,
+	};
+
+	/* Align buffer */
+	i = (uintptr_t)buf & sizeof(char *)-1;
+	if (!i) i = sizeof(char *);
+	if (buflen < 3*sizeof(char *)-i) {
+		errno = ERANGE;
+		return -1;
+	}
+	buf += sizeof(char *)-i;
+	buflen -= sizeof(char *)-i;
+
+	if (strcmp(prots, "tcp") && strcmp(prots, "udp")) return -1;
+
+	se->s_port = port;
+	se->s_proto = (char *)prots;
+	se->s_aliases = (void *)buf;
+	buf += 2*sizeof(char *);
+	buflen -= 2*sizeof(char *);
+	se->s_aliases[1] = 0;
+	se->s_aliases[0] = se->s_name = buf;
+
+	if (getnameinfo((void *)&sin, sizeof sin, 0, 0, buf, buflen, 
+		strcmp(prots, "udp") ? 0 : NI_DGRAM) < 0) return -1;
+
+	*res = se;
+	return 0;
+}
diff --git a/src/network/getsockname.c b/src/network/getsockname.c
new file mode 100644
index 00000000..4b1002f8
--- /dev/null
+++ b/src/network/getsockname.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int getsockname(int fd, struct sockaddr *addr, socklen_t *len)
+{
+	unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len };
+	return syscall2(__NR_socketcall, SYS_GETSOCKNAME, (long)args);
+}
diff --git a/src/network/getsockopt.c b/src/network/getsockopt.c
new file mode 100644
index 00000000..8c818863
--- /dev/null
+++ b/src/network/getsockopt.c
@@ -0,0 +1,13 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen)
+{
+	unsigned long args[] = {
+		fd, level, optname,
+		(unsigned long)optval,
+		(unsigned long)optlen
+	};
+	return syscall2(__NR_socketcall, SYS_GETSOCKOPT, (long)args);
+}
diff --git a/src/network/h_errno.c b/src/network/h_errno.c
new file mode 100644
index 00000000..73ead046
--- /dev/null
+++ b/src/network/h_errno.c
@@ -0,0 +1 @@
+int h_errno;
diff --git a/src/network/hstrerror.c b/src/network/hstrerror.c
new file mode 100644
index 00000000..b7a6ab6c
--- /dev/null
+++ b/src/network/hstrerror.c
@@ -0,0 +1,16 @@
+#define _GNU_SOURCE
+#include <netdb.h>
+
+static const char msgs[] =
+	"Host not found\0"
+	"Try again\0"
+	"Non-recoverable error\0"
+	"Address not available\0"
+	"\0Unknown error";
+
+const char *hstrerror(int ecode)
+{
+	const char *s;
+	for (s=msgs, ecode--; ecode && *s; ecode--, s++) for (; *s; s++);
+	return *s ? s : s+1;
+}
diff --git a/src/network/htonl.c b/src/network/htonl.c
new file mode 100644
index 00000000..b21dace0
--- /dev/null
+++ b/src/network/htonl.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint32_t htonl(uint32_t n)
+{
+	union {
+		uint8_t b[4];
+		uint32_t i;
+	} u = { { n>>24, n>>16, n>>8, n } };
+	return u.i;
+}
diff --git a/src/network/htons.c b/src/network/htons.c
new file mode 100644
index 00000000..522504a5
--- /dev/null
+++ b/src/network/htons.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint16_t htons(uint16_t n)
+{
+	union {
+		uint8_t b[2];
+		uint16_t s;
+	} u = { { n>>8, n } };
+	return u.s;
+}
diff --git a/src/network/in6addr_any.c b/src/network/in6addr_any.c
new file mode 100644
index 00000000..995387fa
--- /dev/null
+++ b/src/network/in6addr_any.c
@@ -0,0 +1,3 @@
+#include <netinet/in.h>
+
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
diff --git a/src/network/in6addr_loopback.c b/src/network/in6addr_loopback.c
new file mode 100644
index 00000000..b96005b8
--- /dev/null
+++ b/src/network/in6addr_loopback.c
@@ -0,0 +1,3 @@
+#include <netinet/in.h>
+
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
diff --git a/src/network/inet_addr.c b/src/network/inet_addr.c
new file mode 100644
index 00000000..84137281
--- /dev/null
+++ b/src/network/inet_addr.c
@@ -0,0 +1,11 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "__dns.h"
+
+in_addr_t inet_addr(const char *p)
+{
+	struct sockaddr_in sin;
+	if (__ipparse(&sin, AF_INET, p)) return -1;
+	return sin.sin_addr.s_addr;
+}
diff --git a/src/network/inet_aton.c b/src/network/inet_aton.c
new file mode 100644
index 00000000..ea4ee165
--- /dev/null
+++ b/src/network/inet_aton.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+int inet_aton(const char *cp, struct in_addr *inp)
+{
+	return inet_pton(AF_INET, cp, (void *)inp) > 0;
+}
diff --git a/src/network/inet_ntoa.c b/src/network/inet_ntoa.c
new file mode 100644
index 00000000..71411e0b
--- /dev/null
+++ b/src/network/inet_ntoa.c
@@ -0,0 +1,10 @@
+#include <arpa/inet.h>
+#include <stdio.h>
+
+char *inet_ntoa(struct in_addr in)
+{
+	static char buf[16];
+	unsigned char *a = (void *)&in;
+	snprintf(buf, sizeof buf, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
+	return buf;
+}
diff --git a/src/network/inet_ntop.c b/src/network/inet_ntop.c
new file mode 100644
index 00000000..3e8a6db0
--- /dev/null
+++ b/src/network/inet_ntop.c
@@ -0,0 +1,48 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *inet_ntop(int af, const void *a0, char *s, socklen_t l)
+{
+	const unsigned char *a = a0;
+	int i, j, max, best;
+	char buf[100];
+
+	switch (af) {
+	case AF_INET:
+		if (snprintf(s, l, "%d.%d.%d.%d", a[0],a[1],a[2],a[3]) < l)
+			return s;
+		break;
+	case AF_INET6:
+		memset(buf, 'x', sizeof buf);
+		buf[sizeof buf-1]=0;
+		snprintf(buf, sizeof buf, 
+			"%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x",
+			a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],
+			a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]);
+		/* Replace longest /(^0|:)[:0]{2,}/ with "::" */
+		for (i=best=0, max=2; buf[i]; i++) {
+			if (i && buf[i] != ':') continue;
+			j = strspn(buf+i, ":0");
+			if (j>max) best=i, max=j;
+		}
+		if (max>2) {
+			buf[best] = buf[best+1] = ':';
+			strcpy(buf+best+2, buf+best+max);
+		}
+		if (strlen(buf) < l) {
+			strcpy(s, buf);
+			return s;
+		}
+		break;
+	default:
+		errno = EAFNOSUPPORT;
+		return 0;
+	}
+	errno = ENOSPC;
+	return 0;
+}
diff --git a/src/network/inet_pton.c b/src/network/inet_pton.c
new file mode 100644
index 00000000..349c4025
--- /dev/null
+++ b/src/network/inet_pton.c
@@ -0,0 +1,31 @@
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include "__dns.h"
+
+int inet_pton(int af, const char *s, void *a0)
+{
+	unsigned char *a = a0;
+	const char *z;
+	unsigned long x;
+	int i;
+
+	/* Reimplement this because inet_pton cannot accept special v4 forms */
+	if (af==AF_INET) {
+		for (i=0; i<4 && *s; i++) {
+			a[i] = x = strtoul(s, (char **)&z, 10);
+			if (!isdigit(*s) || z==s || (*z && *z != '.') || x>255)
+				return 0;
+			s=z+1;
+		}
+		return 0;
+	} else if (af==AF_INET6) {
+		return !__ipparse(a, AF_INET6, s);
+	}
+
+	errno = EAFNOSUPPORT;
+	return 0;
+}
diff --git a/src/network/listen.c b/src/network/listen.c
new file mode 100644
index 00000000..7c8c1a8a
--- /dev/null
+++ b/src/network/listen.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int listen(int fd, int backlog)
+{
+	unsigned long args[] = { fd, backlog };
+	return syscall2(__NR_socketcall, SYS_LISTEN, (long)args);
+}
diff --git a/src/network/ntohl.c b/src/network/ntohl.c
new file mode 100644
index 00000000..64379196
--- /dev/null
+++ b/src/network/ntohl.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint32_t ntohl(uint32_t n)
+{
+	union {
+		uint32_t i;
+		uint8_t b[4];
+	} u = { n };
+	return (u.b[0]<<24) | (u.b[1]<<16) | (u.b[2]<<8) | u.b[3];
+}
diff --git a/src/network/ntohs.c b/src/network/ntohs.c
new file mode 100644
index 00000000..3544a479
--- /dev/null
+++ b/src/network/ntohs.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint16_t ntohs(uint16_t n)
+{
+	union {
+		uint16_t s;
+		uint8_t b[2];
+	} u = { n };
+	return (u.b[0]<<8) | u.b[1];
+}
diff --git a/src/network/proto.c b/src/network/proto.c
new file mode 100644
index 00000000..8c25c53a
--- /dev/null
+++ b/src/network/proto.c
@@ -0,0 +1,58 @@
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+/* do we really need all these?? */
+
+static int idx;
+static const unsigned char protos[][6] = {
+	"\000ip",
+	"\001icmp",
+	"\002igmp",
+	"\003ggp",
+	"\006tcp",
+	"\014pup",
+	"\021udp",
+	"\026idp",
+	"\377raw"
+	"\0\0"
+};
+
+void endprotoent(void)
+{
+	idx = 0;
+}
+
+void setprotoent(int stayopen)
+{
+	idx = 0;
+}
+
+struct protoent *getprotoent(void)
+{
+	static struct protoent p;
+	static const char *aliases;
+	if (!protos[idx][1]) return NULL;
+	p.p_proto = protos[idx][0];
+	p.p_name = (char *)protos[idx++]+1;
+	p.p_aliases = (char **)&aliases;
+	return &p;
+}
+
+struct protoent *getprotobyname(const char *name)
+{
+	struct protoent *p;
+	endprotoent();
+	do p = getprotoent();
+	while (p && strcmp(name, p->p_name));
+	return p;
+}
+
+struct protoent *getprotobynumber(int num)
+{
+	struct protoent *p;
+	endprotoent();
+	do p = getprotoent();
+	while (p && p->p_proto != num);
+	return p;
+}
diff --git a/src/network/recv.c b/src/network/recv.c
new file mode 100644
index 00000000..521a4b19
--- /dev/null
+++ b/src/network/recv.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t recv(int fd, void *buf, size_t len, int flags)
+{
+	unsigned long args[] = { fd, (unsigned long)buf, len, flags };
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall2(__NR_socketcall, SYS_RECV, (long)args);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/network/recvfrom.c b/src/network/recvfrom.c
new file mode 100644
index 00000000..df50114b
--- /dev/null
+++ b/src/network/recvfrom.c
@@ -0,0 +1,17 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *alen)
+{
+	unsigned long args[] = {
+		fd, (unsigned long)buf, len, flags,
+		(unsigned long)addr, (unsigned long)alen
+	};
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall2(__NR_socketcall, SYS_RECVFROM, (long)args);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/network/recvmsg.c b/src/network/recvmsg.c
new file mode 100644
index 00000000..ead16f9c
--- /dev/null
+++ b/src/network/recvmsg.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
+{
+	unsigned long args[] = { fd, (unsigned long)msg, flags };
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall2(__NR_socketcall, SYS_RECVMSG, (long)args);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/network/res_init.c b/src/network/res_init.c
new file mode 100644
index 00000000..cbd5b155
--- /dev/null
+++ b/src/network/res_init.c
@@ -0,0 +1,4 @@
+int res_init()
+{
+	return 0;
+}
diff --git a/src/network/res_query.c b/src/network/res_query.c
new file mode 100644
index 00000000..4ebeb102
--- /dev/null
+++ b/src/network/res_query.c
@@ -0,0 +1,20 @@
+#include <netdb.h>
+#include "__dns.h"
+
+int res_query(const char *name, int class, int type, unsigned char *dest, int len)
+{
+	if (class != 1 || len < 512)
+		return -1;
+	switch(__dns_doqueries(dest, name, &type, 1)) {
+	case EAI_NONAME:
+		h_errno = HOST_NOT_FOUND;
+		return -1;
+	case EAI_AGAIN:
+		h_errno = TRY_AGAIN;
+		return -1;
+	case EAI_FAIL:
+		h_errno = NO_RECOVERY;
+		return -1;
+	}
+	return 512;
+}
diff --git a/src/network/send.c b/src/network/send.c
new file mode 100644
index 00000000..d72fb03c
--- /dev/null
+++ b/src/network/send.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t send(int fd, const void *buf, size_t len, int flags)
+{
+	unsigned long args[] = { fd, (unsigned long)buf, len, flags };
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall2(__NR_socketcall, SYS_SEND, (long)args);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c
new file mode 100644
index 00000000..ea2fe482
--- /dev/null
+++ b/src/network/sendmsg.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+	unsigned long args[] = { fd, (unsigned long)msg, flags };
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall2(__NR_socketcall, SYS_SENDMSG, (long)args);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/network/sendto.c b/src/network/sendto.c
new file mode 100644
index 00000000..5d224b0b
--- /dev/null
+++ b/src/network/sendto.c
@@ -0,0 +1,17 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t alen)
+{
+	unsigned long args[] = {
+		fd, (unsigned long)buf, len, flags,
+		(unsigned long)addr, alen
+	};
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall2(__NR_socketcall, SYS_SENDTO, (long)args);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/network/serv.c b/src/network/serv.c
new file mode 100644
index 00000000..5ade6ad1
--- /dev/null
+++ b/src/network/serv.c
@@ -0,0 +1,16 @@
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+void endservent(void)
+{
+}
+
+void setservent(int stayopen)
+{
+}
+
+struct servent *getservent(void)
+{
+	return 0;
+}
diff --git a/src/network/setsockopt.c b/src/network/setsockopt.c
new file mode 100644
index 00000000..b50303b8
--- /dev/null
+++ b/src/network/setsockopt.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
+{
+	unsigned long args[] = { fd, level, optname, (unsigned long)optval, optlen };
+	return syscall2(__NR_socketcall, SYS_SETSOCKOPT, (long)args);
+}
diff --git a/src/network/shutdown.c b/src/network/shutdown.c
new file mode 100644
index 00000000..91950c8a
--- /dev/null
+++ b/src/network/shutdown.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int shutdown(int fd, int how)
+{
+	unsigned long args[] = { fd, how };
+	return syscall2(__NR_socketcall, SYS_SHUTDOWN, (long)args);
+}
diff --git a/src/network/sockatmark.c b/src/network/sockatmark.c
new file mode 100644
index 00000000..5328a855
--- /dev/null
+++ b/src/network/sockatmark.c
@@ -0,0 +1,11 @@
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include "socketcall.h"
+
+int sockatmark(int s)
+{
+	int ret;
+	if (ioctl(s, SIOCATMARK, &ret) < 0)
+		return -1;
+	return ret;
+}
diff --git a/src/network/socket.c b/src/network/socket.c
new file mode 100644
index 00000000..afaeb411
--- /dev/null
+++ b/src/network/socket.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int socket(int domain, int type, int protocol)
+{
+	unsigned long args[] = { domain, type, protocol };
+	return syscall2(__NR_socketcall, SYS_SOCKET, (long)args);
+}
diff --git a/src/network/socketcall.h b/src/network/socketcall.h
new file mode 100644
index 00000000..9ae98587
--- /dev/null
+++ b/src/network/socketcall.h
@@ -0,0 +1,24 @@
+#define SYS_SOCKET      1
+#define SYS_BIND        2
+#define SYS_CONNECT     3
+#define SYS_LISTEN      4
+#define SYS_ACCEPT      5
+#define SYS_GETSOCKNAME 6
+#define SYS_GETPEERNAME 7
+#define SYS_SOCKETPAIR  8
+#define SYS_SEND        9
+#define SYS_RECV        10
+#define SYS_SENDTO      11
+#define SYS_RECVFROM    12
+#define SYS_SHUTDOWN    13
+#define SYS_SETSOCKOPT  14
+#define SYS_GETSOCKOPT  15
+#define SYS_SENDMSG     16
+#define SYS_RECVMSG     17
+
+#define FIOSETOWN       0x8901
+#define SIOCSPGRP       0x8902
+#define FIOGETOWN       0x8903
+#define SIOCGPGRP       0x8904
+#define SIOCATMARK      0x8905
+#define SIOCGSTAMP      0x8906
diff --git a/src/network/socketpair.c b/src/network/socketpair.c
new file mode 100644
index 00000000..65a47fd9
--- /dev/null
+++ b/src/network/socketpair.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int socketpair(int domain, int type, int protocol, int fd[2])
+{
+	unsigned long args[] = { domain, type, protocol, (unsigned long)fd };
+	return syscall2(__NR_socketcall, SYS_SOCKETPAIR, (long)args);
+}
diff --git a/src/passwd/getgr_r.c b/src/passwd/getgr_r.c
new file mode 100644
index 00000000..5b1333e3
--- /dev/null
+++ b/src/passwd/getgr_r.c
@@ -0,0 +1,53 @@
+#include "pwf.h"
+
+#define FIX(x) (gr->gr_##x = gr->gr_##x-line+buf)
+
+static int getgr_r(const char *name, gid_t gid, struct group *gr, char *buf, size_t size, struct group **res)
+{
+	FILE *f;
+	char *line = 0;
+	size_t len = 0;
+	char **mem = 0;
+	size_t nmem = 0;
+	int rv = 0;
+	size_t i;
+
+	f = fopen("/etc/group", "rb");
+	if (!f) return errno;
+
+	*res = 0;
+	while (__getgrent_a(f, gr, &line, &len, &mem, &nmem)) {
+		if (name && !strcmp(name, gr->gr_name)
+		|| !name && gr->gr_gid == gid) {
+			if (size < len + nmem*sizeof(char *) + 32) {
+				rv = ERANGE;
+				break;
+			}
+			*res = gr;
+			buf += (16-(uintptr_t)buf)%16;
+			gr->gr_mem = (void *)buf;
+			buf += nmem*sizeof(char *);
+			memcpy(buf, line, len);
+			FIX(name);
+			FIX(passwd);
+			for (i=0; mem[i]; i++)
+				gr->gr_mem[i] = mem[i]-line+buf;
+			gr->gr_mem[i] = 0;
+			break;
+		}
+	}
+ 	free(mem);
+ 	free(line);
+	fclose(f);
+	return rv;
+}
+
+int getgrnam_r(const char *name, struct group *gr, char *buf, size_t size, struct group **res)
+{
+	return getgr_r(name, 0, gr, buf, size, res);
+}
+
+int getgruid_r(gid_t gid, struct group *gr, char *buf, size_t size, struct group **res)
+{
+	return getgr_r(0, gid, gr, buf, size, res);
+}
diff --git a/src/passwd/getgrent.c b/src/passwd/getgrent.c
new file mode 100644
index 00000000..e9d25eba
--- /dev/null
+++ b/src/passwd/getgrent.c
@@ -0,0 +1,39 @@
+#include "pwf.h"
+
+static FILE *f;
+
+void setgrent()
+{
+	if (f) fclose(f);
+	f = 0;
+}
+
+weak_alias(setgrent, endgrent);
+
+struct group *getgrent()
+{
+	static char *line, **mem;
+	static struct group gr;
+	size_t size=0, nmem=0;
+	if (!f) f = fopen("/etc/group", "rb");
+	if (!f) return 0;
+	return __getgrent_a(f, &gr, &line, &size, &mem, &nmem);
+}
+
+struct group *getgrgid(gid_t gid)
+{
+	struct group *gr;
+	setgrent();
+	while ((gr=getgrent()) && gr->gr_gid != gid);
+	endgrent();
+	return gr;
+}
+
+struct group *getgrnam(const char *name)
+{
+	struct group *gr;
+	setgrent();
+	while ((gr=getgrent()) && strcmp(gr->gr_name, name));
+	endgrent();
+	return gr;
+}
diff --git a/src/passwd/getgrent_a.c b/src/passwd/getgrent_a.c
new file mode 100644
index 00000000..ccb51d52
--- /dev/null
+++ b/src/passwd/getgrent_a.c
@@ -0,0 +1,46 @@
+#include "pwf.h"
+
+struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem)
+{
+	ssize_t l;
+	char *s, *mems;
+	size_t i;
+
+	for (;;) {
+		if ((l=getline(line, size, f)) < 0) {
+			free(*line);
+			*line = 0;
+			return 0;
+		}
+		line[0][l-1] = 0;
+
+		s = line[0];
+		gr->gr_name = s++;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; gr->gr_passwd = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; gr->gr_gid = atoi(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; mems = s;
+		break;
+	}
+
+	for (*nmem=!!*s; *s; s++)
+		if (*s==',') ++*nmem;
+	free(*mem);
+	*mem = calloc(sizeof(char *), *nmem+1);
+	if (!*mem) {
+		free(*line);
+		*line = 0;
+		return 0;
+	}
+	mem[0][0] = mems;
+	for (s=mems, i=0; *s; s++)
+		if (*s==',') *s++ = 0, mem[0][++i] = s;
+	mem[0][++i] = 0;
+	gr->gr_mem = *mem;
+	return gr;
+}
diff --git a/src/passwd/getpw_r.c b/src/passwd/getpw_r.c
new file mode 100644
index 00000000..7b331e8a
--- /dev/null
+++ b/src/passwd/getpw_r.c
@@ -0,0 +1,46 @@
+#include "pwf.h"
+
+#define FIX(x) (pw->pw_##x = pw->pw_##x-line+buf)
+
+static int getpw_r(const char *name, uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res)
+{
+	FILE *f;
+	char *line = 0;
+	size_t len = 0;
+	int rv = 0;
+
+	f = fopen("/etc/passwd", "rb");
+	if (!f) return errno;
+
+	*res = 0;
+	while (__getpwent_a(f, pw, &line, &len)) {
+		if (name && !strcmp(name, pw->pw_name)
+		|| !name && pw->pw_uid == uid) {
+			if (size < len) {
+				rv = ERANGE;
+				break;
+			}
+			*res = pw;
+			memcpy(buf, line, len);
+			FIX(name);
+			FIX(passwd);
+			FIX(gecos);
+			FIX(dir);
+			FIX(shell);
+			break;
+		}
+	}
+ 	free(line);
+	fclose(f);
+	return rv;
+}
+
+int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **res)
+{
+	return getpw_r(name, 0, pw, buf, size, res);
+}
+
+int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res)
+{
+	return getpw_r(0, uid, pw, buf, size, res);
+}
diff --git a/src/passwd/getpwent.c b/src/passwd/getpwent.c
new file mode 100644
index 00000000..dabd411a
--- /dev/null
+++ b/src/passwd/getpwent.c
@@ -0,0 +1,39 @@
+#include "pwf.h"
+
+static FILE *f;
+
+void setpwent()
+{
+	if (f) fclose(f);
+	f = 0;
+}
+
+weak_alias(setpwent, endpwent);
+
+struct passwd *getpwent()
+{
+	static char *line;
+	static struct passwd pw;
+	size_t size=0;
+	if (!f) f = fopen("/etc/passwd", "rb");
+	if (!f) return 0;
+	return __getpwent_a(f, &pw, &line, &size);
+}
+
+struct passwd *getpwuid(uid_t uid)
+{
+	struct passwd *pw;
+	setpwent();
+	while ((pw=getpwent()) && pw->pw_uid != uid);
+	endpwent();
+	return pw;
+}
+
+struct passwd *getpwnam(const char *name)
+{
+	struct passwd *pw;
+	setpwent();
+	while ((pw=getpwent()) && strcmp(pw->pw_name, name));
+	endpwent();
+	return pw;
+}
diff --git a/src/passwd/getpwent_a.c b/src/passwd/getpwent_a.c
new file mode 100644
index 00000000..aaf84edd
--- /dev/null
+++ b/src/passwd/getpwent_a.c
@@ -0,0 +1,37 @@
+#include "pwf.h"
+
+struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size)
+{
+	ssize_t l;
+	char *s;
+	for (;;) {
+		if ((l=getline(line, size, f)) < 0) {
+			free(*line);
+			*line = 0;
+			return 0;
+		}
+		line[0][l-1] = 0;
+
+		s = line[0];
+		pw->pw_name = s++;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_passwd = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_uid = atoi(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_gid = atoi(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_gecos = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_dir = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; pw->pw_shell = s;
+		return pw;
+	}
+}
diff --git a/src/passwd/getspent.c b/src/passwd/getspent.c
new file mode 100644
index 00000000..8574a480
--- /dev/null
+++ b/src/passwd/getspent.c
@@ -0,0 +1,14 @@
+#include "pwf.h"
+
+void setspent()
+{
+}
+
+void endspent()
+{
+}
+
+struct spwd *getspent()
+{
+	return 0;
+}
diff --git a/src/passwd/getspnam.c b/src/passwd/getspnam.c
new file mode 100644
index 00000000..041f8965
--- /dev/null
+++ b/src/passwd/getspnam.c
@@ -0,0 +1,17 @@
+#include "pwf.h"
+
+#define LINE_LIM 256
+
+struct spwd *getspnam(const char *name)
+{
+	static struct spwd sp;
+	static char *line;
+	struct spwd *res;
+	int e;
+
+	if (!line) line = malloc(LINE_LIM);
+	if (!line) return 0;
+	e = getspnam_r(name, &sp, line, LINE_LIM, &res);
+	if (e) errno = e;
+	return res;
+}
diff --git a/src/passwd/getspnam_r.c b/src/passwd/getspnam_r.c
new file mode 100644
index 00000000..1dd39ce0
--- /dev/null
+++ b/src/passwd/getspnam_r.c
@@ -0,0 +1,89 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include "pwf.h"
+
+/* This implementation support Openwall-style TCB passwords in place of
+ * traditional shadow, if the appropriate directories and files exist.
+ * Thus, it is careful to avoid following symlinks or blocking on fifos
+ * which a malicious user might create in place of his or her TCB shadow
+ * file. It also avoids any allocation to prevent memory-exhaustion
+ * attacks via huge TCB shadow files. */
+
+int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res)
+{
+	char path[20+NAME_MAX];
+	FILE *f = 0;
+	int rv = 0;
+	int fd;
+	size_t k, l = strlen(name);
+	char *s;
+	int skip = 0;
+
+	*res = 0;
+
+	/* Disallow potentially-malicious user names */
+	if (*name=='.' || strchr(name, '/') || !l)
+		return EINVAL;
+
+	/* Buffer size must at least be able to hold name, plus some.. */
+	if (size < l+100) return ERANGE;
+
+	/* Protect against truncation */
+	if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path)
+		return EINVAL;
+
+	fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK);
+	if (fd >= 0) {
+		f = fdopen(fd, "rb");
+		if (!f) {
+			close(fd);
+			return errno;
+		}
+	} else {
+		f = fopen("/etc/shadow", "rb");
+		if (!f) return errno;
+	}
+
+	while (fgets(buf, size, f) && (k=strlen(buf))>0) {
+		if (skip || strncmp(name, buf, l)) {
+			skip = buf[k-1] != '\n';
+			continue;
+		}
+		if (buf[k-1] != '\n') {
+			rv = ERANGE;
+			break;
+		}
+		buf[k-1] = 0;
+
+		s = buf;
+		sp->sp_namp = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_pwdp = s;
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_lstchg = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_min = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_max = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_warn = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_inact = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_expire = atol(s);
+		if (!(s = strchr(s, ':'))) continue;
+
+		*s++ = 0; sp->sp_flag = atol(s);
+		*res = sp;
+		break;
+	}
+	fclose(f);
+	return rv;
+}
diff --git a/src/passwd/lckpwdf.c b/src/passwd/lckpwdf.c
new file mode 100644
index 00000000..2feda617
--- /dev/null
+++ b/src/passwd/lckpwdf.c
@@ -0,0 +1,11 @@
+#include <shadow.h>
+
+int lckpwdf()
+{
+	return 0;
+}
+
+int ulckpwdf()
+{
+	return 0;
+}
diff --git a/src/passwd/pwf.h b/src/passwd/pwf.h
new file mode 100644
index 00000000..0a76ef80
--- /dev/null
+++ b/src/passwd/pwf.h
@@ -0,0 +1,13 @@
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include "libc.h"
+
+struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size);
+struct spwd *__getspent_a(FILE *f, struct spwd *sp, char **line, size_t *size);
+struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem);
diff --git a/src/prng/__rand48_step.c b/src/prng/__rand48_step.c
new file mode 100644
index 00000000..755b4f2f
--- /dev/null
+++ b/src/prng/__rand48_step.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <inttypes.h>
+
+uint64_t __rand48_step(unsigned short *xi, unsigned short *lc)
+{
+	uint64_t a, x;
+	x = xi[0] | xi[1]<<16 | xi[2]+0ULL<<32;
+	a = lc[0] | lc[1]<<16 | lc[2]+0ULL<<32;
+	x = a*x + lc[3];
+	xi[0] = x;
+	xi[1] = x>>16;
+	xi[2] = x>>32;
+	return x & 0xffffffffffffull;
+}
diff --git a/src/prng/__seed48.c b/src/prng/__seed48.c
new file mode 100644
index 00000000..05a4539e
--- /dev/null
+++ b/src/prng/__seed48.c
@@ -0,0 +1 @@
+unsigned short __seed48[7] = { 0, 0, 0, 0xe66d, 0xdeec, 0x5, 0xb };
diff --git a/src/prng/drand48.c b/src/prng/drand48.c
new file mode 100644
index 00000000..d808353c
--- /dev/null
+++ b/src/prng/drand48.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+#include <inttypes.h>
+
+uint64_t __rand48_step(unsigned short *xi, unsigned short *lc);
+extern unsigned short __seed48[7];
+
+double erand48(unsigned short s[3])
+{
+	union {
+		uint64_t u;
+		double f;
+	} x = { 0x3ff0000000000000ULL | __rand48_step(s, __seed48+3)<<4 };
+	return x.f - 1.0;
+}
+
+double drand48(void)
+{
+	return erand48(__seed48);
+}
diff --git a/src/prng/lcong48.c b/src/prng/lcong48.c
new file mode 100644
index 00000000..32b27d42
--- /dev/null
+++ b/src/prng/lcong48.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <string.h>
+
+extern unsigned short __seed48[7];
+
+void lcong48(unsigned short p[7])
+{
+	memcpy(__seed48, p, sizeof __seed48);
+}
diff --git a/src/prng/lrand48.c b/src/prng/lrand48.c
new file mode 100644
index 00000000..a3c4e4e2
--- /dev/null
+++ b/src/prng/lrand48.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <inttypes.h>
+
+uint64_t __rand48_step(unsigned short *xi, unsigned short *lc);
+extern unsigned short __seed48[7];
+
+long nrand48(unsigned short s[3])
+{
+	return __rand48_step(s, __seed48+3) >> 17;
+}
+
+long lrand48(void)
+{
+	return nrand48(__seed48);
+}
diff --git a/src/prng/mrand48.c b/src/prng/mrand48.c
new file mode 100644
index 00000000..ee650fc3
--- /dev/null
+++ b/src/prng/mrand48.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <inttypes.h>
+
+uint64_t __rand48_step(unsigned short *xi, unsigned short *lc);
+extern unsigned short __seed48[7];
+
+long jrand48(unsigned short s[3])
+{
+	return __rand48_step(s, __seed48+3) >> 16;
+}
+
+long mrand48(void)
+{
+	return jrand48(__seed48);
+}
diff --git a/src/prng/rand.c b/src/prng/rand.c
new file mode 100644
index 00000000..e3ce6347
--- /dev/null
+++ b/src/prng/rand.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+
+static unsigned seed;
+
+void srand(unsigned s)
+{
+	seed = s-1;
+}
+
+int rand(void)
+{
+	return (seed = (seed+1) * 1103515245 + 12345 - 1)+1 & 0x7fffffff;
+}
diff --git a/src/prng/rand_r.c b/src/prng/rand_r.c
new file mode 100644
index 00000000..e96cfba9
--- /dev/null
+++ b/src/prng/rand_r.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+int rand_r(unsigned *seed)
+{
+	return (*seed = *seed * 1103515245 + 12345) & 0x7fffffff;
+}
diff --git a/src/prng/random.c b/src/prng/random.c
new file mode 100644
index 00000000..e6b7fd1f
--- /dev/null
+++ b/src/prng/random.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+
+/* FIXME */
+
+long random()
+{
+	return rand();
+}
diff --git a/src/prng/seed48.c b/src/prng/seed48.c
new file mode 100644
index 00000000..e0699c09
--- /dev/null
+++ b/src/prng/seed48.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <string.h>
+
+extern unsigned short __seed48[7];
+
+unsigned short *seed48(unsigned short *s)
+{
+	static unsigned short p[3];
+	memcpy(p, __seed48, sizeof p);
+	memcpy(__seed48, s, sizeof p);
+	return p;
+}
diff --git a/src/prng/srand48.c b/src/prng/srand48.c
new file mode 100644
index 00000000..0a56f6a0
--- /dev/null
+++ b/src/prng/srand48.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+void srand48(long seed)
+{
+	seed48((unsigned short [3]){ 0x330e, seed, seed>>16 });
+}
diff --git a/src/prng/srandom.c b/src/prng/srandom.c
new file mode 100644
index 00000000..77f4dcbd
--- /dev/null
+++ b/src/prng/srandom.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+
+/* FIXME */
+
+void srandom(unsigned seed)
+{
+	return srand(seed);
+}
diff --git a/src/process/execl.c b/src/process/execl.c
new file mode 100644
index 00000000..4c6eaa94
--- /dev/null
+++ b/src/process/execl.c
@@ -0,0 +1,20 @@
+#include <unistd.h>
+#include <stdarg.h>
+
+int execl(const char *path, ...)
+{
+	int argc;
+	va_list ap;
+	va_start(ap, path);
+	for (argc=0; va_arg(ap, const char *); argc++);
+	va_end(ap);
+	{
+		int i;
+		char *argv[argc+1];
+		va_start(ap, path);
+		for (i=0; i<argc; i++)
+			argv[i] = va_arg(ap, char *);
+		argv[i] = NULL;
+		return execv(path, argv);
+	}
+}
diff --git a/src/process/execle.c b/src/process/execle.c
new file mode 100644
index 00000000..37f629d9
--- /dev/null
+++ b/src/process/execle.c
@@ -0,0 +1,22 @@
+#include <unistd.h>
+#include <stdarg.h>
+
+int execle(const char *path, ...)
+{
+	int argc;
+	va_list ap;
+	va_start(ap, path);
+	for (argc=0; va_arg(ap, const char *); argc++);
+	va_end(ap);
+	{
+		int i;
+		char *argv[argc+1];
+		char **envp;
+		va_start(ap, path);
+		for (i=0; i<argc; i++)
+			argv[i] = va_arg(ap, char *);
+		argv[i] = NULL;
+		envp = va_arg(ap, char **);
+		return execve(path, argv, envp);
+	}
+}
diff --git a/src/process/execlp.c b/src/process/execlp.c
new file mode 100644
index 00000000..33fb0f7f
--- /dev/null
+++ b/src/process/execlp.c
@@ -0,0 +1,20 @@
+#include <unistd.h>
+#include <stdarg.h>
+
+int execlp(const char *file, ...)
+{
+	int argc;
+	va_list ap;
+	va_start(ap, file);
+	for (argc=0; va_arg(ap, const char *); argc++);
+	va_end(ap);
+	{
+		int i;
+		char *argv[argc+1];
+		va_start(ap, file);
+		for (i=0; i<argc; i++)
+			argv[i] = va_arg(ap, char *);
+		argv[i] = NULL;
+		return execvp(file, argv);
+	}
+}
diff --git a/src/process/execv.c b/src/process/execv.c
new file mode 100644
index 00000000..2ac0dec0
--- /dev/null
+++ b/src/process/execv.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+
+extern char **__environ;
+
+int execv(const char *path, char *const argv[])
+{
+	return execve(path, argv, __environ);
+}
diff --git a/src/process/execve.c b/src/process/execve.c
new file mode 100644
index 00000000..2a0b62d6
--- /dev/null
+++ b/src/process/execve.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int execve(const char *path, char *const argv[], char *const envp[])
+{
+	/* do we need to use environ if envp is null? */
+	return syscall3(__NR_execve, (long)path, (long)argv, (long)envp);
+}
diff --git a/src/process/execvp.c b/src/process/execvp.c
new file mode 100644
index 00000000..d799ddae
--- /dev/null
+++ b/src/process/execvp.c
@@ -0,0 +1,34 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+extern char **__environ;
+
+int execvp(const char *file, char *const argv[])
+{
+	const char *p, *z, *path = getenv("PATH");
+	int l;
+
+	if (strchr(file, '/'))
+		return execve(file, argv, __environ);
+
+	/* FIXME: integer overflows */
+	if (!path) path = "/usr/local/bin:/bin:/usr/bin";
+	l = strlen(file) + strlen(path) + 2;
+
+	for(p=path; p && *p; p=z) {
+		char b[l];
+		z = strchr(p, ':');
+		if (z) {
+			memcpy(b, p, z-p);
+			b[z++-p] = 0;
+		} else strcpy(b, p);
+		strcat(b, "/");
+		strcat(b, file);
+		if (!access(b, X_OK))
+			return execve(b, argv, __environ);
+	}
+	errno = ENOENT;
+	return -1;
+}
diff --git a/src/process/fork.c b/src/process/fork.c
new file mode 100644
index 00000000..1213f0f5
--- /dev/null
+++ b/src/process/fork.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include "syscall.h"
+
+/* FIXME: add support for atfork stupidity */
+
+pid_t fork(void)
+{
+	return syscall0(__NR_fork);
+}
diff --git a/src/process/system.c b/src/process/system.c
new file mode 100644
index 00000000..0f1c07b5
--- /dev/null
+++ b/src/process/system.c
@@ -0,0 +1,45 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+int system(const char *cmd)
+{
+	pid_t pid;
+	sigset_t old, new;
+	struct sigaction sa, oldint, oldquit;
+	int status;
+
+	if (!cmd) return 1;
+
+	sa.sa_handler = SIG_IGN;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+
+	sigaction(SIGINT, &sa, &oldint);
+	sigaction(SIGQUIT, &sa, &oldquit);
+	sigaddset(&sa.sa_mask, SIGCHLD);
+	sigprocmask(SIG_BLOCK, &new, &old);
+
+	pid = fork();
+	if (pid <= 0) {
+		sigaction(SIGINT, &oldint, NULL);
+		sigaction(SIGQUIT, &oldquit, NULL);
+		sigprocmask(SIG_SETMASK, &old, NULL);
+		if (pid == 0) {
+			execl("/bin/sh", "sh", "-c", cmd, (char *)0);
+			_exit(127);
+		}
+		return -1;
+	}
+	while (waitpid(pid, &status, 0) == -1)
+		if (errno != EINTR) {
+			status = -1;
+			break;
+		}
+	sigaction(SIGINT, &oldint, NULL);
+	sigaction(SIGQUIT, &oldquit, NULL);
+	sigprocmask(SIG_SETMASK, &old, NULL);
+	return status;
+}
diff --git a/src/process/vfork.c b/src/process/vfork.c
new file mode 100644
index 00000000..32a7a6ed
--- /dev/null
+++ b/src/process/vfork.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t vfork(void)
+{
+	/* vfork syscall cannot be made from C code */
+	return syscall0(__NR_fork);
+}
diff --git a/src/process/wait.c b/src/process/wait.c
new file mode 100644
index 00000000..34da102d
--- /dev/null
+++ b/src/process/wait.c
@@ -0,0 +1,6 @@
+#include <sys/wait.h>
+
+pid_t wait(int *status)
+{
+	return waitpid((pid_t)-1, status, 0);
+}
diff --git a/src/process/waitid.c b/src/process/waitid.c
new file mode 100644
index 00000000..0ec0d55c
--- /dev/null
+++ b/src/process/waitid.c
@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include "syscall.h"
+
+int waitid(idtype_t type, id_t id, siginfo_t *info, int options)
+{
+	return syscall5(__NR_waitid, type, id, (long)info, options, 0);
+}
diff --git a/src/process/waitpid.c b/src/process/waitpid.c
new file mode 100644
index 00000000..0ddcd15a
--- /dev/null
+++ b/src/process/waitpid.c
@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include "syscall.h"
+
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+	return syscall4(__NR_wait4, pid, (long)status, options, 0);
+}
diff --git a/src/regex/fnmatch.c b/src/regex/fnmatch.c
new file mode 100644
index 00000000..5f2fccdb
--- /dev/null
+++ b/src/regex/fnmatch.c
@@ -0,0 +1,150 @@
+#include <fnmatch.h>
+#include <wctype.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <limits.h>
+
+static int next(const char **s)
+{
+	wchar_t c;
+	int l = mbtowc(&c, *s, MB_LEN_MAX);
+	/* hack to allow literal matches of invalid byte sequences */
+	if (l < 0) return (unsigned char)*(*s)++ - 0x100;
+	*s += l;
+	return c;
+}
+
+#define BRACKET_ERROR  -0x100
+#define BRACKET_NOCHAR -0x101
+
+static int bracket_next(const char **s)
+{
+	int c;
+	int type;
+	if (**s == '[') {
+		type = *(*s+1);
+		if (type == '.' || type == '=') {
+			*s += 2;
+			c = next(s);
+			if (c <= 0) return BRACKET_ERROR;
+			if (**s == type && *(*s+1) == ']') {
+				*s += 2;
+				return c;
+			}
+			for (; **s && (**s != type || *(*s+1) != ']'); (*s)++);
+			if (!**s) return BRACKET_ERROR;
+			*s += 2;
+			return BRACKET_NOCHAR;
+		}
+	}
+	c = next(s);
+	if (c <= 0) return BRACKET_ERROR;
+	return c;
+}
+
+#define __FNM_CONT 0x8000
+
+int fnmatch(const char *p, const char *s, int flags)
+{
+	int c, d, k;
+	int not;
+	int match;
+	int first;
+	int no_slash = (flags & FNM_PATHNAME) ? '/' : 0;
+	int no_period = (flags & FNM_PERIOD) && !(flags & __FNM_CONT) ? '.' : 0x100;
+
+	flags |= __FNM_CONT;
+
+	while ((c = *p++)) {
+		switch (c) {
+		case '?':
+			k = next(&s);
+			if (!k || k == no_period || k == no_slash)
+				return FNM_NOMATCH;
+			break;
+		case '\\':
+			if (!(flags & FNM_NOESCAPE)) {
+				c = *p++;
+				goto literal;
+			}
+			if (*s++ != c) return FNM_NOMATCH;
+			break;
+		case '*':
+			for (; *p == '*'; p++);
+			if (*p && !*s) return FNM_NOMATCH;
+			if (*s == no_period)
+				return FNM_NOMATCH;
+			if (!*p && (!no_slash || !strchr(s, no_slash)))
+				return 0;
+			for (; *s; s++)
+				if (!fnmatch(p, s, flags))
+					return 0;
+				else if (*s == no_slash)
+					break;
+			return FNM_NOMATCH;
+		case '[':
+			not = (*p == '!' || *p == '^');
+			if (not) p++;
+			k = next(&s);
+			if (!k || k == no_slash || k == no_period)
+				return FNM_NOMATCH;
+			match = 0;
+			first = 1;
+			for (;;) {
+				if (!*p) return FNM_NOMATCH;
+				if (*p == ']' && !first) break;
+				first = 0;
+				if (*p == '[' && *(p+1) == ':') {
+					const char *z;
+					p += 2;
+					for (z=p; *z && (*z != ':' || *(z+1) != ']'); z++);
+					if (!*z || z-p > 32) { /* FIXME: symbolic const? */
+						return FNM_NOMATCH;
+					} else {
+						char class[z-p+1];
+						memcpy(class, p, z-p);
+						class[z-p] = 0;
+						if (iswctype(k, wctype(class)))
+							match = 1;
+					}
+					p = z+2;
+					continue;
+				}
+				c = bracket_next(&p);
+				if (c == BRACKET_ERROR)
+					return FNM_NOMATCH;
+				if (c == BRACKET_NOCHAR)
+					continue;
+				if (*p == '-' && *(p+1) != ']') {
+					p++;
+					d = bracket_next(&p);
+					if (d == BRACKET_ERROR)
+						return FNM_NOMATCH;
+					if (d == BRACKET_NOCHAR)
+						continue;
+					if (k >= c && k <= d)
+						match = 1;
+					continue;
+				}
+				if (k == c) match = 1;
+			}
+			p++;
+			if (not == match)
+				return FNM_NOMATCH;
+			break;
+		default:
+		literal:
+			if (*s++ != c)
+				return FNM_NOMATCH;
+			if (c == no_slash && (flags & FNM_PERIOD)) {
+				no_period = '.';
+				continue;
+			}
+			break;
+		}
+		no_period = 0x100;
+	}
+	if (*s) return FNM_NOMATCH;
+	return 0;
+}
diff --git a/src/regex/glob.c b/src/regex/glob.c
new file mode 100644
index 00000000..9a70f0bc
--- /dev/null
+++ b/src/regex/glob.c
@@ -0,0 +1,238 @@
+#include <glob.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "libc.h"
+
+struct match
+{
+	struct match *next;
+	char name[1];
+};
+
+static int is_literal(const char *p, int useesc)
+{
+	int bracket = 0;
+	for (; *p; p++) {
+		switch (*p) {
+		case '\\':
+			if (!useesc) break;
+		case '?':
+		case '*':
+			return 0;
+		case '[':
+			bracket = 1;
+			break;
+		case ']':
+			if (bracket) return 0;
+			break;
+		}
+	}
+	return 1;
+}
+
+static int append(struct match **tail, const char *name, size_t len, int mark)
+{
+	struct match *new = malloc(sizeof(struct match) + len + 1);
+	if (!new) return -1;
+	(*tail)->next = new;
+	new->next = NULL;
+	strcpy(new->name, name);
+	if (mark) strcat(new->name, "/");
+	*tail = new;
+	return 0;
+}
+
+static int match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail)
+{
+	DIR *dir;
+	long long de_buf[(sizeof(struct dirent) + NAME_MAX + sizeof(long long))/sizeof(long long)];
+	struct dirent *de;
+	char pat[strlen(p)+1];
+	char *p2;
+	size_t l = strlen(d);
+	int literal;
+	int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | FNM_PERIOD;
+	int error;
+
+	if ((p2 = strchr(p, '/'))) {
+		strcpy(pat, p);
+		pat[p2-p] = 0;
+		for (; *p2 == '/'; p2++);
+		p = pat;
+	}
+	literal = is_literal(p, !(flags & GLOB_NOESCAPE));
+	if (*d == '/' && !*(d+1)) l = 0;
+
+	/* rely on opendir failing for nondirectory objects */
+	dir = opendir(*d ? d : ".");
+	error = errno;
+	if (!dir) {
+		/* this is not an error -- we let opendir call stat for us */
+		if (error == ENOTDIR) return 0;
+		if (error == EACCES && !*p) {
+			struct stat st;
+			if (!stat(d, &st) && S_ISDIR(st.st_mode)) {
+				if (append(tail, d, l, l))
+					return GLOB_NOSPACE;
+				return 0;
+			}
+		}
+		if (errfunc(d, error) || (flags & GLOB_ERR))
+			return GLOB_ABORTED;
+		return 0;
+	}
+	if (!*p) {
+		error = append(tail, d, l, l) ? GLOB_NOSPACE : 0;
+		closedir(dir);
+		return error;
+	}
+	while (!(error = readdir_r(dir, (void *)de_buf, &de)) && de) {
+		char namebuf[l+de->d_reclen+2], *name = namebuf;
+		if (!literal && fnmatch(p, de->d_name, fnm_flags))
+			continue;
+		if (literal && strcmp(p, de->d_name))
+			continue;
+		if (p2 && de->d_type && !S_ISDIR(de->d_type<<12) && !S_ISLNK(de->d_type<<12))
+			continue;
+		if (*d) {
+			memcpy(name, d, l);
+			name[l] = '/';
+			strcpy(name+l+1, de->d_name);
+		} else {
+			name = de->d_name;
+		}
+		if (p2) {
+			if ((error = match_in_dir(name, p2, flags, errfunc, tail))) {
+				closedir(dir);
+				return error;
+			}
+		} else {
+			int mark = 0;
+			if (flags & GLOB_MARK) {
+				if (de->d_type)
+					mark = S_ISDIR(de->d_type<<12);
+				else {
+					struct stat st;
+					stat(name, &st);
+					mark = S_ISDIR(st.st_mode);
+				}
+			}
+			if (append(tail, name, l+de->d_reclen+1, mark)) {
+				closedir(dir);
+				return GLOB_NOSPACE;
+			}
+		}
+	}
+	closedir(dir);
+	if (error && (errfunc(d, error) || (flags & GLOB_ERR)))
+		return GLOB_ABORTED;
+	return 0;
+}
+
+static int ignore_err(const char *path, int err)
+{
+	return 0;
+}
+
+static void freelist(struct match *head)
+{
+	struct match *match, *next;
+	for (match=head->next; match; match=next) {
+		next = match->next;
+		free(match);
+	}
+}
+
+static int sort(const void *a, const void *b)
+{
+	return strcmp(*(const char **)a, *(const char **)b);
+}
+
+int glob(const char *pat, int flags, int (*errfunc)(const char *path, int err), glob_t *g)
+{
+	const char *p=pat, *d;
+	struct match head = { .next = NULL }, *tail = &head;
+	size_t cnt, i;
+	size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
+	int error = 0;
+	
+	if (*p == '/') {
+		for (; *p == '/'; p++);
+		d = "/";
+	} else {
+		d = "";
+	}
+
+	if (!errfunc) errfunc = ignore_err;
+
+	if (!(flags & GLOB_APPEND)) {
+		g->gl_offs = offs;
+		g->gl_pathc = 0;
+		g->gl_pathv = NULL;
+	}
+
+	if (*p) error = match_in_dir(d, p, flags, errfunc, &tail);
+	if (error == GLOB_NOSPACE) {
+		freelist(&head);
+		return error;
+	}
+	
+	for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++);
+	if (!cnt) {
+		if (flags & GLOB_NOCHECK) {
+			tail = &head;
+			if (append(&tail, pat, strlen(pat), 0))
+				return GLOB_NOSPACE;
+			cnt++;
+		} else
+			return GLOB_NOMATCH;
+	}
+
+	if (flags & GLOB_APPEND) {
+		char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
+		if (!pathv) {
+			freelist(&head);
+			return GLOB_NOSPACE;
+		}
+		g->gl_pathv = pathv;
+		offs += g->gl_pathc;
+	} else {
+		g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
+		if (!g->gl_pathv) {
+			freelist(&head);
+			return GLOB_NOSPACE;
+		}
+		for (i=0; i<offs; i++)
+			g->gl_pathv[i] = NULL;
+	}
+	for (i=0, tail=head.next; i<cnt; tail=tail->next, i++)
+		g->gl_pathv[offs + i] = tail->name;
+	g->gl_pathv[offs + i] = NULL;
+	g->gl_pathc += cnt;
+
+	if (!(flags & GLOB_NOSORT))
+		qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort);
+	
+	return error;
+}
+
+void globfree(glob_t *g)
+{
+	size_t i;
+	for (i=0; i<g->gl_pathc; i++)
+		free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
+	free(g->gl_pathv);
+	g->gl_pathc = 0;
+	g->gl_pathv = NULL;
+}
+
+LFS64(glob);
+LFS64(globfree);
diff --git a/src/regex/regcomp.c b/src/regex/regcomp.c
new file mode 100644
index 00000000..3307942e
--- /dev/null
+++ b/src/regex/regcomp.c
@@ -0,0 +1,3362 @@
+/*
+  regcomp.c - TRE POSIX compatible regex compilation functions.
+
+  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <regex.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include "tre.h"
+
+#include <assert.h>
+
+/***********************************************************************
+ from tre-ast.c and tre-ast.h
+***********************************************************************/
+
+/* The different AST node types. */
+typedef enum {
+  LITERAL,
+  CATENATION,
+  ITERATION,
+  UNION
+} tre_ast_type_t;
+
+/* Special subtypes of TRE_LITERAL. */
+#define EMPTY	  -1   /* Empty leaf (denotes empty string). */
+#define ASSERTION -2   /* Assertion leaf. */
+#define TAG	  -3   /* Tag leaf. */
+#define BACKREF	  -4   /* Back reference leaf. */
+
+#define IS_SPECIAL(x)	((x)->code_min < 0)
+#define IS_EMPTY(x)	((x)->code_min == EMPTY)
+#define IS_ASSERTION(x) ((x)->code_min == ASSERTION)
+#define IS_TAG(x)	((x)->code_min == TAG)
+#define IS_BACKREF(x)	((x)->code_min == BACKREF)
+
+/* Taken from tre-compile.h */
+typedef struct {
+  int position;
+  int code_min;
+  int code_max;
+  int *tags;
+  int assertions;
+  tre_ctype_t class;
+  tre_ctype_t *neg_classes;
+  int backref;
+} tre_pos_and_tags_t;
+
+/* A generic AST node.  All AST nodes consist of this node on the top
+   level with `obj' pointing to the actual content. */
+typedef struct {
+  tre_ast_type_t type;   /* Type of the node. */
+  void *obj;             /* Pointer to actual node. */
+  int nullable;
+  int submatch_id;
+  int num_submatches;
+  int num_tags;
+  tre_pos_and_tags_t *firstpos;
+  tre_pos_and_tags_t *lastpos;
+} tre_ast_node_t;
+
+
+/* A "literal" node.  These are created for assertions, back references,
+   tags, matching parameter settings, and all expressions that match one
+   character. */
+typedef struct {
+  long code_min;
+  long code_max;
+  int position;
+  tre_ctype_t class;
+  tre_ctype_t *neg_classes;
+} tre_literal_t;
+
+/* A "catenation" node.	 These are created when two regexps are concatenated.
+   If there are more than one subexpressions in sequence, the `left' part
+   holds all but the last, and `right' part holds the last subexpression
+   (catenation is left associative). */
+typedef struct {
+  tre_ast_node_t *left;
+  tre_ast_node_t *right;
+} tre_catenation_t;
+
+/* An "iteration" node.	 These are created for the "*", "+", "?", and "{m,n}"
+   operators. */
+typedef struct {
+  /* Subexpression to match. */
+  tre_ast_node_t *arg;
+  /* Minimum number of consecutive matches. */
+  int min;
+  /* Maximum number of consecutive matches. */
+  int max;
+} tre_iteration_t;
+
+/* An "union" node.  These are created for the "|" operator. */
+typedef struct {
+  tre_ast_node_t *left;
+  tre_ast_node_t *right;
+} tre_union_t;
+
+static tre_ast_node_t *
+tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size)
+{
+  tre_ast_node_t *node;
+
+  node = tre_mem_calloc(mem, sizeof(*node));
+  if (!node)
+    return NULL;
+  node->obj = tre_mem_calloc(mem, size);
+  if (!node->obj)
+    return NULL;
+  node->type = type;
+  node->nullable = -1;
+  node->submatch_id = -1;
+
+  return node;
+}
+
+static tre_ast_node_t *
+tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position)
+{
+  tre_ast_node_t *node;
+  tre_literal_t *lit;
+
+  node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t));
+  if (!node)
+    return NULL;
+  lit = node->obj;
+  lit->code_min = code_min;
+  lit->code_max = code_max;
+  lit->position = position;
+
+  return node;
+}
+
+static tre_ast_node_t *
+tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max)
+{
+  tre_ast_node_t *node;
+  tre_iteration_t *iter;
+
+  node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t));
+  if (!node)
+    return NULL;
+  iter = node->obj;
+  iter->arg = arg;
+  iter->min = min;
+  iter->max = max;
+  node->num_submatches = arg->num_submatches;
+
+  return node;
+}
+
+static tre_ast_node_t *
+tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right)
+{
+  tre_ast_node_t *node;
+
+  node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t));
+  if (node == NULL)
+    return NULL;
+  ((tre_union_t *)node->obj)->left = left;
+  ((tre_union_t *)node->obj)->right = right;
+  node->num_submatches = left->num_submatches + right->num_submatches;
+
+  return node;
+}
+
+static tre_ast_node_t *
+tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left,
+		       tre_ast_node_t *right)
+{
+  tre_ast_node_t *node;
+
+  node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t));
+  if (node == NULL)
+    return NULL;
+  ((tre_catenation_t *)node->obj)->left = left;
+  ((tre_catenation_t *)node->obj)->right = right;
+  node->num_submatches = left->num_submatches + right->num_submatches;
+
+  return node;
+}
+
+/***********************************************************************
+ from tre-stack.c and tre-stack.h
+***********************************************************************/
+
+/* Just to save some typing. */
+#define STACK_PUSH(s, value)						      \
+  do									      \
+    {									      \
+      status = tre_stack_push(s, (void *)(value));			      \
+    }									      \
+  while (0)
+
+#define STACK_PUSHX(s, value)						      \
+  {									      \
+    status = tre_stack_push(s, (void *)(value));			      \
+    if (status != REG_OK)						      \
+      break;								      \
+  }
+
+#define STACK_PUSHR(s, value)						      \
+  {									      \
+    reg_errcode_t status;						      \
+    status = tre_stack_push(s, (void *)(value));			      \
+    if (status != REG_OK)						      \
+      return status;							      \
+  }
+
+typedef struct tre_stack_rec {
+  int size;
+  int max_size;
+  int increment;
+  int ptr;
+  void **stack;
+} tre_stack_t;
+
+
+static tre_stack_t *
+tre_stack_new(int size, int max_size, int increment)
+{
+  tre_stack_t *s;
+
+  s = xmalloc(sizeof(*s));
+  if (s != NULL)
+    {
+      s->stack = xmalloc(sizeof(*s->stack) * size);
+      if (s->stack == NULL)
+	{
+	  xfree(s);
+	  return NULL;
+	}
+      s->size = size;
+      s->max_size = max_size;
+      s->increment = increment;
+      s->ptr = 0;
+    }
+  return s;
+}
+
+static void
+tre_stack_destroy(tre_stack_t *s)
+{
+  xfree(s->stack);
+  xfree(s);
+}
+
+static int
+tre_stack_num_objects(tre_stack_t *s)
+{
+  return s->ptr;
+}
+
+static reg_errcode_t
+tre_stack_push(tre_stack_t *s, void *value)
+{
+  if (s->ptr < s->size)
+    {
+      s->stack[s->ptr] = value;
+      s->ptr++;
+    }
+  else
+    {
+      if (s->size >= s->max_size)
+	{
+	  DPRINT(("tre_stack_push: stack full\n"));
+	  return REG_ESPACE;
+	}
+      else
+	{
+	  void **new_buffer;
+	  int new_size;
+	  DPRINT(("tre_stack_push: trying to realloc more space\n"));
+	  new_size = s->size + s->increment;
+	  if (new_size > s->max_size)
+	    new_size = s->max_size;
+	  new_buffer = xrealloc(s->stack, sizeof(*new_buffer) * new_size);
+	  if (new_buffer == NULL)
+	    {
+	      DPRINT(("tre_stack_push: realloc failed.\n"));
+	      return REG_ESPACE;
+	    }
+	  DPRINT(("tre_stack_push: realloc succeeded.\n"));
+	  assert(new_size > s->size);
+	  s->size = new_size;
+	  s->stack = new_buffer;
+	  tre_stack_push(s, value);
+	}
+    }
+  return REG_OK;
+}
+
+static void *
+tre_stack_pop(tre_stack_t *s)
+{
+  return s->stack[--s->ptr];
+}
+
+
+/***********************************************************************
+ from tre-parse.c and tre-parse.h
+***********************************************************************/
+
+/* Parse context. */
+typedef struct {
+  /* Memory allocator.	The AST is allocated using this. */
+  tre_mem_t mem;
+  /* Stack used for keeping track of regexp syntax. */
+  tre_stack_t *stack;
+  /* The parse result. */
+  tre_ast_node_t *result;
+  /* The regexp to parse and its length. */
+  const tre_char_t *re;
+  /* The first character of the entire regexp. */
+  const tre_char_t *re_start;
+  /* The first character after the end of the regexp. */
+  const tre_char_t *re_end;
+  int len;
+  /* Current submatch ID. */
+  int submatch_id;
+  /* Current position (number of literal). */
+  int position;
+  /* The highest back reference or -1 if none seen so far. */
+  int max_backref;
+  /* Compilation flags. */
+  int cflags;
+  /* If this flag is set the top-level submatch is not captured. */
+  int nofirstsub;
+} tre_parse_ctx_t;
+
+static reg_errcode_t
+tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i,
+	 tre_ast_node_t ***items)
+{
+  reg_errcode_t status;
+  tre_ast_node_t **array = *items;
+  /* Allocate more space if necessary. */
+  if (*i >= *max_i)
+    {
+      tre_ast_node_t **new_items;
+      DPRINT(("out of array space, i = %d\n", *i));
+      /* If the array is already 1024 items large, give up -- there's
+	 probably an error in the regexp (e.g. not a '\0' terminated
+	 string and missing ']') */
+      if (*max_i > 1024)
+	return REG_ESPACE;
+      *max_i *= 2;
+      new_items = xrealloc(array, sizeof(*items) * *max_i);
+      if (new_items == NULL)
+	return REG_ESPACE;
+      *items = array = new_items;
+    }
+  array[*i] = tre_ast_new_literal(mem, min, max, -1);
+  status = array[*i] == NULL ? REG_ESPACE : REG_OK;
+  (*i)++;
+  return status;
+}
+
+
+/* Expands a character class to character ranges. */
+static reg_errcode_t
+tre_expand_ctype(tre_mem_t mem, tre_ctype_t class, tre_ast_node_t ***items,
+		 int *i, int *max_i, int cflags)
+{
+  reg_errcode_t status = REG_OK;
+  tre_cint_t c;
+  int j, min = -1, max = 0;
+  assert(TRE_MB_CUR_MAX == 1);
+
+  DPRINT(("  expanding class to character ranges\n"));
+  for (j = 0; (j < 256) && (status == REG_OK); j++)
+    {
+      c = j;
+      if (tre_isctype(c, class)
+	  || ((cflags & REG_ICASE)
+	      && (tre_isctype(tre_tolower(c), class)
+		  || tre_isctype(tre_toupper(c), class))))
+{
+	  if (min < 0)
+	    min = c;
+	  max = c;
+	}
+      else if (min >= 0)
+	{
+	  DPRINT(("  range %c (%d) to %c (%d)\n", min, min, max, max));
+	  status = tre_new_item(mem, min, max, i, max_i, items);
+	  min = -1;
+	}
+    }
+  if (min >= 0 && status == REG_OK)
+    status = tre_new_item(mem, min, max, i, max_i, items);
+  return status;
+}
+
+
+static int
+tre_compare_items(const void *a, const void *b)
+{
+  tre_ast_node_t *node_a = *(tre_ast_node_t **)a;
+  tre_ast_node_t *node_b = *(tre_ast_node_t **)b;
+  tre_literal_t *l_a = node_a->obj, *l_b = node_b->obj;
+  int a_min = l_a->code_min, b_min = l_b->code_min;
+
+  if (a_min < b_min)
+    return -1;
+  else if (a_min > b_min)
+    return 1;
+  else
+    return 0;
+}
+
+/* Maximum number of character classes that can occur in a negated bracket
+   expression.	*/
+#define MAX_NEG_CLASSES 64
+
+/* Maximum length of character class names. */
+#define MAX_CLASS_NAME
+
+static reg_errcode_t
+tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate,
+			tre_ctype_t neg_classes[], int *num_neg_classes,
+			tre_ast_node_t ***items, int *num_items,
+			int *items_size)
+{
+  const tre_char_t *re = ctx->re;
+  reg_errcode_t status = REG_OK;
+  tre_ctype_t class = (tre_ctype_t)0;
+  int i = *num_items;
+  int max_i = *items_size;
+  int skip;
+
+  /* Build an array of the items in the bracket expression. */
+  while (status == REG_OK)
+    {
+      skip = 0;
+      if (re == ctx->re_end)
+	{
+	  status = REG_EBRACK;
+	}
+      else if (*re == ']' && re > ctx->re)
+	{
+	  DPRINT(("tre_parse_bracket:	done: '%.*" STRF "'\n",
+		  ctx->re_end - re, re));
+	  re++;
+	  break;
+	}
+      else
+	{
+	  tre_cint_t min = 0, max = 0;
+
+	  class = (tre_ctype_t)0;
+	  if (re + 2 < ctx->re_end
+	      && *(re + 1) == '-' && *(re + 2) != ']')
+	    {
+	      DPRINT(("tre_parse_bracket:  range: '%.*" STRF "'\n",
+		      ctx->re_end - re, re));
+	      min = *re;
+	      max = *(re + 2);
+	      re += 3;
+	      /* XXX - Should use collation order instead of encoding values
+		 in character ranges. */
+	      if (min > max)
+		status = REG_ERANGE;
+	    }
+	  else if (re + 1 < ctx->re_end
+		   && *re == '[' && *(re + 1) == '.')
+	    status = REG_ECOLLATE;
+	  else if (re + 1 < ctx->re_end
+		   && *re == '[' && *(re + 1) == '=')
+	    status = REG_ECOLLATE;
+	  else if (re + 1 < ctx->re_end
+		   && *re == '[' && *(re + 1) == ':')
+	    {
+	      char tmp_str[64];
+	      const tre_char_t *endptr = re + 2;
+	      int len;
+	      DPRINT(("tre_parse_bracket:  class: '%.*" STRF "'\n",
+		      ctx->re_end - re, re));
+	      while (endptr < ctx->re_end && *endptr != ':')
+		endptr++;
+	      if (endptr != ctx->re_end)
+		{
+		  len = MIN(endptr - re - 2, 63);
+#ifdef TRE_WCHAR
+		  {
+		    tre_char_t tmp_wcs[64];
+		    wcsncpy(tmp_wcs, re + 2, len);
+		    tmp_wcs[len] = '\0';
+#if defined HAVE_WCSRTOMBS
+		    {
+		      mbstate_t state;
+		      const tre_char_t *src = tmp_wcs;
+		      memset(&state, '\0', sizeof(state));
+		      len = wcsrtombs(tmp_str, &src, sizeof(tmp_str), &state);
+		    }
+#elif defined HAVE_WCSTOMBS
+		    len = wcstombs(tmp_str, tmp_wcs, 63);
+#endif /* defined HAVE_WCSTOMBS */
+		  }
+#else /* !TRE_WCHAR */
+		  strncpy(tmp_str, re + 2, len);
+#endif /* !TRE_WCHAR */
+		  tmp_str[len] = '\0';
+		  DPRINT(("  class name: %s\n", tmp_str));
+		  class = tre_ctype(tmp_str);
+		  if (!class)
+		    status = REG_ECTYPE;
+		  /* Optimize character classes for 8 bit character sets. */
+		  if (status == REG_OK && TRE_MB_CUR_MAX == 1)
+		    {
+		      status = tre_expand_ctype(ctx->mem, class, items,
+						&i, &max_i, ctx->cflags);
+		      class = (tre_ctype_t)0;
+		      skip = 1;
+		    }
+		  re = endptr + 2;
+		}
+	      else
+		status = REG_ECTYPE;
+	      min = 0;
+	      max = TRE_CHAR_MAX;
+	    }
+	  else
+	    {
+	      DPRINT(("tre_parse_bracket:   char: '%.*" STRF "'\n",
+		      ctx->re_end - re, re));
+	      if (*re == '-' && *(re + 1) != ']'
+		  && ctx->re != re)
+		/* Two ranges are not allowed to share and endpoint. */
+		status = REG_ERANGE;
+	      min = max = *re++;
+	    }
+
+	  if (status != REG_OK)
+	    break;
+
+	  if (class && negate)
+	    if (*num_neg_classes >= MAX_NEG_CLASSES)
+	      status = REG_ESPACE;
+	    else
+	      neg_classes[(*num_neg_classes)++] = class;
+	  else if (!skip)
+	    {
+	      status = tre_new_item(ctx->mem, min, max, &i, &max_i, items);
+	      if (status != REG_OK)
+		break;
+	      ((tre_literal_t*)((*items)[i-1])->obj)->class = class;
+	    }
+
+	  /* Add opposite-case counterpoints if REG_ICASE is present.
+	     This is broken if there are more than two "same" characters. */
+	  if (ctx->cflags & REG_ICASE && !class && status == REG_OK && !skip)
+	    {
+	      int cmin, ccurr;
+
+	      DPRINT(("adding opposite-case counterpoints\n"));
+	      while (min <= max)
+		{
+		  if (tre_islower(min))
+		    {
+		      cmin = ccurr = tre_toupper(min++);
+		      while (tre_islower(min) && tre_toupper(min) == ccurr + 1
+			     && min <= max)
+			ccurr = tre_toupper(min++);
+		      status = tre_new_item(ctx->mem, cmin, ccurr,
+					    &i, &max_i, items);
+		    }
+		  else if (tre_isupper(min))
+		    {
+		      cmin = ccurr = tre_tolower(min++);
+		      while (tre_isupper(min) && tre_tolower(min) == ccurr + 1
+			     && min <= max)
+			ccurr = tre_tolower(min++);
+		      status = tre_new_item(ctx->mem, cmin, ccurr,
+					    &i, &max_i, items);
+		    }
+		  else min++;
+		  if (status != REG_OK)
+		    break;
+		}
+	      if (status != REG_OK)
+		break;
+	    }
+	}
+    }
+  *num_items = i;
+  *items_size = max_i;
+  ctx->re = re;
+  return status;
+}
+
+static reg_errcode_t
+tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
+{
+  tre_ast_node_t *node = NULL;
+  int negate = 0;
+  reg_errcode_t status = REG_OK;
+  tre_ast_node_t **items, *u, *n;
+  int i = 0, j, max_i = 32, curr_max, curr_min;
+  tre_ctype_t neg_classes[MAX_NEG_CLASSES];
+  int num_neg_classes = 0;
+
+  /* Start off with an array of `max_i' elements. */
+  items = xmalloc(sizeof(*items) * max_i);
+  if (items == NULL)
+    return REG_ESPACE;
+
+  if (*ctx->re == '^')
+    {
+      DPRINT(("tre_parse_bracket: negate: '%.*" STRF "'\n",
+	      ctx->re_end - ctx->re, ctx->re));
+      negate = 1;
+      ctx->re++;
+    }
+
+  status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes,
+				   &items, &i, &max_i);
+
+  if (status != REG_OK)
+    goto parse_bracket_done;
+
+  /* Sort the array if we need to negate it. */
+  if (negate)
+    qsort(items, i, sizeof(*items), tre_compare_items);
+
+  curr_max = curr_min = 0;
+  /* Build a union of the items in the array, negated if necessary. */
+  for (j = 0; j < i && status == REG_OK; j++)
+    {
+      int min, max;
+      tre_literal_t *l = items[j]->obj;
+      min = l->code_min;
+      max = l->code_max;
+
+      DPRINT(("item: %d - %d, class %ld, curr_max = %d\n",
+	      (int)l->code_min, (int)l->code_max, (long)l->class, curr_max));
+
+      if (negate)
+	{
+	  if (min < curr_max)
+	    {
+	      /* Overlap. */
+	      curr_max = MAX(max + 1, curr_max);
+	      DPRINT(("overlap, curr_max = %d\n", curr_max));
+	      l = NULL;
+	    }
+	  else
+	    {
+	      /* No overlap. */
+	      curr_max = min - 1;
+	      if (curr_max >= curr_min)
+		{
+		  DPRINT(("no overlap\n"));
+		  l->code_min = curr_min;
+		  l->code_max = curr_max;
+		}
+	      else
+		{
+		  DPRINT(("no overlap, zero room\n"));
+		  l = NULL;
+		}
+	      curr_min = curr_max = max + 1;
+	    }
+	}
+
+      if (l != NULL)
+	{
+	  int k;
+	  DPRINT(("creating %d - %d\n", (int)l->code_min, (int)l->code_max));
+	  l->position = ctx->position;
+	  if (num_neg_classes > 0)
+	    {
+	      l->neg_classes = tre_mem_alloc(ctx->mem,
+					     (sizeof(l->neg_classes)
+					      * (num_neg_classes + 1)));
+	      if (l->neg_classes == NULL)
+		{
+		  status = REG_ESPACE;
+		  break;
+		}
+	      for (k = 0; k < num_neg_classes; k++)
+		l->neg_classes[k] = neg_classes[k];
+	      l->neg_classes[k] = (tre_ctype_t)0;
+	    }
+	  else
+	    l->neg_classes = NULL;
+	  if (node == NULL)
+	    node = items[j];
+	  else
+	    {
+	      u = tre_ast_new_union(ctx->mem, node, items[j]);
+	      if (u == NULL)
+		status = REG_ESPACE;
+	      node = u;
+	    }
+	}
+    }
+
+  if (status != REG_OK)
+    goto parse_bracket_done;
+
+  if (negate)
+    {
+      int k;
+      DPRINT(("final: creating %d - %d\n", curr_min, (int)TRE_CHAR_MAX));
+      n = tre_ast_new_literal(ctx->mem, curr_min, TRE_CHAR_MAX, ctx->position);
+      if (n == NULL)
+	status = REG_ESPACE;
+      else
+	{
+	  tre_literal_t *l = n->obj;
+	  if (num_neg_classes > 0)
+	    {
+	      l->neg_classes = tre_mem_alloc(ctx->mem,
+					     (sizeof(l->neg_classes)
+					      * (num_neg_classes + 1)));
+	      if (l->neg_classes == NULL)
+		{
+		  status = REG_ESPACE;
+		  goto parse_bracket_done;
+		}
+	      for (k = 0; k < num_neg_classes; k++)
+		l->neg_classes[k] = neg_classes[k];
+	      l->neg_classes[k] = (tre_ctype_t)0;
+	    }
+	  else
+	    l->neg_classes = NULL;
+	  if (node == NULL)
+	    node = n;
+	  else
+	    {
+	      u = tre_ast_new_union(ctx->mem, node, n);
+	      if (u == NULL)
+		status = REG_ESPACE;
+	      node = u;
+	    }
+	}
+    }
+
+  if (status != REG_OK)
+    goto parse_bracket_done;
+
+#ifdef TRE_DEBUG
+  tre_ast_print(node);
+#endif /* TRE_DEBUG */
+
+ parse_bracket_done:
+  xfree(items);
+  ctx->position++;
+  *result = node;
+  return status;
+}
+
+
+/* Parses a positive decimal integer.  Returns -1 if the string does not
+   contain a valid number. */
+static int
+tre_parse_int(const tre_char_t **regex, const tre_char_t *regex_end)
+{
+  int num = -1;
+  const tre_char_t *r = *regex;
+  while (r < regex_end && *r >= '0' && *r <= '9')
+    {
+      if (num < 0)
+	num = 0;
+      num = num * 10 + *r - '0';
+      r++;
+    }
+  *regex = r;
+  return num;
+}
+
+
+static reg_errcode_t
+tre_parse_bound(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
+{
+  int min, max;
+  const tre_char_t *r = ctx->re;
+  const tre_char_t *start;
+  int counts_set = 0;
+
+  /* Parse number (minimum repetition count). */
+  min = -1;
+  if (r < ctx->re_end && *r >= '0' && *r <= '9') {
+    DPRINT(("tre_parse:	  min count: '%.*" STRF "'\n", ctx->re_end - r, r));
+    min = tre_parse_int(&r, ctx->re_end);
+  }
+
+  /* Parse comma and second number (maximum repetition count). */
+  max = min;
+  if (r < ctx->re_end && *r == ',')
+    {
+      r++;
+      DPRINT(("tre_parse:   max count: '%.*" STRF "'\n", ctx->re_end - r, r));
+      max = tre_parse_int(&r, ctx->re_end);
+    }
+
+  /* Check that the repeat counts are sane. */
+  if ((max >= 0 && min > max) || max > RE_DUP_MAX)
+    return REG_BADBR;
+
+
+  /*
+   '{'
+     optionally followed immediately by a number == minimum repcount
+     optionally followed by , then a number == maximum repcount
+  */
+
+
+  do {
+    int done;
+    start = r;
+
+    /* Parse count limit settings */
+    done = 0;
+    if (!counts_set)
+      while (r + 1 < ctx->re_end && !done)
+	{
+	  switch (*r)
+	    {
+	    case ',':
+	      r++;
+	      break;
+	    case ' ':
+	      r++;
+	      break;
+	    case '}':
+	      done = 1;
+	      break;
+	    default:
+	      done = 1;
+	      break;
+	    }
+	}
+  } while (start != r);
+
+  /* Missing }. */
+  if (r >= ctx->re_end)
+    return REG_EBRACE;
+
+  /* Empty contents of {}. */
+  if (r == ctx->re)
+    return REG_BADBR;
+
+  /* Parse the ending '}' or '\}'.*/
+  if (ctx->cflags & REG_EXTENDED)
+    {
+      if (r >= ctx->re_end || *r != '}')
+	return REG_BADBR;
+      r++;
+    }
+  else
+    {
+      if (r + 1 >= ctx->re_end
+	  || *r != '\\'
+	  || *(r + 1) != '}')
+	return REG_BADBR;
+      r += 2;
+    }
+
+
+  /* Create the AST node(s). */
+  if (min == 0 && max == 0)
+    {
+      *result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
+      if (*result == NULL)
+	return REG_ESPACE;
+    }
+  else
+    {
+      if (min < 0 && max < 0)
+	/* Only approximate parameters set, no repetitions. */
+	min = max = 1;
+
+      *result = tre_ast_new_iter(ctx->mem, *result, min, max);
+      if (!*result)
+	return REG_ESPACE;
+    }
+
+  ctx->re = r;
+  return REG_OK;
+}
+
+typedef enum {
+  PARSE_RE = 0,
+  PARSE_ATOM,
+  PARSE_MARK_FOR_SUBMATCH,
+  PARSE_BRANCH,
+  PARSE_PIECE,
+  PARSE_CATENATION,
+  PARSE_POST_CATENATION,
+  PARSE_UNION,
+  PARSE_POST_UNION,
+  PARSE_POSTFIX,
+  PARSE_RESTORE_CFLAGS
+} tre_parse_re_stack_symbol_t;
+
+
+static reg_errcode_t
+tre_parse(tre_parse_ctx_t *ctx)
+{
+  tre_ast_node_t *result = NULL;
+  tre_parse_re_stack_symbol_t symbol;
+  reg_errcode_t status = REG_OK;
+  tre_stack_t *stack = ctx->stack;
+  int bottom = tre_stack_num_objects(stack);
+  int depth = 0;
+
+  DPRINT(("tre_parse: parsing '%.*" STRF "', len = %d\n",
+	  ctx->len, ctx->re, ctx->len));
+
+  if (!ctx->nofirstsub)
+    {
+      STACK_PUSH(stack, ctx->re);
+      STACK_PUSH(stack, ctx->submatch_id);
+      STACK_PUSH(stack, PARSE_MARK_FOR_SUBMATCH);
+      ctx->submatch_id++;
+    }
+  STACK_PUSH(stack, PARSE_RE);
+  ctx->re_start = ctx->re;
+  ctx->re_end = ctx->re + ctx->len;
+
+
+  /* The following is basically just a recursive descent parser.  I use
+     an explicit stack instead of recursive functions mostly because of
+     two reasons: compatibility with systems which have an overflowable
+     call stack, and efficiency (both in lines of code and speed).  */
+  while (tre_stack_num_objects(stack) > bottom && status == REG_OK)
+    {
+      if (status != REG_OK)
+	break;
+      symbol = (tre_parse_re_stack_symbol_t)tre_stack_pop(stack);
+      switch (symbol)
+	{
+	case PARSE_RE:
+	  /* Parse a full regexp.  A regexp is one or more branches,
+	     separated by the union operator `|'. */
+	  if (ctx->cflags & REG_EXTENDED)
+	    STACK_PUSHX(stack, PARSE_UNION);
+	  STACK_PUSHX(stack, PARSE_BRANCH);
+	  break;
+
+	case PARSE_BRANCH:
+	  /* Parse a branch.  A branch is one or more pieces, concatenated.
+	     A piece is an atom possibly followed by a postfix operator. */
+	  STACK_PUSHX(stack, PARSE_CATENATION);
+	  STACK_PUSHX(stack, PARSE_PIECE);
+	  break;
+
+	case PARSE_PIECE:
+	  /* Parse a piece.  A piece is an atom possibly followed by one
+	     or more postfix operators. */
+	  STACK_PUSHX(stack, PARSE_POSTFIX);
+	  STACK_PUSHX(stack, PARSE_ATOM);
+	  break;
+
+	case PARSE_CATENATION:
+	  /* If the expression has not ended, parse another piece. */
+	  {
+	    tre_char_t c;
+	    if (ctx->re >= ctx->re_end)
+	      break;
+	    c = *ctx->re;
+	    if (ctx->cflags & REG_EXTENDED && c == '|')
+	      break;
+	    if ((ctx->cflags & REG_EXTENDED
+	         && c == ')' && depth > 0)
+	        || (!(ctx->cflags & REG_EXTENDED)
+		    && (c == '\\'
+		        && *(ctx->re + 1) == ')')))
+	      {
+	        if (!(ctx->cflags & REG_EXTENDED) && depth == 0)
+	          status = REG_EPAREN;
+	        DPRINT(("tre_parse:	  group end: '%.*" STRF "'\n",
+		        ctx->re_end - ctx->re, ctx->re));
+	        depth--;
+	        if (!(ctx->cflags & REG_EXTENDED))
+	          ctx->re += 2;
+	        break;
+	      }
+
+	    /* Left associative concatenation. */
+	    STACK_PUSHX(stack, PARSE_CATENATION);
+	    STACK_PUSHX(stack, result);
+	    STACK_PUSHX(stack, PARSE_POST_CATENATION);
+	    STACK_PUSHX(stack, PARSE_PIECE);
+	    break;
+	  }
+
+	case PARSE_POST_CATENATION:
+	  {
+	    tre_ast_node_t *tree = tre_stack_pop(stack);
+	    tre_ast_node_t *tmp_node;
+	    tmp_node = tre_ast_new_catenation(ctx->mem, tree, result);
+	    if (!tmp_node)
+	      return REG_ESPACE;
+	    result = tmp_node;
+	    break;
+	  }
+
+	case PARSE_UNION:
+	  if (ctx->re >= ctx->re_end)
+	    break;
+	  switch (*ctx->re)
+	    {
+	    case '|':
+	      DPRINT(("tre_parse:	union: '%.*" STRF "'\n",
+		      ctx->re_end - ctx->re, ctx->re));
+	      STACK_PUSHX(stack, PARSE_UNION);
+	      STACK_PUSHX(stack, result);
+	      STACK_PUSHX(stack, PARSE_POST_UNION);
+	      STACK_PUSHX(stack, PARSE_BRANCH);
+	      ctx->re++;
+	      break;
+
+	    case ')':
+	      ctx->re++;
+	      break;
+
+	    default:
+	      break;
+	    }
+	  break;
+
+	case PARSE_POST_UNION:
+	  {
+	    tre_ast_node_t *tmp_node;
+	    tre_ast_node_t *tree = tre_stack_pop(stack);
+	    tmp_node = tre_ast_new_union(ctx->mem, tree, result);
+	    if (!tmp_node)
+	      return REG_ESPACE;
+	    result = tmp_node;
+	    break;
+	  }
+
+	case PARSE_POSTFIX:
+	  /* Parse postfix operators. */
+	  if (ctx->re >= ctx->re_end)
+	    break;
+	  switch (*ctx->re)
+	    {
+	    case '+':
+	    case '?':
+	      if (!(ctx->cflags & REG_EXTENDED))
+	        break;
+	    case '*':
+	      {
+		tre_ast_node_t *tmp_node;
+		int rep_min = 0;
+		int rep_max = -1;
+		if (*ctx->re == '+')
+		  rep_min = 1;
+		if (*ctx->re == '?')
+		  rep_max = 1;
+
+		ctx->re++;
+		tmp_node = tre_ast_new_iter(ctx->mem, result, rep_min, rep_max);
+		if (tmp_node == NULL)
+		  return REG_ESPACE;
+		result = tmp_node;
+		STACK_PUSHX(stack, PARSE_POSTFIX);
+		break;
+	      }
+
+	    case '\\':
+	      /* "\{" is special without REG_EXTENDED */
+	      if (!(ctx->cflags & REG_EXTENDED)
+		  && ctx->re + 1 < ctx->re_end
+		  && *(ctx->re + 1) == '{')
+		{
+		  ctx->re++;
+		  goto parse_brace;
+		}
+	      else
+		break;
+
+	    case '{':
+	      /* "{" is literal without REG_EXTENDED */
+	      if (!(ctx->cflags & REG_EXTENDED))
+		break;
+
+	    parse_brace:
+	      DPRINT(("tre_parse:	bound: '%.*" STRF "'\n",
+		      ctx->re_end - ctx->re, ctx->re));
+	      ctx->re++;
+
+	      status = tre_parse_bound(ctx, &result);
+	      if (status != REG_OK)
+		return status;
+	      STACK_PUSHX(stack, PARSE_POSTFIX);
+	      break;
+	    }
+	  break;
+
+	case PARSE_ATOM:
+	  /* Parse an atom.  An atom is a regular expression enclosed in `()',
+	     an empty set of `()', a bracket expression, `.', `^', `$',
+	     a `\' followed by a character, or a single character. */
+
+	  /* End of regexp? (empty string). */
+	  if (ctx->re >= ctx->re_end)
+	    goto parse_literal;
+
+	  switch (*ctx->re)
+	    {
+	    case '(':  /* parenthesized subexpression */
+
+	      if (ctx->cflags & REG_EXTENDED
+		  || (ctx->re > ctx->re_start
+		      && *(ctx->re - 1) == '\\'))
+		{
+		  depth++;
+		    {
+		      DPRINT(("tre_parse: group begin: '%.*" STRF
+			      "', submatch %d\n",
+			      ctx->re_end - ctx->re, ctx->re,
+			      ctx->submatch_id));
+		      ctx->re++;
+		      /* First parse a whole RE, then mark the resulting tree
+			 for submatching. */
+		      STACK_PUSHX(stack, ctx->submatch_id);
+		      STACK_PUSHX(stack, PARSE_MARK_FOR_SUBMATCH);
+		      STACK_PUSHX(stack, PARSE_RE);
+		      ctx->submatch_id++;
+		    }
+		}
+	      else
+		goto parse_literal;
+	      break;
+
+	    case ')':  /* end of current subexpression */
+	      if ((ctx->cflags & REG_EXTENDED && depth > 0)
+		  || (ctx->re > ctx->re_start
+		      && *(ctx->re - 1) == '\\'))
+		{
+		  DPRINT(("tre_parse:	    empty: '%.*" STRF "'\n",
+			  ctx->re_end - ctx->re, ctx->re));
+		  /* We were expecting an atom, but instead the current
+		     subexpression was closed.	POSIX leaves the meaning of
+		     this to be implementation-defined.	 We interpret this as
+		     an empty expression (which matches an empty string).  */
+		  result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
+		  if (result == NULL)
+		    return REG_ESPACE;
+		  if (!(ctx->cflags & REG_EXTENDED))
+		    ctx->re--;
+		}
+	      else
+		goto parse_literal;
+	      break;
+
+	    case '[': /* bracket expression */
+	      DPRINT(("tre_parse:     bracket: '%.*" STRF "'\n",
+		      ctx->re_end - ctx->re, ctx->re));
+	      ctx->re++;
+	      status = tre_parse_bracket(ctx, &result);
+	      if (status != REG_OK)
+		return status;
+	      break;
+
+	    case '\\':
+	      /* If this is "\(" or "\)" chew off the backslash and
+		 try again. */
+	      if (!(ctx->cflags & REG_EXTENDED)
+		  && ctx->re + 1 < ctx->re_end
+		  && (*(ctx->re + 1) == '('
+		      || *(ctx->re + 1) == ')'))
+		{
+		  ctx->re++;
+		  STACK_PUSHX(stack, PARSE_ATOM);
+		  break;
+		}
+
+	      if (ctx->re + 1 >= ctx->re_end)
+		/* Trailing backslash. */
+		return REG_EESCAPE;
+
+	      DPRINT(("tre_parse:  bleep: '%.*" STRF "'\n",
+		      ctx->re_end - ctx->re, ctx->re));
+	      ctx->re++;
+	      switch (*ctx->re)
+		{
+		default:
+		  if (!(ctx->cflags & REG_EXTENDED) && tre_isdigit(*ctx->re))
+		    {
+		      /* Back reference. */
+		      int val = *ctx->re - '0';
+		      DPRINT(("tre_parse:     backref: '%.*" STRF "'\n",
+			      ctx->re_end - ctx->re + 1, ctx->re - 1));
+		      result = tre_ast_new_literal(ctx->mem, BACKREF, val,
+						   ctx->position);
+		      if (result == NULL)
+			return REG_ESPACE;
+		      ctx->position++;
+		      ctx->max_backref = MAX(val, ctx->max_backref);
+		      ctx->re++;
+		    }
+		  else
+		    {
+		      /* Escaped character. */
+		      DPRINT(("tre_parse:     escaped: '%.*" STRF "'\n",
+			      ctx->re_end - ctx->re + 1, ctx->re - 1));
+		      result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re,
+						   ctx->position);
+		      ctx->position++;
+		      ctx->re++;
+		    }
+		  break;
+		}
+	      if (result == NULL)
+		return REG_ESPACE;
+	      break;
+
+	    case '.':	 /* the any-symbol */
+	      DPRINT(("tre_parse:	  any: '%.*" STRF "'\n",
+		      ctx->re_end - ctx->re, ctx->re));
+	      if (ctx->cflags & REG_NEWLINE)
+		{
+		  tre_ast_node_t *tmp1;
+		  tre_ast_node_t *tmp2;
+		  tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n' - 1,
+					     ctx->position);
+		  if (!tmp1)
+		    return REG_ESPACE;
+		  tmp2 = tre_ast_new_literal(ctx->mem, '\n' + 1, TRE_CHAR_MAX,
+					     ctx->position + 1);
+		  if (!tmp2)
+		    return REG_ESPACE;
+		  result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
+		  if (!result)
+		    return REG_ESPACE;
+		  ctx->position += 2;
+		}
+	      else
+		{
+		  result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX,
+					       ctx->position);
+		  if (!result)
+		    return REG_ESPACE;
+		  ctx->position++;
+		}
+	      ctx->re++;
+	      break;
+
+	    case '^':	 /* beginning of line assertion */
+	      /* '^' has a special meaning everywhere in EREs, and in the
+		 beginning of the RE and after \( is BREs. */
+	      if (ctx->cflags & REG_EXTENDED
+		  || (ctx->re - 2 >= ctx->re_start
+		      && *(ctx->re - 2) == '\\'
+		      && *(ctx->re - 1) == '(')
+		  || ctx->re == ctx->re_start)
+		{
+		  DPRINT(("tre_parse:	      BOL: '%.*" STRF "'\n",
+			  ctx->re_end - ctx->re, ctx->re));
+		  result = tre_ast_new_literal(ctx->mem, ASSERTION,
+					       ASSERT_AT_BOL, -1);
+		  if (result == NULL)
+		    return REG_ESPACE;
+		  ctx->re++;
+		}
+	      else
+		goto parse_literal;
+	      break;
+
+	    case '$':	 /* end of line assertion. */
+	      /* '$' is special everywhere in EREs, and in the end of the
+		 string and before \) is BREs. */
+	      if (ctx->cflags & REG_EXTENDED
+		  || (ctx->re + 2 < ctx->re_end
+		      && *(ctx->re + 1) == '\\'
+		      && *(ctx->re + 2) == ')')
+		  || ctx->re + 1 == ctx->re_end)
+		{
+		  DPRINT(("tre_parse:	      EOL: '%.*" STRF "'\n",
+			  ctx->re_end - ctx->re, ctx->re));
+		  result = tre_ast_new_literal(ctx->mem, ASSERTION,
+					       ASSERT_AT_EOL, -1);
+		  if (result == NULL)
+		    return REG_ESPACE;
+		  ctx->re++;
+		}
+	      else
+		goto parse_literal;
+	      break;
+
+	    default:
+	    parse_literal:
+
+	      /* We are expecting an atom.  If the subexpression (or the whole
+		 regexp ends here, we interpret it as an empty expression
+		 (which matches an empty string).  */
+	      if (
+		  (ctx->re >= ctx->re_end
+		   || *ctx->re == '*'
+		   || (ctx->cflags & REG_EXTENDED
+		       && (*ctx->re == '|'
+			   || *ctx->re == '{'
+			   || *ctx->re == '+'
+			   || *ctx->re == '?'))
+		   /* Test for "\)" in BRE mode. */
+		   || (!(ctx->cflags & REG_EXTENDED)
+		       && ctx->re + 1 < ctx->re_end
+		       && *ctx->re == '\\'
+		       && *(ctx->re + 1) == '{')))
+		{
+		  DPRINT(("tre_parse:	    empty: '%.*" STRF "'\n",
+			  ctx->re_end - ctx->re, ctx->re));
+		  result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
+		  if (!result)
+		    return REG_ESPACE;
+		  break;
+		}
+
+	      DPRINT(("tre_parse:     literal: '%.*" STRF "'\n",
+		      ctx->re_end - ctx->re, ctx->re));
+	      /* Note that we can't use an tre_isalpha() test here, since there
+		 may be characters which are alphabetic but neither upper or
+		 lower case. */
+	      if (ctx->cflags & REG_ICASE
+		  && (tre_isupper(*ctx->re) || tre_islower(*ctx->re)))
+		{
+		  tre_ast_node_t *tmp1;
+		  tre_ast_node_t *tmp2;
+
+		  /* XXX - Can there be more than one opposite-case
+		     counterpoints for some character in some locale?  Or
+		     more than two characters which all should be regarded
+		     the same character if case is ignored?  If yes, there
+		     does not seem to be a portable way to detect it.  I guess
+		     that at least for multi-character collating elements there
+		     could be several opposite-case counterpoints, but they
+		     cannot be supported portably anyway. */
+		  tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(*ctx->re),
+					     tre_toupper(*ctx->re),
+					     ctx->position);
+		  if (!tmp1)
+		    return REG_ESPACE;
+		  tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(*ctx->re),
+					     tre_tolower(*ctx->re),
+					     ctx->position);
+		  if (!tmp2)
+		    return REG_ESPACE;
+		  result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
+		  if (!result)
+		    return REG_ESPACE;
+		}
+	      else
+		{
+		  result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re,
+					       ctx->position);
+		  if (!result)
+		    return REG_ESPACE;
+		}
+	      ctx->position++;
+	      ctx->re++;
+	      break;
+	    }
+	  break;
+
+	case PARSE_MARK_FOR_SUBMATCH:
+	  {
+	    int submatch_id = (int)tre_stack_pop(stack);
+
+	    if (result->submatch_id >= 0)
+	      {
+		tre_ast_node_t *n, *tmp_node;
+		n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
+		if (n == NULL)
+		  return REG_ESPACE;
+		tmp_node = tre_ast_new_catenation(ctx->mem, n, result);
+		if (tmp_node == NULL)
+		  return REG_ESPACE;
+		tmp_node->num_submatches = result->num_submatches;
+		result = tmp_node;
+	      }
+	    result->submatch_id = submatch_id;
+	    result->num_submatches++;
+	    break;
+	  }
+
+	case PARSE_RESTORE_CFLAGS:
+	  ctx->cflags = (int)tre_stack_pop(stack);
+	  break;
+	}
+    }
+
+  /* Check for missing closing parentheses. */
+  if (depth > 0)
+    return REG_EPAREN;
+
+  if (status == REG_OK)
+    ctx->result = result;
+
+  return status;
+}
+
+
+/***********************************************************************
+ from tre-compile.c
+***********************************************************************/
+
+/*
+  Algorithms to setup tags so that submatch addressing can be done.
+*/
+
+
+/* Inserts a catenation node to the root of the tree given in `node'.
+   As the left child a new tag with number `tag_id' to `node' is added,
+   and the right child is the old root. */
+/*              OR                  */
+/* Inserts a catenation node to the root of the tree given in `node'.
+   As the right child a new tag with number `tag_id' to `node' is added,
+   and the left child is the old root. */
+static reg_errcode_t
+tre_add_tag(tre_mem_t mem, tre_ast_node_t *node, int tag_id, int right)
+{
+  tre_catenation_t *c;
+  tre_ast_node_t *child_tag, *child_old;
+
+  DPRINT(("add_tag_%s: tag %d\n", right ? "right" : "left", tag_id));
+
+  c = tre_mem_alloc(mem, sizeof(*c));
+  if (c == NULL)
+    return REG_ESPACE;
+  child_tag = tre_ast_new_literal(mem, TAG, tag_id, -1);
+  if (child_tag == NULL)
+    return REG_ESPACE;
+  child_old = tre_mem_alloc(mem, sizeof(tre_ast_node_t));
+  if (child_old == NULL)
+    return REG_ESPACE;
+
+  child_old->obj = node->obj;
+  child_old->type = node->type;
+  child_old->nullable = -1;
+  child_old->submatch_id = -1;
+  child_old->firstpos = NULL;
+  child_old->lastpos = NULL;
+  child_old->num_tags = 0;
+  node->obj = c;
+  node->type = CATENATION;
+
+  c->right = c->left = child_old;
+  if (right) c->right = child_tag;
+  else c->left = child_tag;
+
+  return REG_OK;
+}
+
+typedef enum {
+  ADDTAGS_RECURSE,
+  ADDTAGS_AFTER_ITERATION,
+  ADDTAGS_AFTER_UNION_LEFT,
+  ADDTAGS_AFTER_UNION_RIGHT,
+  ADDTAGS_AFTER_CAT_LEFT,
+  ADDTAGS_AFTER_CAT_RIGHT,
+  ADDTAGS_SET_SUBMATCH_END
+} tre_addtags_symbol_t;
+
+
+typedef struct {
+  int tag;
+  int next_tag;
+} tre_tag_states_t;
+
+/* Adds tags to appropriate locations in the parse tree in `tree', so that
+   subexpressions marked for submatch addressing can be traced. */
+static reg_errcode_t
+tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree,
+	     tre_tnfa_t *tnfa)
+{
+  reg_errcode_t status = REG_OK;
+  tre_addtags_symbol_t symbol;
+  tre_ast_node_t *node = tree; /* Tree node we are currently looking at. */
+  int bottom = tre_stack_num_objects(stack);
+  /* True for first pass (counting number of needed tags) */
+  int first_pass = (mem == NULL || tnfa == NULL);
+  int *regset, *orig_regset;
+  int num_tags = 0; /* Total number of tags. */
+  int tag = 0;	    /* The tag that is to be added next. */
+  int next_tag = 1; /* Next tag to use after this one. */
+  int *parents;	    /* Stack of submatches the current submatch is
+		       contained in. */
+  tre_tag_states_t *saved_states;
+
+  tre_tag_direction_t direction = TRE_TAG_MINIMIZE;
+  if (!first_pass)
+      tnfa->end_tag = 0;
+
+  regset = xmalloc(sizeof(*regset) * ((tnfa->num_submatches + 1) * 2));
+  if (regset == NULL)
+    return REG_ESPACE;
+  regset[0] = -1;
+  orig_regset = regset;
+
+  parents = xmalloc(sizeof(*parents) * (tnfa->num_submatches + 1));
+  if (parents == NULL)
+    {
+      xfree(regset);
+      return REG_ESPACE;
+    }
+  parents[0] = -1;
+
+  saved_states = xmalloc(sizeof(*saved_states) * (tnfa->num_submatches + 1));
+  if (saved_states == NULL)
+    {
+      xfree(regset);
+      xfree(parents);
+      return REG_ESPACE;
+    }
+  else
+    {
+      unsigned int i;
+      for (i = 0; i <= tnfa->num_submatches; i++)
+	saved_states[i].tag = -1;
+    }
+
+  STACK_PUSH(stack, node);
+  STACK_PUSH(stack, ADDTAGS_RECURSE);
+
+  while (tre_stack_num_objects(stack) > bottom)
+    {
+      if (status != REG_OK)
+	break;
+
+      symbol = (tre_addtags_symbol_t)tre_stack_pop(stack);
+      switch (symbol)
+	{
+
+	case ADDTAGS_SET_SUBMATCH_END:
+	  {
+	    int id = (int)tre_stack_pop(stack);
+	    int i;
+
+	    /* Add end of this submatch to regset. */
+	    for (i = 0; regset[i] >= 0; i++);
+	    regset[i] = id * 2 + 1;
+	    regset[i + 1] = -1;
+
+	    /* Pop this submatch from the parents stack. */
+	    for (i = 0; parents[i] >= 0; i++);
+	    parents[i - 1] = -1;
+	    break;
+	  }
+
+	case ADDTAGS_RECURSE:
+	  node = tre_stack_pop(stack);
+
+	  if (node->submatch_id >= 0)
+	    {
+	      int id = node->submatch_id;
+	      int i;
+
+
+	      /* Add start of this submatch to regset. */
+	      for (i = 0; regset[i] >= 0; i++);
+	      regset[i] = id * 2;
+	      regset[i + 1] = -1;
+
+	      if (!first_pass)
+		{
+		  for (i = 0; parents[i] >= 0; i++);
+		  tnfa->submatch_data[id].parents = NULL;
+		  if (i > 0)
+		    {
+		      int *p = xmalloc(sizeof(*p) * (i + 1));
+		      if (p == NULL)
+			{
+			  status = REG_ESPACE;
+			  break;
+			}
+		      assert(tnfa->submatch_data[id].parents == NULL);
+		      tnfa->submatch_data[id].parents = p;
+		      for (i = 0; parents[i] >= 0; i++)
+			p[i] = parents[i];
+		      p[i] = -1;
+		    }
+		}
+
+	      /* Add end of this submatch to regset after processing this
+		 node. */
+	      STACK_PUSHX(stack, node->submatch_id);
+	      STACK_PUSHX(stack, ADDTAGS_SET_SUBMATCH_END);
+	    }
+
+	  switch (node->type)
+	    {
+	    case LITERAL:
+	      {
+		tre_literal_t *lit = node->obj;
+
+		if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
+		  {
+		    int i;
+		    DPRINT(("Literal %d-%d\n",
+			    (int)lit->code_min, (int)lit->code_max));
+		    if (regset[0] >= 0)
+		      {
+			/* Regset is not empty, so add a tag before the
+			   literal or backref. */
+			if (!first_pass)
+			  {
+			    status = tre_add_tag(mem, node, tag, 0 /*left*/);
+			    tnfa->tag_directions[tag] = direction;
+			    /* Go through the regset and set submatch data for
+			       submatches that are using this tag. */
+			    for (i = 0; regset[i] >= 0; i++)
+			      {
+				int id = regset[i] >> 1;
+				int start = !(regset[i] & 1);
+				DPRINT(("  Using tag %d for %s offset of "
+					"submatch %d\n", tag,
+					start ? "start" : "end", id));
+				if (start)
+				  tnfa->submatch_data[id].so_tag = tag;
+				else
+				  tnfa->submatch_data[id].eo_tag = tag;
+			      }
+			  }
+			else
+			  {
+			    DPRINT(("  num_tags = 1\n"));
+			    node->num_tags = 1;
+			  }
+
+			DPRINT(("  num_tags++\n"));
+			regset[0] = -1;
+			tag = next_tag;
+			num_tags++;
+			next_tag++;
+		      }
+		  }
+		else
+		  {
+		    assert(!IS_TAG(lit));
+		  }
+		break;
+	      }
+	    case CATENATION:
+	      {
+		tre_catenation_t *cat = node->obj;
+		tre_ast_node_t *left = cat->left;
+		tre_ast_node_t *right = cat->right;
+		int reserved_tag = -1;
+		DPRINT(("Catenation, next_tag = %d\n", next_tag));
+
+
+		/* After processing right child. */
+		STACK_PUSHX(stack, node);
+		STACK_PUSHX(stack, ADDTAGS_AFTER_CAT_RIGHT);
+
+		/* Process right child. */
+		STACK_PUSHX(stack, right);
+		STACK_PUSHX(stack, ADDTAGS_RECURSE);
+
+		/* After processing left child. */
+		STACK_PUSHX(stack, next_tag + left->num_tags);
+		DPRINT(("  Pushing %d for after left\n",
+			next_tag + left->num_tags));
+		if (left->num_tags > 0 && right->num_tags > 0)
+		  {
+		    /* Reserve the next tag to the right child. */
+		    DPRINT(("  Reserving next_tag %d to right child\n",
+			    next_tag));
+		    reserved_tag = next_tag;
+		    next_tag++;
+		  }
+		STACK_PUSHX(stack, reserved_tag);
+		STACK_PUSHX(stack, ADDTAGS_AFTER_CAT_LEFT);
+
+		/* Process left child. */
+		STACK_PUSHX(stack, left);
+		STACK_PUSHX(stack, ADDTAGS_RECURSE);
+
+		}
+	      break;
+	    case ITERATION:
+	      {
+		tre_iteration_t *iter = node->obj;
+		DPRINT(("Iteration\n"));
+
+		if (first_pass)
+		  {
+		    STACK_PUSHX(stack, regset[0] >= 0);
+		  }
+		else
+		  {
+		    STACK_PUSHX(stack, tag);
+		  }
+		STACK_PUSHX(stack, node);
+		STACK_PUSHX(stack, ADDTAGS_AFTER_ITERATION);
+
+		STACK_PUSHX(stack, iter->arg);
+		STACK_PUSHX(stack, ADDTAGS_RECURSE);
+
+		/* Regset is not empty, so add a tag here. */
+		if (regset[0] >= 0)
+		  {
+		    if (!first_pass)
+		      {
+			int i;
+			status = tre_add_tag(mem, node, tag, 0 /*left*/);
+			tnfa->tag_directions[tag] = direction;
+			/* Go through the regset and set submatch data for
+			   submatches that are using this tag. */
+			for (i = 0; regset[i] >= 0; i++)
+			  {
+			    int id = regset[i] >> 1;
+			    int start = !(regset[i] & 1);
+			    DPRINT(("  Using tag %d for %s offset of "
+				    "submatch %d\n", tag,
+				    start ? "start" : "end", id));
+			    if (start)
+			      tnfa->submatch_data[id].so_tag = tag;
+			    else
+			      tnfa->submatch_data[id].eo_tag = tag;
+			  }
+		      }
+
+		    DPRINT(("  num_tags++\n"));
+		    regset[0] = -1;
+		    tag = next_tag;
+		    num_tags++;
+		    next_tag++;
+		  }
+		direction = TRE_TAG_MINIMIZE;
+	      }
+	      break;
+	    case UNION:
+	      {
+		tre_union_t *uni = node->obj;
+		tre_ast_node_t *left = uni->left;
+		tre_ast_node_t *right = uni->right;
+		int left_tag;
+		int right_tag;
+
+		if (regset[0] >= 0)
+		  {
+		    left_tag = next_tag;
+		    right_tag = next_tag + 1;
+		  }
+		else
+		  {
+		    left_tag = tag;
+		    right_tag = next_tag;
+		  }
+
+		DPRINT(("Union\n"));
+
+		/* After processing right child. */
+		STACK_PUSHX(stack, right_tag);
+		STACK_PUSHX(stack, left_tag);
+		STACK_PUSHX(stack, regset);
+		STACK_PUSHX(stack, regset[0] >= 0);
+		STACK_PUSHX(stack, node);
+		STACK_PUSHX(stack, right);
+		STACK_PUSHX(stack, left);
+		STACK_PUSHX(stack, ADDTAGS_AFTER_UNION_RIGHT);
+
+		/* Process right child. */
+		STACK_PUSHX(stack, right);
+		STACK_PUSHX(stack, ADDTAGS_RECURSE);
+
+		/* After processing left child. */
+		STACK_PUSHX(stack, ADDTAGS_AFTER_UNION_LEFT);
+
+		/* Process left child. */
+		STACK_PUSHX(stack, left);
+		STACK_PUSHX(stack, ADDTAGS_RECURSE);
+
+		/* Regset is not empty, so add a tag here. */
+		if (regset[0] >= 0)
+		  {
+		    if (!first_pass)
+		      {
+			int i;
+			status = tre_add_tag(mem, node, tag, 0 /*left*/);
+			tnfa->tag_directions[tag] = direction;
+			/* Go through the regset and set submatch data for
+			   submatches that are using this tag. */
+			for (i = 0; regset[i] >= 0; i++)
+			  {
+			    int id = regset[i] >> 1;
+			    int start = !(regset[i] & 1);
+			    DPRINT(("  Using tag %d for %s offset of "
+				    "submatch %d\n", tag,
+				    start ? "start" : "end", id));
+			    if (start)
+			      tnfa->submatch_data[id].so_tag = tag;
+			    else
+			      tnfa->submatch_data[id].eo_tag = tag;
+			  }
+		      }
+
+		    DPRINT(("  num_tags++\n"));
+		    regset[0] = -1;
+		    tag = next_tag;
+		    num_tags++;
+		    next_tag++;
+		  }
+
+		if (node->num_submatches > 0)
+		  {
+		    /* The next two tags are reserved for markers. */
+		    next_tag++;
+		    tag = next_tag;
+		    next_tag++;
+		  }
+
+		break;
+	      }
+	    }
+
+	  if (node->submatch_id >= 0)
+	    {
+	      int i;
+	      /* Push this submatch on the parents stack. */
+	      for (i = 0; parents[i] >= 0; i++);
+	      parents[i] = node->submatch_id;
+	      parents[i + 1] = -1;
+	    }
+
+	  break; /* end case: ADDTAGS_RECURSE */
+
+	case ADDTAGS_AFTER_ITERATION:
+	  {
+	    int enter_tag;
+	    node = tre_stack_pop(stack);
+	    if (first_pass)
+		node->num_tags = ((tre_iteration_t *)node->obj)->arg->num_tags
+		  + (int)tre_stack_pop(stack);
+	    else
+		enter_tag = (int)tre_stack_pop(stack);
+
+	    DPRINT(("After iteration\n"));
+	    direction = TRE_TAG_MAXIMIZE;
+	    break;
+	  }
+
+	case ADDTAGS_AFTER_CAT_LEFT:
+	  {
+	    int new_tag = (int)tre_stack_pop(stack);
+	    next_tag = (int)tre_stack_pop(stack);
+	    DPRINT(("After cat left, tag = %d, next_tag = %d\n",
+		    tag, next_tag));
+	    if (new_tag >= 0)
+	      {
+		DPRINT(("  Setting tag to %d\n", new_tag));
+		tag = new_tag;
+	      }
+	    break;
+	  }
+
+	case ADDTAGS_AFTER_CAT_RIGHT:
+	  DPRINT(("After cat right\n"));
+	  node = tre_stack_pop(stack);
+	  if (first_pass)
+	    node->num_tags = ((tre_catenation_t *)node->obj)->left->num_tags
+	      + ((tre_catenation_t *)node->obj)->right->num_tags;
+	  break;
+
+	case ADDTAGS_AFTER_UNION_LEFT:
+	  DPRINT(("After union left\n"));
+	  /* Lift the bottom of the `regset' array so that when processing
+	     the right operand the items currently in the array are
+	     invisible.	 The original bottom was saved at ADDTAGS_UNION and
+	     will be restored at ADDTAGS_AFTER_UNION_RIGHT below. */
+	  while (*regset >= 0)
+	    regset++;
+	  break;
+
+	case ADDTAGS_AFTER_UNION_RIGHT:
+	  {
+	    int added_tags, tag_left, tag_right;
+	    tre_ast_node_t *left = tre_stack_pop(stack);
+	    tre_ast_node_t *right = tre_stack_pop(stack);
+	    DPRINT(("After union right\n"));
+	    node = tre_stack_pop(stack);
+	    added_tags = (int)tre_stack_pop(stack);
+	    if (first_pass)
+	      {
+		node->num_tags = ((tre_union_t *)node->obj)->left->num_tags
+		  + ((tre_union_t *)node->obj)->right->num_tags + added_tags
+		  + ((node->num_submatches > 0) ? 2 : 0);
+	      }
+	    regset = tre_stack_pop(stack);
+	    tag_left = (int)tre_stack_pop(stack);
+	    tag_right = (int)tre_stack_pop(stack);
+
+	    /* Add tags after both children, the left child gets a smaller
+	       tag than the right child.  This guarantees that we prefer
+	       the left child over the right child. */
+	    /* XXX - This is not always necessary (if the children have
+	       tags which must be seen for every match of that child). */
+	    /* XXX - Check if this is the only place where tre_add_tag_right
+	       is used.	 If so, use tre_add_tag_left (putting the tag before
+	       the child as opposed after the child) and throw away
+	       tre_add_tag_right. */
+	    if (node->num_submatches > 0)
+	      {
+		if (!first_pass)
+		  {
+		    status = tre_add_tag(mem, left, tag_left, 1 /*right*/);
+		    tnfa->tag_directions[tag] = TRE_TAG_MAXIMIZE;
+		    status = tre_add_tag(mem, right, tag_right, 1 /*right*/);
+		    tnfa->tag_directions[tag] = TRE_TAG_MAXIMIZE;
+		  }
+		DPRINT(("  num_tags += 2\n"));
+		num_tags += 2;
+	      }
+	    direction = TRE_TAG_MAXIMIZE;
+	    break;
+	  }
+
+	default:
+	  assert(0);
+	  break;
+
+	} /* end switch(symbol) */
+    } /* end while(tre_stack_num_objects(stack) > bottom) */
+
+  if (!first_pass)
+    {
+      int i;
+      /* Go through the regset and set submatch data for
+	 submatches that are using this tag. */
+      for (i = 0; regset[i] >= 0; i++)
+	{
+	  int id = regset[i] >> 1;
+	  int start = !(regset[i] & 1);
+	  DPRINT(("  Using tag %d for %s offset of "
+		  "submatch %d\n", num_tags,
+		  start ? "start" : "end", id));
+	  if (start)
+	    tnfa->submatch_data[id].so_tag = num_tags;
+	  else
+	    tnfa->submatch_data[id].eo_tag = num_tags;
+	}
+    }
+
+  DPRINT(("tre_add_tags: %s complete.  Number of tags %d.\n",
+	  first_pass? "First pass" : "Second pass", num_tags));
+
+  assert(tree->num_tags == num_tags);
+  tnfa->end_tag = num_tags;
+  tnfa->num_tags = num_tags;
+  xfree(orig_regset);
+  xfree(parents);
+  xfree(saved_states);
+  return status;
+}
+
+
+
+/*
+  AST to TNFA compilation routines.
+*/
+
+typedef enum {
+  COPY_RECURSE,
+  COPY_SET_RESULT_PTR
+} tre_copyast_symbol_t;
+
+/* Flags for tre_copy_ast(). */
+#define COPY_REMOVE_TAGS	 1
+#define COPY_MAXIMIZE_FIRST_TAG	 2
+
+static reg_errcode_t
+tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
+	     int flags, int *pos_add, tre_tag_direction_t *tag_directions,
+	     tre_ast_node_t **copy, int *max_pos)
+{
+  reg_errcode_t status = REG_OK;
+  int bottom = tre_stack_num_objects(stack);
+  int num_copied = 0;
+  int first_tag = 1;
+  tre_ast_node_t **result = copy;
+  tre_copyast_symbol_t symbol;
+
+  STACK_PUSH(stack, ast);
+  STACK_PUSH(stack, COPY_RECURSE);
+
+  while (status == REG_OK && tre_stack_num_objects(stack) > bottom)
+    {
+      tre_ast_node_t *node;
+      if (status != REG_OK)
+	break;
+
+      symbol = (tre_copyast_symbol_t)tre_stack_pop(stack);
+      switch (symbol)
+	{
+	case COPY_SET_RESULT_PTR:
+	  result = tre_stack_pop(stack);
+	  break;
+	case COPY_RECURSE:
+	  node = tre_stack_pop(stack);
+	  switch (node->type)
+	    {
+	    case LITERAL:
+	      {
+		tre_literal_t *lit = node->obj;
+		int pos = lit->position;
+		int min = lit->code_min;
+		int max = lit->code_max;
+		if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
+		  {
+		    /* XXX - e.g. [ab] has only one position but two
+		       nodes, so we are creating holes in the state space
+		       here.  Not fatal, just wastes memory. */
+		    pos += *pos_add;
+		    num_copied++;
+		  }
+		else if (IS_TAG(lit) && (flags & COPY_REMOVE_TAGS))
+		  {
+		    /* Change this tag to empty. */
+		    min = EMPTY;
+		    max = pos = -1;
+		  }
+		else if (IS_TAG(lit) && (flags & COPY_MAXIMIZE_FIRST_TAG)
+			 && first_tag)
+		  {
+		    /* Maximize the first tag. */
+		    tag_directions[max] = TRE_TAG_MAXIMIZE;
+		    first_tag = 0;
+		  }
+		*result = tre_ast_new_literal(mem, min, max, pos);
+		if (*result == NULL)
+		  status = REG_ESPACE;
+
+		if (pos > *max_pos)
+		  *max_pos = pos;
+		break;
+	      }
+	    case UNION:
+	      {
+		tre_union_t *uni = node->obj;
+		tre_union_t *copy;
+		*result = tre_ast_new_union(mem, uni->left, uni->right);
+		if (*result == NULL)
+		  {
+		    status = REG_ESPACE;
+		    break;
+		  }
+		copy = (*result)->obj;
+		result = &copy->left;
+		STACK_PUSHX(stack, uni->right);
+		STACK_PUSHX(stack, COPY_RECURSE);
+		STACK_PUSHX(stack, &copy->right);
+		STACK_PUSHX(stack, COPY_SET_RESULT_PTR);
+		STACK_PUSHX(stack, uni->left);
+		STACK_PUSHX(stack, COPY_RECURSE);
+		break;
+	      }
+	    case CATENATION:
+	      {
+		tre_catenation_t *cat = node->obj;
+		tre_catenation_t *copy;
+		*result = tre_ast_new_catenation(mem, cat->left, cat->right);
+		if (*result == NULL)
+		  {
+		    status = REG_ESPACE;
+		    break;
+		  }
+		copy = (*result)->obj;
+		copy->left = NULL;
+		copy->right = NULL;
+		result = &copy->left;
+
+		STACK_PUSHX(stack, cat->right);
+		STACK_PUSHX(stack, COPY_RECURSE);
+		STACK_PUSHX(stack, &copy->right);
+		STACK_PUSHX(stack, COPY_SET_RESULT_PTR);
+		STACK_PUSHX(stack, cat->left);
+		STACK_PUSHX(stack, COPY_RECURSE);
+		break;
+	      }
+	    case ITERATION:
+	      {
+		tre_iteration_t *iter = node->obj;
+		STACK_PUSHX(stack, iter->arg);
+		STACK_PUSHX(stack, COPY_RECURSE);
+		*result = tre_ast_new_iter(mem, iter->arg, iter->min, iter->max);
+		if (*result == NULL)
+		  {
+		    status = REG_ESPACE;
+		    break;
+		  }
+		iter = (*result)->obj;
+		result = &iter->arg;
+		break;
+	      }
+	    default:
+	      assert(0);
+	      break;
+	    }
+	  break;
+	}
+    }
+  *pos_add += num_copied;
+  return status;
+}
+
+typedef enum {
+  EXPAND_RECURSE,
+  EXPAND_AFTER_ITER
+} tre_expand_ast_symbol_t;
+
+/* Expands each iteration node that has a finite nonzero minimum or maximum
+   iteration count to a catenated sequence of copies of the node. */
+static reg_errcode_t
+tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
+	       int *position, tre_tag_direction_t *tag_directions,
+	       int *max_depth)
+{
+  reg_errcode_t status = REG_OK;
+  int bottom = tre_stack_num_objects(stack);
+  int pos_add = 0;
+  int pos_add_total = 0;
+  int max_pos = 0;
+  /* Approximate parameter nesting level. */
+  int iter_depth = 0;
+
+  STACK_PUSHR(stack, ast);
+  STACK_PUSHR(stack, EXPAND_RECURSE);
+  while (status == REG_OK && tre_stack_num_objects(stack) > bottom)
+    {
+      tre_ast_node_t *node;
+      tre_expand_ast_symbol_t symbol;
+
+      if (status != REG_OK)
+	break;
+
+      DPRINT(("pos_add %d\n", pos_add));
+
+      symbol = (tre_expand_ast_symbol_t)tre_stack_pop(stack);
+      node = tre_stack_pop(stack);
+      switch (symbol)
+	{
+	case EXPAND_RECURSE:
+	  switch (node->type)
+	    {
+	    case LITERAL:
+	      {
+		tre_literal_t *lit= node->obj;
+		if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
+		  {
+		    lit->position += pos_add;
+		    if (lit->position > max_pos)
+		      max_pos = lit->position;
+		  }
+		break;
+	      }
+	    case UNION:
+	      {
+		tre_union_t *uni = node->obj;
+		STACK_PUSHX(stack, uni->right);
+		STACK_PUSHX(stack, EXPAND_RECURSE);
+		STACK_PUSHX(stack, uni->left);
+		STACK_PUSHX(stack, EXPAND_RECURSE);
+		break;
+	      }
+	    case CATENATION:
+	      {
+		tre_catenation_t *cat = node->obj;
+		STACK_PUSHX(stack, cat->right);
+		STACK_PUSHX(stack, EXPAND_RECURSE);
+		STACK_PUSHX(stack, cat->left);
+		STACK_PUSHX(stack, EXPAND_RECURSE);
+		break;
+	      }
+	    case ITERATION:
+	      {
+		tre_iteration_t *iter = node->obj;
+		STACK_PUSHX(stack, pos_add);
+		STACK_PUSHX(stack, node);
+		STACK_PUSHX(stack, EXPAND_AFTER_ITER);
+		STACK_PUSHX(stack, iter->arg);
+		STACK_PUSHX(stack, EXPAND_RECURSE);
+		/* If we are going to expand this node at EXPAND_AFTER_ITER
+		   then don't increase the `pos' fields of the nodes now, it
+		   will get done when expanding. */
+		if (iter->min > 1 || iter->max > 1)
+		  pos_add = 0;
+		iter_depth++;
+		DPRINT(("iter\n"));
+		break;
+	      }
+	    default:
+	      assert(0);
+	      break;
+	    }
+	  break;
+	case EXPAND_AFTER_ITER:
+	  {
+	    tre_iteration_t *iter = node->obj;
+	    int pos_add_last;
+	    pos_add = (int)tre_stack_pop(stack);
+	    pos_add_last = pos_add;
+	    if (iter->min > 1 || iter->max > 1)
+	      {
+		tre_ast_node_t *seq1 = NULL, *seq2 = NULL;
+		int i;
+		int pos_add_save = pos_add;
+
+		/* Create a catenated sequence of copies of the node. */
+		for (i = 0; i < iter->min; i++)
+		  {
+		    tre_ast_node_t *copy;
+		    /* Remove tags from all but the last copy. */
+		    int flags = ((i + 1 < iter->min)
+				 ? COPY_REMOVE_TAGS
+				 : COPY_MAXIMIZE_FIRST_TAG);
+		    DPRINT(("  pos_add %d\n", pos_add));
+		    pos_add_save = pos_add;
+		    status = tre_copy_ast(mem, stack, iter->arg, flags,
+					  &pos_add, tag_directions, &copy,
+					  &max_pos);
+		    if (status != REG_OK)
+		      return status;
+		    if (seq1 != NULL)
+		      seq1 = tre_ast_new_catenation(mem, seq1, copy);
+		    else
+		      seq1 = copy;
+		    if (seq1 == NULL)
+		      return REG_ESPACE;
+		  }
+
+		if (iter->max == -1)
+		  {
+		    /* No upper limit. */
+		    pos_add_save = pos_add;
+		    status = tre_copy_ast(mem, stack, iter->arg, 0,
+					  &pos_add, NULL, &seq2, &max_pos);
+		    if (status != REG_OK)
+		      return status;
+		    seq2 = tre_ast_new_iter(mem, seq2, 0, -1);
+		    if (seq2 == NULL)
+		      return REG_ESPACE;
+		  }
+		else
+		  {
+		    for (i = iter->min; i < iter->max; i++)
+		      {
+			tre_ast_node_t *tmp, *copy;
+			pos_add_save = pos_add;
+			status = tre_copy_ast(mem, stack, iter->arg, 0,
+					      &pos_add, NULL, &copy, &max_pos);
+			if (status != REG_OK)
+			  return status;
+			if (seq2 != NULL)
+			  seq2 = tre_ast_new_catenation(mem, copy, seq2);
+			else
+			  seq2 = copy;
+			if (seq2 == NULL)
+			  return REG_ESPACE;
+			tmp = tre_ast_new_literal(mem, EMPTY, -1, -1);
+			if (tmp == NULL)
+			  return REG_ESPACE;
+			seq2 = tre_ast_new_union(mem, tmp, seq2);
+			if (seq2 == NULL)
+			  return REG_ESPACE;
+		      }
+		  }
+
+		pos_add = pos_add_save;
+		if (seq1 == NULL)
+		  seq1 = seq2;
+		else if (seq2 != NULL)
+		  seq1 = tre_ast_new_catenation(mem, seq1, seq2);
+		if (seq1 == NULL)
+		  return REG_ESPACE;
+		node->obj = seq1->obj;
+		node->type = seq1->type;
+	      }
+
+	    iter_depth--;
+	    pos_add_total += pos_add - pos_add_last;
+	    if (iter_depth == 0)
+	      pos_add = pos_add_total;
+
+	    break;
+	  }
+	default:
+	  assert(0);
+	  break;
+	}
+    }
+
+  *position += pos_add_total;
+
+  /* `max_pos' should never be larger than `*position' if the above
+     code works, but just an extra safeguard let's make sure
+     `*position' is set large enough so enough memory will be
+     allocated for the transition table. */
+  if (max_pos > *position)
+    *position = max_pos;
+
+#ifdef TRE_DEBUG
+  DPRINT(("Expanded AST:\n"));
+  tre_ast_print(ast);
+  DPRINT(("*position %d, max_pos %d\n", *position, max_pos));
+#endif
+
+  return status;
+}
+
+static tre_pos_and_tags_t *
+tre_set_empty(tre_mem_t mem)
+{
+  tre_pos_and_tags_t *new_set;
+
+  new_set = tre_mem_calloc(mem, sizeof(*new_set));
+  if (new_set == NULL)
+    return NULL;
+
+  new_set[0].position = -1;
+  new_set[0].code_min = -1;
+  new_set[0].code_max = -1;
+
+  return new_set;
+}
+
+static tre_pos_and_tags_t *
+tre_set_one(tre_mem_t mem, int position, int code_min, int code_max,
+	    tre_ctype_t class, tre_ctype_t *neg_classes, int backref)
+{
+  tre_pos_and_tags_t *new_set;
+
+  new_set = tre_mem_calloc(mem, sizeof(*new_set) * 2);
+  if (new_set == NULL)
+    return NULL;
+
+  new_set[0].position = position;
+  new_set[0].code_min = code_min;
+  new_set[0].code_max = code_max;
+  new_set[0].class = class;
+  new_set[0].neg_classes = neg_classes;
+  new_set[0].backref = backref;
+  new_set[1].position = -1;
+  new_set[1].code_min = -1;
+  new_set[1].code_max = -1;
+
+  return new_set;
+}
+
+static tre_pos_and_tags_t *
+tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2,
+	      int *tags, int assertions)
+{
+  int s1, s2, i, j;
+  tre_pos_and_tags_t *new_set;
+  int *new_tags;
+  int num_tags;
+
+  for (num_tags = 0; tags != NULL && tags[num_tags] >= 0; num_tags++);
+  for (s1 = 0; set1[s1].position >= 0; s1++);
+  for (s2 = 0; set2[s2].position >= 0; s2++);
+  new_set = tre_mem_calloc(mem, sizeof(*new_set) * (s1 + s2 + 1));
+  if (!new_set )
+    return NULL;
+
+  for (s1 = 0; set1[s1].position >= 0; s1++)
+    {
+      new_set[s1].position = set1[s1].position;
+      new_set[s1].code_min = set1[s1].code_min;
+      new_set[s1].code_max = set1[s1].code_max;
+      new_set[s1].assertions = set1[s1].assertions | assertions;
+      new_set[s1].class = set1[s1].class;
+      new_set[s1].neg_classes = set1[s1].neg_classes;
+      new_set[s1].backref = set1[s1].backref;
+      if (set1[s1].tags == NULL && tags == NULL)
+	new_set[s1].tags = NULL;
+      else
+	{
+	  for (i = 0; set1[s1].tags != NULL && set1[s1].tags[i] >= 0; i++);
+	  new_tags = tre_mem_alloc(mem, (sizeof(*new_tags)
+					 * (i + num_tags + 1)));
+	  if (new_tags == NULL)
+	    return NULL;
+	  for (j = 0; j < i; j++)
+	    new_tags[j] = set1[s1].tags[j];
+	  for (i = 0; i < num_tags; i++)
+	    new_tags[j + i] = tags[i];
+	  new_tags[j + i] = -1;
+	  new_set[s1].tags = new_tags;
+	}
+    }
+
+  for (s2 = 0; set2[s2].position >= 0; s2++)
+    {
+      new_set[s1 + s2].position = set2[s2].position;
+      new_set[s1 + s2].code_min = set2[s2].code_min;
+      new_set[s1 + s2].code_max = set2[s2].code_max;
+      /* XXX - why not | assertions here as well? */
+      new_set[s1 + s2].assertions = set2[s2].assertions;
+      new_set[s1 + s2].class = set2[s2].class;
+      new_set[s1 + s2].neg_classes = set2[s2].neg_classes;
+      new_set[s1 + s2].backref = set2[s2].backref;
+      if (set2[s2].tags == NULL)
+	new_set[s1 + s2].tags = NULL;
+      else
+	{
+	  for (i = 0; set2[s2].tags[i] >= 0; i++);
+	  new_tags = tre_mem_alloc(mem, sizeof(*new_tags) * (i + 1));
+	  if (new_tags == NULL)
+	    return NULL;
+	  for (j = 0; j < i; j++)
+	    new_tags[j] = set2[s2].tags[j];
+	  new_tags[j] = -1;
+	  new_set[s1 + s2].tags = new_tags;
+	}
+    }
+  new_set[s1 + s2].position = -1;
+  return new_set;
+}
+
+/* Finds the empty path through `node' which is the one that should be
+   taken according to POSIX.2 rules, and adds the tags on that path to
+   `tags'.   `tags' may be NULL.  If `num_tags_seen' is not NULL, it is
+   set to the number of tags seen on the path. */
+static reg_errcode_t
+tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, int *tags,
+		int *assertions, int *num_tags_seen)
+{
+  tre_literal_t *lit;
+  tre_union_t *uni;
+  tre_catenation_t *cat;
+  tre_iteration_t *iter;
+  int i;
+  int bottom = tre_stack_num_objects(stack);
+  reg_errcode_t status = REG_OK;
+  if (num_tags_seen)
+    *num_tags_seen = 0;
+
+  status = tre_stack_push(stack, node);
+
+  /* Walk through the tree recursively. */
+  while (status == REG_OK && tre_stack_num_objects(stack) > bottom)
+    {
+      node = tre_stack_pop(stack);
+
+      switch (node->type)
+	{
+	case LITERAL:
+	  lit = (tre_literal_t *)node->obj;
+	  switch (lit->code_min)
+	    {
+	    case TAG:
+	      if (lit->code_max >= 0)
+		{
+		  if (tags != NULL)
+		    {
+		      /* Add the tag to `tags'. */
+		      for (i = 0; tags[i] >= 0; i++)
+			if (tags[i] == lit->code_max)
+			  break;
+		      if (tags[i] < 0)
+			{
+			  tags[i] = lit->code_max;
+			  tags[i + 1] = -1;
+			}
+		    }
+		  if (num_tags_seen)
+		    (*num_tags_seen)++;
+		}
+	      break;
+	    case ASSERTION:
+	      assert(lit->code_max >= 1
+		     || lit->code_max <= ASSERT_LAST);
+	      if (assertions != NULL)
+		*assertions |= lit->code_max;
+	      break;
+	    case EMPTY:
+	      break;
+	    default:
+	      assert(0);
+	      break;
+	    }
+	  break;
+
+	case UNION:
+	  /* Subexpressions starting earlier take priority over ones
+	     starting later, so we prefer the left subexpression over the
+	     right subexpression. */
+	  uni = (tre_union_t *)node->obj;
+	  if (uni->left->nullable)
+	    STACK_PUSHX(stack, uni->left)
+	  else if (uni->right->nullable)
+	    STACK_PUSHX(stack, uni->right)
+	  else
+	    assert(0);
+	  break;
+
+	case CATENATION:
+	  /* The path must go through both children. */
+	  cat = (tre_catenation_t *)node->obj;
+	  assert(cat->left->nullable);
+	  assert(cat->right->nullable);
+	  STACK_PUSHX(stack, cat->left);
+	  STACK_PUSHX(stack, cat->right);
+	  break;
+
+	case ITERATION:
+	  /* A match with an empty string is preferred over no match at
+	     all, so we go through the argument if possible. */
+	  iter = (tre_iteration_t *)node->obj;
+	  if (iter->arg->nullable)
+	    STACK_PUSHX(stack, iter->arg);
+	  break;
+
+	default:
+	  assert(0);
+	  break;
+	}
+    }
+
+  return status;
+}
+
+
+typedef enum {
+  NFL_RECURSE,
+  NFL_POST_UNION,
+  NFL_POST_CATENATION,
+  NFL_POST_ITERATION
+} tre_nfl_stack_symbol_t;
+
+
+/* Computes and fills in the fields `nullable', `firstpos', and `lastpos' for
+   the nodes of the AST `tree'. */
+static reg_errcode_t
+tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree)
+{
+  int bottom = tre_stack_num_objects(stack);
+
+  STACK_PUSHR(stack, tree);
+  STACK_PUSHR(stack, NFL_RECURSE);
+
+  while (tre_stack_num_objects(stack) > bottom)
+    {
+      tre_nfl_stack_symbol_t symbol;
+      tre_ast_node_t *node;
+
+      symbol = (tre_nfl_stack_symbol_t) tre_stack_pop(stack);
+      node = tre_stack_pop(stack);
+      switch (symbol)
+	{
+	case NFL_RECURSE:
+	  switch (node->type)
+	    {
+	    case LITERAL:
+	      {
+		tre_literal_t *lit = (tre_literal_t *)node->obj;
+		if (IS_BACKREF(lit))
+		  {
+		    /* Back references: nullable = false, firstpos = {i},
+		       lastpos = {i}. */
+		    node->nullable = 0;
+		    node->firstpos = tre_set_one(mem, lit->position, 0,
+					     TRE_CHAR_MAX, 0, NULL, -1);
+		    if (!node->firstpos)
+		      return REG_ESPACE;
+		    node->lastpos = tre_set_one(mem, lit->position, 0,
+						TRE_CHAR_MAX, 0, NULL,
+						lit->code_max);
+		    if (!node->lastpos)
+		      return REG_ESPACE;
+		  }
+		else if (lit->code_min < 0)
+		  {
+		    /* Tags, empty strings and zero width assertions:
+		       nullable = true, firstpos = {}, and lastpos = {}. */
+		    node->nullable = 1;
+		    node->firstpos = tre_set_empty(mem);
+		    if (!node->firstpos)
+		      return REG_ESPACE;
+		    node->lastpos = tre_set_empty(mem);
+		    if (!node->lastpos)
+		      return REG_ESPACE;
+		  }
+		else
+		  {
+		    /* Literal at position i: nullable = false, firstpos = {i},
+		       lastpos = {i}. */
+		    node->nullable = 0;
+		    node->firstpos =
+		      tre_set_one(mem, lit->position, lit->code_min,
+				  lit->code_max, 0, NULL, -1);
+		    if (!node->firstpos)
+		      return REG_ESPACE;
+		    node->lastpos = tre_set_one(mem, lit->position,
+						lit->code_min, lit->code_max,
+						lit->class, lit->neg_classes,
+						-1);
+		    if (!node->lastpos)
+		      return REG_ESPACE;
+		  }
+		break;
+	      }
+
+	    case UNION:
+	      /* Compute the attributes for the two subtrees, and after that
+		 for this node. */
+	      STACK_PUSHR(stack, node);
+	      STACK_PUSHR(stack, NFL_POST_UNION);
+	      STACK_PUSHR(stack, ((tre_union_t *)node->obj)->right);
+	      STACK_PUSHR(stack, NFL_RECURSE);
+	      STACK_PUSHR(stack, ((tre_union_t *)node->obj)->left);
+	      STACK_PUSHR(stack, NFL_RECURSE);
+	      break;
+
+	    case CATENATION:
+	      /* Compute the attributes for the two subtrees, and after that
+		 for this node. */
+	      STACK_PUSHR(stack, node);
+	      STACK_PUSHR(stack, NFL_POST_CATENATION);
+	      STACK_PUSHR(stack, ((tre_catenation_t *)node->obj)->right);
+	      STACK_PUSHR(stack, NFL_RECURSE);
+	      STACK_PUSHR(stack, ((tre_catenation_t *)node->obj)->left);
+	      STACK_PUSHR(stack, NFL_RECURSE);
+	      break;
+
+	    case ITERATION:
+	      /* Compute the attributes for the subtree, and after that for
+		 this node. */
+	      STACK_PUSHR(stack, node);
+	      STACK_PUSHR(stack, NFL_POST_ITERATION);
+	      STACK_PUSHR(stack, ((tre_iteration_t *)node->obj)->arg);
+	      STACK_PUSHR(stack, NFL_RECURSE);
+	      break;
+	    }
+	  break; /* end case: NFL_RECURSE */
+
+	case NFL_POST_UNION:
+	  {
+	    tre_union_t *uni = (tre_union_t *)node->obj;
+	    node->nullable = uni->left->nullable || uni->right->nullable;
+	    node->firstpos = tre_set_union(mem, uni->left->firstpos,
+					   uni->right->firstpos, NULL, 0);
+	    if (!node->firstpos)
+	      return REG_ESPACE;
+	    node->lastpos = tre_set_union(mem, uni->left->lastpos,
+					  uni->right->lastpos, NULL, 0);
+	    if (!node->lastpos)
+	      return REG_ESPACE;
+	    break;
+	  }
+
+	case NFL_POST_ITERATION:
+	  {
+	    tre_iteration_t *iter = (tre_iteration_t *)node->obj;
+
+	    if (iter->min == 0 || iter->arg->nullable)
+	      node->nullable = 1;
+	    else
+	      node->nullable = 0;
+	    node->firstpos = iter->arg->firstpos;
+	    node->lastpos = iter->arg->lastpos;
+	    break;
+	  }
+
+	case NFL_POST_CATENATION:
+	  {
+	    int num_tags, *tags, assertions;
+	    reg_errcode_t status;
+	    tre_catenation_t *cat = node->obj;
+	    node->nullable = cat->left->nullable && cat->right->nullable;
+
+	    /* Compute firstpos. */
+	    if (cat->left->nullable)
+	      {
+		/* The left side matches the empty string.  Make a first pass
+		   with tre_match_empty() to get the number of tags. */
+		status = tre_match_empty(stack, cat->left,
+					 NULL, NULL, &num_tags);
+		if (status != REG_OK)
+		  return status;
+		/* Allocate arrays for the tags and parameters. */
+		tags = xmalloc(sizeof(*tags) * (num_tags + 1));
+		if (!tags)
+		  return REG_ESPACE;
+		tags[0] = -1;
+		assertions = 0;
+		/* Second pass with tre_mach_empty() to get the list of
+		   tags. */
+		status = tre_match_empty(stack, cat->left, tags,
+					 &assertions, NULL);
+		if (status != REG_OK)
+		  {
+		    xfree(tags);
+		    return status;
+		  }
+		node->firstpos =
+		  tre_set_union(mem, cat->right->firstpos, cat->left->firstpos,
+				tags, assertions);
+		xfree(tags);
+		if (!node->firstpos)
+		  return REG_ESPACE;
+	      }
+	    else
+	      {
+		node->firstpos = cat->left->firstpos;
+	      }
+
+	    /* Compute lastpos. */
+	    if (cat->right->nullable)
+	      {
+		/* The right side matches the empty string.  Make a first pass
+		   with tre_match_empty() to get the number of tags. */
+		status = tre_match_empty(stack, cat->right,
+					 NULL, NULL, &num_tags);
+		if (status != REG_OK)
+		  return status;
+		/* Allocate arrays for the tags and parameters. */
+		tags = xmalloc(sizeof(int) * (num_tags + 1));
+		if (!tags)
+		  return REG_ESPACE;
+		tags[0] = -1;
+		assertions = 0;
+		/* Second pass with tre_mach_empty() to get the list of
+		   tags. */
+		status = tre_match_empty(stack, cat->right, tags,
+					 &assertions, NULL);
+		if (status != REG_OK)
+		  {
+		    xfree(tags);
+		    return status;
+		  }
+		node->lastpos =
+		  tre_set_union(mem, cat->left->lastpos, cat->right->lastpos,
+				tags, assertions);
+		xfree(tags);
+		if (!node->lastpos)
+		  return REG_ESPACE;
+	      }
+	    else
+	      {
+		node->lastpos = cat->right->lastpos;
+	      }
+	    break;
+	  }
+
+	default:
+	  assert(0);
+	  break;
+	}
+    }
+
+  return REG_OK;
+}
+
+
+/* Adds a transition from each position in `p1' to each position in `p2'. */
+static reg_errcode_t
+tre_make_trans(tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2,
+	       tre_tnfa_transition_t *transitions,
+	       int *counts, int *offs)
+{
+  tre_pos_and_tags_t *orig_p2 = p2;
+  tre_tnfa_transition_t *trans;
+  int i, j, k, l, dup, prev_p2_pos;
+
+  if (transitions != NULL)
+    while (p1->position >= 0)
+      {
+	p2 = orig_p2;
+	prev_p2_pos = -1;
+	while (p2->position >= 0)
+	  {
+	    /* Optimization: if this position was already handled, skip it. */
+	    if (p2->position == prev_p2_pos)
+	      {
+		p2++;
+		continue;
+	      }
+	    prev_p2_pos = p2->position;
+	    /* Set `trans' to point to the next unused transition from
+	       position `p1->position'. */
+	    trans = transitions + offs[p1->position];
+	    while (trans->state != NULL)
+	      {
+#if 0
+		/* If we find a previous transition from `p1->position' to
+		   `p2->position', it is overwritten.  This can happen only
+		   if there are nested loops in the regexp, like in "((a)*)*".
+		   In POSIX.2 repetition using the outer loop is always
+		   preferred over using the inner loop.	 Therefore the
+		   transition for the inner loop is useless and can be thrown
+		   away. */
+		/* XXX - The same position is used for all nodes in a bracket
+		   expression, so this optimization cannot be used (it will
+		   break bracket expressions) unless I figure out a way to
+		   detect it here. */
+		if (trans->state_id == p2->position)
+		  {
+		    DPRINT(("*"));
+		    break;
+		  }
+#endif
+		trans++;
+	      }
+
+	    if (trans->state == NULL)
+	      (trans + 1)->state = NULL;
+	    /* Use the character ranges, assertions, etc. from `p1' for
+	       the transition from `p1' to `p2'. */
+	    trans->code_min = p1->code_min;
+	    trans->code_max = p1->code_max;
+	    trans->state = transitions + offs[p2->position];
+	    trans->state_id = p2->position;
+	    trans->assertions = p1->assertions | p2->assertions
+	      | (p1->class ? ASSERT_CHAR_CLASS : 0)
+	      | (p1->neg_classes != NULL ? ASSERT_CHAR_CLASS_NEG : 0);
+	    if (p1->backref >= 0)
+	      {
+		assert((trans->assertions & ASSERT_CHAR_CLASS) == 0);
+		assert(p2->backref < 0);
+		trans->u.backref = p1->backref;
+		trans->assertions |= ASSERT_BACKREF;
+	      }
+	    else
+	      trans->u.class = p1->class;
+	    if (p1->neg_classes != NULL)
+	      {
+		for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++);
+		trans->neg_classes =
+		  xmalloc(sizeof(*trans->neg_classes) * (i + 1));
+		if (trans->neg_classes == NULL)
+		  return REG_ESPACE;
+		for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++)
+		  trans->neg_classes[i] = p1->neg_classes[i];
+		trans->neg_classes[i] = (tre_ctype_t)0;
+	      }
+	    else
+	      trans->neg_classes = NULL;
+
+	    /* Find out how many tags this transition has. */
+	    i = 0;
+	    if (p1->tags != NULL)
+	      while(p1->tags[i] >= 0)
+		i++;
+	    j = 0;
+	    if (p2->tags != NULL)
+	      while(p2->tags[j] >= 0)
+		j++;
+
+	    /* If we are overwriting a transition, free the old tag array. */
+	    if (trans->tags != NULL)
+	      xfree(trans->tags);
+	    trans->tags = NULL;
+
+	    /* If there were any tags, allocate an array and fill it. */
+	    if (i + j > 0)
+	      {
+		trans->tags = xmalloc(sizeof(*trans->tags) * (i + j + 1));
+		if (!trans->tags)
+		  return REG_ESPACE;
+		i = 0;
+		if (p1->tags != NULL)
+		  while(p1->tags[i] >= 0)
+		    {
+		      trans->tags[i] = p1->tags[i];
+		      i++;
+		    }
+		l = i;
+		j = 0;
+		if (p2->tags != NULL)
+		  while (p2->tags[j] >= 0)
+		    {
+		      /* Don't add duplicates. */
+		      dup = 0;
+		      for (k = 0; k < i; k++)
+			if (trans->tags[k] == p2->tags[j])
+			  {
+			    dup = 1;
+			    break;
+			  }
+		      if (!dup)
+			trans->tags[l++] = p2->tags[j];
+		      j++;
+		    }
+		trans->tags[l] = -1;
+	      }
+
+
+#ifdef TRE_DEBUG
+	    {
+	      int *tags;
+
+	      DPRINT(("	 %2d -> %2d on %3d", p1->position, p2->position,
+		      p1->code_min));
+	      if (p1->code_max != p1->code_min)
+		DPRINT(("-%3d", p1->code_max));
+	      tags = trans->tags;
+	      if (tags)
+		{
+		  DPRINT((", tags ["));
+		  while (*tags >= 0)
+		    {
+		      DPRINT(("%d", *tags));
+		      tags++;
+		      if (*tags >= 0)
+			DPRINT((","));
+		    }
+		  DPRINT(("]"));
+		}
+	      if (trans->assertions)
+		DPRINT((", assert %d", trans->assertions));
+	      if (trans->assertions & ASSERT_BACKREF)
+		DPRINT((", backref %d", trans->u.backref));
+	      else if (trans->class)
+		DPRINT((", class %ld", (long)trans->class));
+	      if (trans->neg_classes)
+		DPRINT((", neg_classes %p", trans->neg_classes));
+	      DPRINT(("\n"));
+	    }
+#endif /* TRE_DEBUG */
+	    p2++;
+	  }
+	p1++;
+      }
+  else
+    /* Compute a maximum limit for the number of transitions leaving
+       from each state. */
+    while (p1->position >= 0)
+      {
+	p2 = orig_p2;
+	while (p2->position >= 0)
+	  {
+	    counts[p1->position]++;
+	    p2++;
+	  }
+	p1++;
+      }
+  return REG_OK;
+}
+
+/* Converts the syntax tree to a TNFA.	All the transitions in the TNFA are
+   labelled with one character range (there are no transitions on empty
+   strings).  The TNFA takes O(n^2) space in the worst case, `n' is size of
+   the regexp. */
+static reg_errcode_t
+tre_ast_to_tnfa(tre_ast_node_t *node, tre_tnfa_transition_t *transitions,
+		int *counts, int *offs)
+{
+  tre_union_t *uni;
+  tre_catenation_t *cat;
+  tre_iteration_t *iter;
+  reg_errcode_t errcode = REG_OK;
+
+  /* XXX - recurse using a stack!. */
+  switch (node->type)
+    {
+    case LITERAL:
+      break;
+    case UNION:
+      uni = (tre_union_t *)node->obj;
+      errcode = tre_ast_to_tnfa(uni->left, transitions, counts, offs);
+      if (errcode != REG_OK)
+	return errcode;
+      errcode = tre_ast_to_tnfa(uni->right, transitions, counts, offs);
+      break;
+
+    case CATENATION:
+      cat = (tre_catenation_t *)node->obj;
+      /* Add a transition from each position in cat->left->lastpos
+	 to each position in cat->right->firstpos. */
+      errcode = tre_make_trans(cat->left->lastpos, cat->right->firstpos,
+			       transitions, counts, offs);
+      if (errcode != REG_OK)
+	return errcode;
+      errcode = tre_ast_to_tnfa(cat->left, transitions, counts, offs);
+      if (errcode != REG_OK)
+	return errcode;
+      errcode = tre_ast_to_tnfa(cat->right, transitions, counts, offs);
+      break;
+
+    case ITERATION:
+      iter = (tre_iteration_t *)node->obj;
+      assert(iter->max == -1 || iter->max == 1);
+
+      if (iter->max == -1)
+	{
+	  assert(iter->min == 0 || iter->min == 1);
+	  /* Add a transition from each last position in the iterated
+	     expression to each first position. */
+	  errcode = tre_make_trans(iter->arg->lastpos, iter->arg->firstpos,
+				   transitions, counts, offs);
+	  if (errcode != REG_OK)
+	    return errcode;
+	}
+      errcode = tre_ast_to_tnfa(iter->arg, transitions, counts, offs);
+      break;
+    }
+  return errcode;
+}
+
+
+static void
+tre_free(regex_t *preg)
+{
+  tre_tnfa_t *tnfa;
+  unsigned int i;
+  tre_tnfa_transition_t *trans;
+
+  tnfa = (void *)preg->TRE_REGEX_T_FIELD;
+  if (!tnfa)
+    return;
+
+  for (i = 0; i < tnfa->num_transitions; i++)
+    if (tnfa->transitions[i].state)
+      {
+	if (tnfa->transitions[i].tags)
+	  xfree(tnfa->transitions[i].tags);
+	if (tnfa->transitions[i].neg_classes)
+	  xfree(tnfa->transitions[i].neg_classes);
+      }
+  if (tnfa->transitions)
+    xfree(tnfa->transitions);
+
+  if (tnfa->initial)
+    {
+      for (trans = tnfa->initial; trans->state; trans++)
+	{
+	  if (trans->tags)
+	    xfree(trans->tags);
+	}
+      xfree(tnfa->initial);
+    }
+
+  if (tnfa->submatch_data)
+    {
+      for (i = 0; i < tnfa->num_submatches; i++)
+	if (tnfa->submatch_data[i].parents)
+	  xfree(tnfa->submatch_data[i].parents);
+      xfree(tnfa->submatch_data);
+    }
+
+  if (tnfa->tag_directions)
+    xfree(tnfa->tag_directions);
+  xfree(tnfa);
+}
+
+
+#define ERROR_EXIT(err)		  \
+  do				  \
+    {				  \
+      errcode = err;		  \
+      if (1) goto error_exit;	  \
+    }				  \
+ while (0)
+
+
+static int
+tre_compile(regex_t *preg, const tre_char_t *regex, size_t n, int cflags)
+{
+  tre_stack_t *stack;
+  tre_ast_node_t *tree, *tmp_ast_l, *tmp_ast_r;
+  tre_pos_and_tags_t *p;
+  int *counts = NULL, *offs = NULL;
+  int i, add = 0;
+  tre_tnfa_transition_t *transitions, *initial;
+  tre_tnfa_t *tnfa = NULL;
+  tre_submatch_data_t *submatch_data;
+  tre_tag_direction_t *tag_directions = NULL;
+  reg_errcode_t errcode;
+  tre_mem_t mem;
+
+  /* Parse context. */
+  tre_parse_ctx_t parse_ctx;
+
+  /* Allocate a stack used throughout the compilation process for various
+     purposes. */
+  stack = tre_stack_new(512, 10240, 128);
+  if (!stack)
+    return REG_ESPACE;
+  /* Allocate a fast memory allocator. */
+  mem = tre_mem_new();
+  if (!mem)
+    {
+      tre_stack_destroy(stack);
+      return REG_ESPACE;
+    }
+
+  /* Parse the regexp. */
+  memset(&parse_ctx, 0, sizeof(parse_ctx));
+  parse_ctx.mem = mem;
+  parse_ctx.stack = stack;
+  parse_ctx.re = regex;
+  parse_ctx.len = n;
+  parse_ctx.cflags = cflags;
+  parse_ctx.max_backref = -1;
+  DPRINT(("tre_compile: parsing '%.*" STRF "'\n", n, regex));
+  errcode = tre_parse(&parse_ctx);
+  if (errcode != REG_OK)
+    ERROR_EXIT(errcode);
+  preg->re_nsub = parse_ctx.submatch_id - 1;
+  tree = parse_ctx.result;
+
+#ifdef TRE_DEBUG
+  tre_ast_print(tree);
+#endif /* TRE_DEBUG */
+
+  /* Referring to nonexistent subexpressions is illegal. */
+  if (parse_ctx.max_backref > (int)preg->re_nsub)
+    ERROR_EXIT(REG_ESUBREG);
+
+  /* Allocate the TNFA struct. */
+  tnfa = xcalloc(1, sizeof(tre_tnfa_t));
+  if (tnfa == NULL)
+    ERROR_EXIT(REG_ESPACE);
+  tnfa->have_backrefs = parse_ctx.max_backref >= 0;
+  tnfa->num_submatches = parse_ctx.submatch_id;
+
+  /* Set up tags for submatch addressing.  If REG_NOSUB is set and the
+     regexp does not have back references, this can be skipped. */
+  if (tnfa->have_backrefs || !(cflags & REG_NOSUB))
+    {
+      DPRINT(("tre_compile: setting up tags\n"));
+
+      /* Figure out how many tags we will need. */
+      errcode = tre_add_tags(NULL, stack, tree, tnfa);
+      if (errcode != REG_OK)
+	ERROR_EXIT(errcode);
+#ifdef TRE_DEBUG
+      tre_ast_print(tree);
+#endif /* TRE_DEBUG */
+
+      if (tnfa->num_tags > 0)
+	{
+	  tag_directions = xmalloc(sizeof(*tag_directions)
+				   * (tnfa->num_tags + 1));
+	  if (tag_directions == NULL)
+	    ERROR_EXIT(REG_ESPACE);
+	  tnfa->tag_directions = tag_directions;
+	  memset(tag_directions, -1,
+		 sizeof(*tag_directions) * (tnfa->num_tags + 1));
+	}
+
+      submatch_data = xcalloc(parse_ctx.submatch_id, sizeof(*submatch_data));
+      if (submatch_data == NULL)
+	ERROR_EXIT(REG_ESPACE);
+      tnfa->submatch_data = submatch_data;
+
+      errcode = tre_add_tags(mem, stack, tree, tnfa);
+      if (errcode != REG_OK)
+	ERROR_EXIT(errcode);
+
+#ifdef TRE_DEBUG
+      for (i = 0; i < parse_ctx.submatch_id; i++)
+	DPRINT(("pmatch[%d] = {t%d, t%d}\n",
+		i, submatch_data[i].so_tag, submatch_data[i].eo_tag));
+      for (i = 0; i < tnfa->num_tags; i++)
+	DPRINT(("t%d is %s\n", i,
+		tag_directions[i] == TRE_TAG_MINIMIZE ?
+		"minimized" : "maximized"));
+#endif /* TRE_DEBUG */
+    }
+
+  /* Expand iteration nodes. */
+  errcode = tre_expand_ast(mem, stack, tree, &parse_ctx.position,
+			   tag_directions, NULL);
+  if (errcode != REG_OK)
+    ERROR_EXIT(errcode);
+
+  /* Add a dummy node for the final state.
+     XXX - For certain patterns this dummy node can be optimized away,
+	   for example "a*" or "ab*".	Figure out a simple way to detect
+	   this possibility. */
+  tmp_ast_l = tree;
+  tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++);
+  if (tmp_ast_r == NULL)
+    ERROR_EXIT(REG_ESPACE);
+
+  tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r);
+  if (tree == NULL)
+    ERROR_EXIT(REG_ESPACE);
+
+#ifdef TRE_DEBUG
+  tre_ast_print(tree);
+  DPRINT(("Number of states: %d\n", parse_ctx.position));
+#endif /* TRE_DEBUG */
+
+  errcode = tre_compute_nfl(mem, stack, tree);
+  if (errcode != REG_OK)
+    ERROR_EXIT(errcode);
+
+  counts = xmalloc(sizeof(int) * parse_ctx.position);
+  if (counts == NULL)
+    ERROR_EXIT(REG_ESPACE);
+
+  offs = xmalloc(sizeof(int) * parse_ctx.position);
+  if (offs == NULL)
+    ERROR_EXIT(REG_ESPACE);
+
+  for (i = 0; i < parse_ctx.position; i++)
+    counts[i] = 0;
+  tre_ast_to_tnfa(tree, NULL, counts, NULL);
+
+  add = 0;
+  for (i = 0; i < parse_ctx.position; i++)
+    {
+      offs[i] = add;
+      add += counts[i] + 1;
+      counts[i] = 0;
+    }
+  transitions = xcalloc(add + 1, sizeof(*transitions));
+  if (transitions == NULL)
+    ERROR_EXIT(REG_ESPACE);
+  tnfa->transitions = transitions;
+  tnfa->num_transitions = add;
+
+  DPRINT(("Converting to TNFA:\n"));
+  errcode = tre_ast_to_tnfa(tree, transitions, counts, offs);
+  if (errcode != REG_OK)
+    ERROR_EXIT(errcode);
+
+  p = tree->firstpos;
+  i = 0;
+  while (p->position >= 0)
+    {
+      i++;
+
+#ifdef TRE_DEBUG
+      {
+	int *tags;
+	DPRINT(("initial: %d", p->position));
+	tags = p->tags;
+	if (tags != NULL)
+	  {
+	    if (*tags >= 0)
+	      DPRINT(("/"));
+	    while (*tags >= 0)
+	      {
+		DPRINT(("%d", *tags));
+		tags++;
+		if (*tags >= 0)
+		  DPRINT((","));
+	      }
+	  }
+	DPRINT((", assert %d", p->assertions));
+	DPRINT(("\n"));
+      }
+#endif /* TRE_DEBUG */
+
+      p++;
+    }
+
+  initial = xcalloc(i + 1, sizeof(tre_tnfa_transition_t));
+  if (initial == NULL)
+    ERROR_EXIT(REG_ESPACE);
+  tnfa->initial = initial;
+
+  i = 0;
+  for (p = tree->firstpos; p->position >= 0; p++)
+    {
+      initial[i].state = transitions + offs[p->position];
+      initial[i].state_id = p->position;
+      initial[i].tags = NULL;
+      /* Copy the arrays p->tags, they are allocated
+	 from a tre_mem object. */
+      if (p->tags)
+	{
+	  int j;
+	  for (j = 0; p->tags[j] >= 0; j++);
+	  initial[i].tags = xmalloc(sizeof(*p->tags) * (j + 1));
+	  if (!initial[i].tags)
+	    ERROR_EXIT(REG_ESPACE);
+	  memcpy(initial[i].tags, p->tags, sizeof(*p->tags) * (j + 1));
+	}
+      initial[i].assertions = p->assertions;
+      i++;
+    }
+  initial[i].state = NULL;
+
+  tnfa->num_transitions = add;
+  tnfa->final = transitions + offs[tree->lastpos[0].position];
+  tnfa->num_states = parse_ctx.position;
+  tnfa->cflags = cflags;
+
+  DPRINT(("final state %p\n", (void *)tnfa->final));
+
+  tre_mem_destroy(mem);
+  tre_stack_destroy(stack);
+  xfree(counts);
+  xfree(offs);
+
+  preg->TRE_REGEX_T_FIELD = (void *)tnfa;
+  return REG_OK;
+
+ error_exit:
+  /* Free everything that was allocated and return the error code. */
+  tre_mem_destroy(mem);
+  if (stack != NULL)
+    tre_stack_destroy(stack);
+  if (counts != NULL)
+    xfree(counts);
+  if (offs != NULL)
+    xfree(offs);
+  preg->TRE_REGEX_T_FIELD = (void *)tnfa;
+  tre_free(preg);
+  return errcode;
+}
+
+
+/***********************************************************************
+ from regcomp.c
+***********************************************************************/
+
+int
+regcomp(regex_t *preg, const char *regex, int cflags)
+{
+  int ret;
+  tre_char_t *wregex;
+  size_t n = strlen(regex);
+
+  if (n+1 > SIZE_MAX/sizeof(tre_char_t))
+    return REG_ESPACE;
+  wregex = xmalloc(sizeof(tre_char_t) * (n + 1));
+  if (wregex == NULL)
+    return REG_ESPACE;
+
+  n = mbstowcs(wregex, regex, n+1);
+  if (n == (size_t)-1) {
+    xfree(wregex);
+    return REG_BADPAT;
+  }
+
+  ret = tre_compile(preg, wregex, n, cflags);
+  xfree(wregex);
+
+  return ret;
+}
+
+void
+regfree(regex_t *preg)
+{
+  tre_free(preg);
+}
+
+/* EOF */
diff --git a/src/regex/regerror.c b/src/regex/regerror.c
new file mode 100644
index 00000000..39d70b2a
--- /dev/null
+++ b/src/regex/regerror.c
@@ -0,0 +1,75 @@
+/*
+  regerror.c - POSIX regerror() implementation for TRE.
+
+  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <string.h>
+#include <regex.h>
+
+/* Error message strings for error codes listed in `regex.h'.  This list
+   needs to be in sync with the codes listed there, naturally. */
+
+/* Converted to single string by Rich Felker to remove the need for
+ * data relocations at runtime, 27 Feb 2006. */
+
+static const char tre_error_messages[] = {
+  "No error\0"
+  "No match\0"
+  "Invalid regexp\0"
+  "Unknown collating element\0"
+  "Unknown character class name\0"
+  "Trailing backslash\0"
+  "Invalid back reference\0"
+  "Missing ']'\0"
+  "Missing ')'\0"
+  "Missing '}'\0"
+  "Invalid contents of {}\0"
+  "Invalid character range\0"
+  "Out of memory\0"
+  "XXX\0"
+};
+
+size_t
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+  const char *err;
+  size_t err_len;
+
+  if (errcode >= 0 && errcode <= REG_BADRPT)
+    for (err=tre_error_messages; errcode; errcode--, err+=strlen(err)+1);
+  else
+    err = "Unknown error";
+
+  err_len = strlen(err) + 1;
+  if (errbuf_size > 0 && errbuf != NULL)
+    {
+      if (err_len > errbuf_size)
+	{
+	  memcpy(errbuf, err, errbuf_size - 1);
+	  errbuf[errbuf_size - 1] = '\0';
+	}
+      else
+	{
+	  strcpy(errbuf, err);
+	}
+    }
+  return err_len;
+}
+
+/* EOF */
diff --git a/src/regex/regexec.c b/src/regex/regexec.c
new file mode 100644
index 00000000..0c3d2834
--- /dev/null
+++ b/src/regex/regexec.c
@@ -0,0 +1,1107 @@
+/*
+  regexec.c - TRE POSIX compatible matching functions (and more).
+
+  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <limits.h>
+
+#include <regex.h>
+
+#include "tre.h"
+
+#include <assert.h>
+
+static void
+tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
+		const tre_tnfa_t *tnfa, int *tags, int match_eo);
+
+/***********************************************************************
+ from tre-match-utils.h
+***********************************************************************/
+
+#define GET_NEXT_WCHAR() do {                                                 \
+    prev_c = next_c; pos += pos_add_next;                                     \
+    if ((pos_add_next = mbtowc(&next_c, str_byte, MB_LEN_MAX)) <= 0) {        \
+        if (pos_add_next < 0) return REG_NOMATCH;                             \
+        else pos_add_next++;                                                  \
+    }                                                                         \
+    str_byte += pos_add_next;                                                 \
+  } while (0)
+
+#define CHECK_ASSERTIONS(assertions)					      \
+  (((assertions & ASSERT_AT_BOL)					      \
+    && (pos > 0 || reg_notbol)						      \
+    && (prev_c != L'\n' || !reg_newline))				      \
+   || ((assertions & ASSERT_AT_EOL)					      \
+       && (next_c != L'\0' || reg_noteol)				      \
+       && (next_c != L'\n' || !reg_newline)))
+
+/* Returns 1 if `t1' wins `t2', 0 otherwise. */
+static int
+tre_tag_order(int num_tags, tre_tag_direction_t *tag_directions,
+	      int *t1, int *t2)
+{
+  int i;
+  for (i = 0; i < num_tags; i++)
+    {
+      if (tag_directions[i] == TRE_TAG_MINIMIZE)
+	{
+	  if (t1[i] < t2[i])
+	    return 1;
+	  if (t1[i] > t2[i])
+	    return 0;
+	}
+      else
+	{
+	  if (t1[i] > t2[i])
+	    return 1;
+	  if (t1[i] < t2[i])
+	    return 0;
+	}
+    }
+  /*  assert(0);*/
+  return 0;
+}
+
+static int
+tre_neg_char_classes_match(tre_ctype_t *classes, tre_cint_t wc, int icase)
+{
+  DPRINT(("neg_char_classes_test: %p, %d, %d\n", classes, wc, icase));
+  while (*classes != (tre_ctype_t)0)
+    if ((!icase && tre_isctype(wc, *classes))
+	|| (icase && (tre_isctype(tre_toupper(wc), *classes)
+		      || tre_isctype(tre_tolower(wc), *classes))))
+      return 1; /* Match. */
+    else
+      classes++;
+  return 0; /* No match. */
+}
+
+
+/***********************************************************************
+ from tre-match-parallel.c
+***********************************************************************/
+
+/*
+  This algorithm searches for matches basically by reading characters
+  in the searched string one by one, starting at the beginning.	 All
+  matching paths in the TNFA are traversed in parallel.	 When two or
+  more paths reach the same state, exactly one is chosen according to
+  tag ordering rules; if returning submatches is not required it does
+  not matter which path is chosen.
+
+  The worst case time required for finding the leftmost and longest
+  match, or determining that there is no match, is always linearly
+  dependent on the length of the text being searched.
+
+  This algorithm cannot handle TNFAs with back referencing nodes.
+  See `tre-match-backtrack.c'.
+*/
+
+
+typedef struct {
+  tre_tnfa_transition_t *state;
+  int *tags;
+} tre_tnfa_reach_t;
+
+typedef struct {
+  int pos;
+  int **tags;
+} tre_reach_pos_t;
+
+
+#ifdef TRE_DEBUG
+static void
+tre_print_reach(const tre_tnfa_t *tnfa, tre_tnfa_reach_t *reach, int num_tags)
+{
+  int i;
+
+  while (reach->state != NULL)
+    {
+      DPRINT((" %p", (void *)reach->state));
+      if (num_tags > 0)
+	{
+	  DPRINT(("/"));
+	  for (i = 0; i < num_tags; i++)
+	    {
+	      DPRINT(("%d:%d", i, reach->tags[i]));
+	      if (i < (num_tags-1))
+		DPRINT((","));
+	    }
+	}
+      reach++;
+    }
+  DPRINT(("\n"));
+
+}
+#endif /* TRE_DEBUG */
+
+static reg_errcode_t
+tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len,
+		      int *match_tags, int eflags, int *match_end_ofs)
+{
+  /* State variables required by GET_NEXT_WCHAR. */
+  tre_char_t prev_c = 0, next_c = 0;
+  const char *str_byte = string;
+  int pos = -1;
+  int pos_add_next = 1;
+#ifdef TRE_MBSTATE
+  mbstate_t mbstate;
+#endif /* TRE_MBSTATE */
+  int reg_notbol = eflags & REG_NOTBOL;
+  int reg_noteol = eflags & REG_NOTEOL;
+  int reg_newline = tnfa->cflags & REG_NEWLINE;
+
+  char *buf;
+  tre_tnfa_transition_t *trans_i;
+  tre_tnfa_reach_t *reach, *reach_next, *reach_i, *reach_next_i;
+  tre_reach_pos_t *reach_pos;
+  int *tag_i;
+  int num_tags, i;
+
+  int match_eo = -1;	   /* end offset of match (-1 if no match found yet) */
+  int new_match = 0;
+  int *tmp_tags = NULL;
+  int *tmp_iptr;
+
+#ifdef TRE_MBSTATE
+  memset(&mbstate, '\0', sizeof(mbstate));
+#endif /* TRE_MBSTATE */
+
+  if (!match_tags)
+    num_tags = 0;
+  else
+    num_tags = tnfa->num_tags;
+
+  /* Allocate memory for temporary data required for matching.	This needs to
+     be done for every matching operation to be thread safe.  This allocates
+     everything in a single large block from the stack frame using alloca()
+     or with malloc() if alloca is unavailable. */
+  {
+    int tbytes, rbytes, pbytes, xbytes, total_bytes;
+    char *tmp_buf;
+    /* Compute the length of the block we need. */
+    tbytes = sizeof(*tmp_tags) * num_tags;
+    rbytes = sizeof(*reach_next) * (tnfa->num_states + 1);
+    pbytes = sizeof(*reach_pos) * tnfa->num_states;
+    xbytes = sizeof(int) * num_tags;
+    total_bytes =
+      (sizeof(long) - 1) * 4 /* for alignment paddings */
+      + (rbytes + xbytes * tnfa->num_states) * 2 + tbytes + pbytes;
+
+    /* Allocate the memory. */
+#ifdef TRE_USE_ALLOCA
+    buf = alloca(total_bytes);
+#else /* !TRE_USE_ALLOCA */
+    buf = xmalloc(total_bytes);
+#endif /* !TRE_USE_ALLOCA */
+    if (buf == NULL)
+      return REG_ESPACE;
+    memset(buf, 0, total_bytes);
+
+    /* Get the various pointers within tmp_buf (properly aligned). */
+    tmp_tags = (void *)buf;
+    tmp_buf = buf + tbytes;
+    tmp_buf += ALIGN(tmp_buf, long);
+    reach_next = (void *)tmp_buf;
+    tmp_buf += rbytes;
+    tmp_buf += ALIGN(tmp_buf, long);
+    reach = (void *)tmp_buf;
+    tmp_buf += rbytes;
+    tmp_buf += ALIGN(tmp_buf, long);
+    reach_pos = (void *)tmp_buf;
+    tmp_buf += pbytes;
+    tmp_buf += ALIGN(tmp_buf, long);
+    for (i = 0; i < tnfa->num_states; i++)
+      {
+	reach[i].tags = (void *)tmp_buf;
+	tmp_buf += xbytes;
+	reach_next[i].tags = (void *)tmp_buf;
+	tmp_buf += xbytes;
+      }
+  }
+
+  for (i = 0; i < tnfa->num_states; i++)
+    reach_pos[i].pos = -1;
+
+  GET_NEXT_WCHAR();
+  pos = 0;
+
+  DPRINT(("length: %d\n", len));
+  DPRINT(("pos:chr/code | states and tags\n"));
+  DPRINT(("-------------+------------------------------------------------\n"));
+
+  reach_next_i = reach_next;
+  while (1)
+    {
+      /* If no match found yet, add the initial states to `reach_next'. */
+      if (match_eo < 0)
+	{
+	  DPRINT((" init >"));
+	  trans_i = tnfa->initial;
+	  while (trans_i->state != NULL)
+	    {
+	      if (reach_pos[trans_i->state_id].pos < pos)
+		{
+		  if (trans_i->assertions
+		      && CHECK_ASSERTIONS(trans_i->assertions))
+		    {
+		      DPRINT(("assertion failed\n"));
+		      trans_i++;
+		      continue;
+		    }
+
+		  DPRINT((" %p", (void *)trans_i->state));
+		  reach_next_i->state = trans_i->state;
+		  for (i = 0; i < num_tags; i++)
+		    reach_next_i->tags[i] = -1;
+		  tag_i = trans_i->tags;
+		  if (tag_i)
+		    while (*tag_i >= 0)
+		      {
+			if (*tag_i < num_tags)
+			  reach_next_i->tags[*tag_i] = pos;
+			tag_i++;
+		      }
+		  if (reach_next_i->state == tnfa->final)
+		    {
+		      DPRINT(("	 found empty match\n"));
+		      match_eo = pos;
+		      new_match = 1;
+		      for (i = 0; i < num_tags; i++)
+			match_tags[i] = reach_next_i->tags[i];
+		    }
+		  reach_pos[trans_i->state_id].pos = pos;
+		  reach_pos[trans_i->state_id].tags = &reach_next_i->tags;
+		  reach_next_i++;
+		}
+	      trans_i++;
+	    }
+	  DPRINT(("\n"));
+	  reach_next_i->state = NULL;
+	}
+      else
+	{
+	  if (num_tags == 0 || reach_next_i == reach_next)
+	    /* We have found a match. */
+	    break;
+	}
+
+      /* Check for end of string. */
+      if (!next_c) break;
+
+      GET_NEXT_WCHAR();
+
+#ifdef TRE_DEBUG
+      DPRINT(("%3d:%2lc/%05d |", pos - 1, (tre_cint_t)prev_c, (int)prev_c));
+      tre_print_reach(tnfa, reach_next, num_tags);
+      DPRINT(("%3d:%2lc/%05d |", pos, (tre_cint_t)next_c, (int)next_c));
+      tre_print_reach(tnfa, reach_next, num_tags);
+#endif /* TRE_DEBUG */
+
+      /* Swap `reach' and `reach_next'. */
+      reach_i = reach;
+      reach = reach_next;
+      reach_next = reach_i;
+
+      /* For each state in `reach' see if there is a transition leaving with
+	 the current input symbol to a state not yet in `reach_next', and
+	 add the destination states to `reach_next'. */
+      reach_next_i = reach_next;
+      for (reach_i = reach; reach_i->state; reach_i++)
+	{
+	  for (trans_i = reach_i->state; trans_i->state; trans_i++)
+	    {
+	      /* Does this transition match the input symbol? */
+	      if (trans_i->code_min <= prev_c &&
+		  trans_i->code_max >= prev_c)
+		{
+		  if (trans_i->assertions
+		      && (CHECK_ASSERTIONS(trans_i->assertions)
+			  /* Handle character class transitions. */
+			  || ((trans_i->assertions & ASSERT_CHAR_CLASS)
+			      && !(tnfa->cflags & REG_ICASE)
+			      && !tre_isctype((tre_cint_t)prev_c,
+					      trans_i->u.class))
+			  || ((trans_i->assertions & ASSERT_CHAR_CLASS)
+			      && (tnfa->cflags & REG_ICASE)
+			      && (!tre_isctype(tre_tolower((tre_cint_t)prev_c),
+					       trans_i->u.class)
+				  && !tre_isctype(tre_toupper((tre_cint_t)prev_c),
+						  trans_i->u.class)))
+			  || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG)
+			      && tre_neg_char_classes_match(trans_i->neg_classes,
+							    (tre_cint_t)prev_c,
+							    tnfa->cflags & REG_ICASE))))
+		    {
+		      DPRINT(("assertion failed\n"));
+		      continue;
+		    }
+
+		  /* Compute the tags after this transition. */
+		  for (i = 0; i < num_tags; i++)
+		    tmp_tags[i] = reach_i->tags[i];
+		  tag_i = trans_i->tags;
+		  if (tag_i != NULL)
+		    while (*tag_i >= 0)
+		      {
+			if (*tag_i < num_tags)
+			  tmp_tags[*tag_i] = pos;
+			tag_i++;
+		      }
+
+		  if (reach_pos[trans_i->state_id].pos < pos)
+		    {
+		      /* Found an unvisited node. */
+		      reach_next_i->state = trans_i->state;
+		      tmp_iptr = reach_next_i->tags;
+		      reach_next_i->tags = tmp_tags;
+		      tmp_tags = tmp_iptr;
+		      reach_pos[trans_i->state_id].pos = pos;
+		      reach_pos[trans_i->state_id].tags = &reach_next_i->tags;
+
+		      if (reach_next_i->state == tnfa->final
+			  && (match_eo == -1
+			      || (num_tags > 0
+				  && reach_next_i->tags[0] <= match_tags[0])))
+			{
+			  DPRINT(("  found match %p\n", trans_i->state));
+			  match_eo = pos;
+			  new_match = 1;
+			  for (i = 0; i < num_tags; i++)
+			    match_tags[i] = reach_next_i->tags[i];
+			}
+		      reach_next_i++;
+
+		    }
+		  else
+		    {
+		      assert(reach_pos[trans_i->state_id].pos == pos);
+		      /* Another path has also reached this state.  We choose
+			 the winner by examining the tag values for both
+			 paths. */
+		      if (tre_tag_order(num_tags, tnfa->tag_directions,
+					tmp_tags,
+					*reach_pos[trans_i->state_id].tags))
+			{
+			  /* The new path wins. */
+			  tmp_iptr = *reach_pos[trans_i->state_id].tags;
+			  *reach_pos[trans_i->state_id].tags = tmp_tags;
+			  if (trans_i->state == tnfa->final)
+			    {
+			      DPRINT(("	 found better match\n"));
+			      match_eo = pos;
+			      new_match = 1;
+			      for (i = 0; i < num_tags; i++)
+				match_tags[i] = tmp_tags[i];
+			    }
+			  tmp_tags = tmp_iptr;
+			}
+		    }
+		}
+	    }
+	}
+      reach_next_i->state = NULL;
+    }
+
+  DPRINT(("match end offset = %d\n", match_eo));
+
+#ifndef TRE_USE_ALLOCA
+  if (buf)
+    xfree(buf);
+#endif /* !TRE_USE_ALLOCA */
+
+  *match_end_ofs = match_eo;
+  return match_eo >= 0 ? REG_OK : REG_NOMATCH;
+}
+
+
+/***********************************************************************
+ from tre-match-backtrack.c
+***********************************************************************/
+
+/*
+  This matcher is for regexps that use back referencing.  Regexp matching
+  with back referencing is an NP-complete problem on the number of back
+  references.  The easiest way to match them is to use a backtracking
+  routine which basically goes through all possible paths in the TNFA
+  and chooses the one which results in the best (leftmost and longest)
+  match.  This can be spectacularly expensive and may run out of stack
+  space, but there really is no better known generic algorithm.	 Quoting
+  Henry Spencer from comp.compilers:
+  <URL: http://compilers.iecc.com/comparch/article/93-03-102>
+
+    POSIX.2 REs require longest match, which is really exciting to
+    implement since the obsolete ("basic") variant also includes
+    \<digit>.  I haven't found a better way of tackling this than doing
+    a preliminary match using a DFA (or simulation) on a modified RE
+    that just replicates subREs for \<digit>, and then doing a
+    backtracking match to determine whether the subRE matches were
+    right.  This can be rather slow, but I console myself with the
+    thought that people who use \<digit> deserve very slow execution.
+    (Pun unintentional but very appropriate.)
+
+*/
+
+typedef struct {
+  int pos;
+  const char *str_byte;
+  tre_tnfa_transition_t *state;
+  int state_id;
+  int next_c;
+  int *tags;
+#ifdef TRE_MBSTATE
+  mbstate_t mbstate;
+#endif /* TRE_MBSTATE */
+} tre_backtrack_item_t;
+
+typedef struct tre_backtrack_struct {
+  tre_backtrack_item_t item;
+  struct tre_backtrack_struct *prev;
+  struct tre_backtrack_struct *next;
+} *tre_backtrack_t;
+
+#ifdef TRE_MBSTATE
+#define BT_STACK_MBSTATE_IN  stack->item.mbstate = (mbstate)
+#define BT_STACK_MBSTATE_OUT (mbstate) = stack->item.mbstate
+#else /* !TRE_MBSTATE */
+#define BT_STACK_MBSTATE_IN
+#define BT_STACK_MBSTATE_OUT
+#endif /* !TRE_MBSTATE */
+
+
+#ifdef TRE_USE_ALLOCA
+#define tre_bt_mem_new		  tre_mem_newa
+#define tre_bt_mem_alloc	  tre_mem_alloca
+#define tre_bt_mem_destroy(obj)	  do { } while (0)
+#else /* !TRE_USE_ALLOCA */
+#define tre_bt_mem_new		  tre_mem_new
+#define tre_bt_mem_alloc	  tre_mem_alloc
+#define tre_bt_mem_destroy	  tre_mem_destroy
+#endif /* !TRE_USE_ALLOCA */
+
+
+#define BT_STACK_PUSH(_pos, _str_byte, _str_wide, _state, _state_id, _next_c, _tags, _mbstate) \
+  do									      \
+    {									      \
+      int i;								      \
+      if (!stack->next)							      \
+	{								      \
+	  tre_backtrack_t s;						      \
+	  s = tre_bt_mem_alloc(mem, sizeof(*s));			      \
+	  if (!s)							      \
+	    {								      \
+	      tre_bt_mem_destroy(mem);					      \
+	      if (tags)							      \
+		xfree(tags);						      \
+	      if (pmatch)						      \
+		xfree(pmatch);						      \
+	      if (states_seen)						      \
+		xfree(states_seen);					      \
+	      return REG_ESPACE;					      \
+	    }								      \
+	  s->prev = stack;						      \
+	  s->next = NULL;						      \
+	  s->item.tags = tre_bt_mem_alloc(mem,				      \
+					  sizeof(*tags) * tnfa->num_tags);    \
+	  if (!s->item.tags)						      \
+	    {								      \
+	      tre_bt_mem_destroy(mem);					      \
+	      if (tags)							      \
+		xfree(tags);						      \
+	      if (pmatch)						      \
+		xfree(pmatch);						      \
+	      if (states_seen)						      \
+		xfree(states_seen);					      \
+	      return REG_ESPACE;					      \
+	    }								      \
+	  stack->next = s;						      \
+	  stack = s;							      \
+	}								      \
+      else								      \
+	stack = stack->next;						      \
+      stack->item.pos = (_pos);						      \
+      stack->item.str_byte = (_str_byte);				      \
+      stack->item.state = (_state);					      \
+      stack->item.state_id = (_state_id);				      \
+      stack->item.next_c = (_next_c);					      \
+      for (i = 0; i < tnfa->num_tags; i++)				      \
+	stack->item.tags[i] = (_tags)[i];				      \
+      BT_STACK_MBSTATE_IN;						      \
+    }									      \
+  while (0)
+
+#define BT_STACK_POP()							      \
+  do									      \
+    {									      \
+      int i;								      \
+      assert(stack->prev);						      \
+      pos = stack->item.pos;						      \
+      str_byte = stack->item.str_byte;					      \
+      state = stack->item.state;					      \
+      next_c = stack->item.next_c;					      \
+      for (i = 0; i < tnfa->num_tags; i++)				      \
+	tags[i] = stack->item.tags[i];					      \
+      BT_STACK_MBSTATE_OUT;						      \
+      stack = stack->prev;						      \
+    }									      \
+  while (0)
+
+#undef MIN
+#define MIN(a, b) ((a) <= (b) ? (a) : (b))
+
+static reg_errcode_t
+tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string,
+		       int len, int *match_tags,
+		       int eflags, int *match_end_ofs)
+{
+  /* State variables required by GET_NEXT_WCHAR. */
+  tre_char_t prev_c = 0, next_c = 0;
+  const char *str_byte = string;
+  int pos = 0;
+  int pos_add_next = 1;
+#ifdef TRE_MBSTATE
+  mbstate_t mbstate;
+#endif /* TRE_MBSTATE */
+  int reg_notbol = eflags & REG_NOTBOL;
+  int reg_noteol = eflags & REG_NOTEOL;
+  int reg_newline = tnfa->cflags & REG_NEWLINE;
+
+  /* These are used to remember the necessary values of the above
+     variables to return to the position where the current search
+     started from. */
+  int next_c_start;
+  const char *str_byte_start;
+  int pos_start = -1;
+#ifdef TRE_MBSTATE
+  mbstate_t mbstate_start;
+#endif /* TRE_MBSTATE */
+
+  /* Compilation flags for this regexp. */
+  int cflags = tnfa->cflags;
+
+  /* End offset of best match so far, or -1 if no match found yet. */
+  int match_eo = -1;
+  /* Tag arrays. */
+  int *next_tags, *tags = NULL;
+  /* Current TNFA state. */
+  tre_tnfa_transition_t *state;
+  int *states_seen = NULL;
+
+  /* Memory allocator to for allocating the backtracking stack. */
+  tre_mem_t mem = tre_bt_mem_new();
+
+  /* The backtracking stack. */
+  tre_backtrack_t stack;
+
+  tre_tnfa_transition_t *trans_i;
+  regmatch_t *pmatch = NULL;
+  int ret;
+
+#ifdef TRE_MBSTATE
+  memset(&mbstate, '\0', sizeof(mbstate));
+#endif /* TRE_MBSTATE */
+
+  if (!mem)
+    return REG_ESPACE;
+  stack = tre_bt_mem_alloc(mem, sizeof(*stack));
+  if (!stack)
+    {
+      ret = REG_ESPACE;
+      goto error_exit;
+    }
+  stack->prev = NULL;
+  stack->next = NULL;
+
+#ifdef TRE_USE_ALLOCA
+  tags = alloca(sizeof(*tags) * tnfa->num_tags);
+  pmatch = alloca(sizeof(*pmatch) * tnfa->num_submatches);
+  states_seen = alloca(sizeof(*states_seen) * tnfa->num_states);
+#else /* !TRE_USE_ALLOCA */
+  tags = xmalloc(sizeof(*tags) * tnfa->num_tags);
+  if (!tags)
+    {
+      ret = REG_ESPACE;
+      goto error_exit;
+    }
+  pmatch = xmalloc(sizeof(*pmatch) * tnfa->num_submatches);
+  if (!pmatch)
+    {
+      ret = REG_ESPACE;
+      goto error_exit;
+    }
+  states_seen = xmalloc(sizeof(*states_seen) * tnfa->num_states);
+  if (!states_seen)
+    {
+      ret = REG_ESPACE;
+      goto error_exit;
+    }
+#endif /* !TRE_USE_ALLOCA */
+
+ retry:
+  {
+    int i;
+    for (i = 0; i < tnfa->num_tags; i++)
+      {
+	tags[i] = -1;
+	if (match_tags)
+	  match_tags[i] = -1;
+      }
+    for (i = 0; i < tnfa->num_states; i++)
+      states_seen[i] = 0;
+  }
+
+  state = NULL;
+  pos = pos_start;
+  GET_NEXT_WCHAR();
+  pos_start = pos;
+  next_c_start = next_c;
+  str_byte_start = str_byte;
+#ifdef TRE_MBSTATE
+  mbstate_start = mbstate;
+#endif /* TRE_MBSTATE */
+
+  /* Handle initial states. */
+  next_tags = NULL;
+  for (trans_i = tnfa->initial; trans_i->state; trans_i++)
+    {
+      DPRINT(("> init %p, prev_c %lc\n", trans_i->state, (tre_cint_t)prev_c));
+      if (trans_i->assertions && CHECK_ASSERTIONS(trans_i->assertions))
+	{
+	  DPRINT(("assert failed\n"));
+	  continue;
+	}
+      if (state == NULL)
+	{
+	  /* Start from this state. */
+	  state = trans_i->state;
+	  next_tags = trans_i->tags;
+	}
+      else
+	{
+	  /* Backtrack to this state. */
+	  DPRINT(("saving state %d for backtracking\n", trans_i->state_id));
+	  BT_STACK_PUSH(pos, str_byte, str_wide, trans_i->state,
+			trans_i->state_id, next_c, tags, mbstate);
+	  {
+	    int *tmp = trans_i->tags;
+	    if (tmp)
+	      while (*tmp >= 0)
+		stack->item.tags[*tmp++] = pos;
+	  }
+	}
+    }
+
+  if (next_tags)
+    for (; *next_tags >= 0; next_tags++)
+      tags[*next_tags] = pos;
+
+
+  DPRINT(("entering match loop, pos %d, str_byte %p\n", pos, str_byte));
+  DPRINT(("pos:chr/code | state and tags\n"));
+  DPRINT(("-------------+------------------------------------------------\n"));
+
+  if (state == NULL)
+    goto backtrack;
+
+  while (1)
+    {
+      tre_tnfa_transition_t *trans_i, *next_state;
+      int empty_br_match;
+
+      DPRINT(("start loop\n"));
+      if (state == tnfa->final)
+	{
+	  DPRINT(("  match found, %d %d\n", match_eo, pos));
+	  if (match_eo < pos
+	      || (match_eo == pos
+		  && match_tags
+		  && tre_tag_order(tnfa->num_tags, tnfa->tag_directions,
+				   tags, match_tags)))
+	    {
+	      int i;
+	      /* This match wins the previous match. */
+	      DPRINT(("	 win previous\n"));
+	      match_eo = pos;
+	      if (match_tags)
+		for (i = 0; i < tnfa->num_tags; i++)
+		  match_tags[i] = tags[i];
+	    }
+	  /* Our TNFAs never have transitions leaving from the final state,
+	     so we jump right to backtracking. */
+	  goto backtrack;
+	}
+
+#ifdef TRE_DEBUG
+      DPRINT(("%3d:%2lc/%05d | %p ", pos, (tre_cint_t)next_c, (int)next_c,
+	      state));
+      {
+	int i;
+	for (i = 0; i < tnfa->num_tags; i++)
+	  DPRINT(("%d%s", tags[i], i < tnfa->num_tags - 1 ? ", " : ""));
+	DPRINT(("\n"));
+      }
+#endif /* TRE_DEBUG */
+
+      /* Go to the next character in the input string. */
+      empty_br_match = 0;
+      trans_i = state;
+      if (trans_i->state && trans_i->assertions & ASSERT_BACKREF)
+	{
+	  /* This is a back reference state.  All transitions leaving from
+	     this state have the same back reference "assertion".  Instead
+	     of reading the next character, we match the back reference. */
+	  int so, eo, bt = trans_i->u.backref;
+	  int bt_len;
+	  int result;
+
+	  DPRINT(("  should match back reference %d\n", bt));
+	  /* Get the substring we need to match against.  Remember to
+	     turn off REG_NOSUB temporarily. */
+	  tre_fill_pmatch(bt + 1, pmatch, tnfa->cflags & !REG_NOSUB,
+			  tnfa, tags, pos);
+	  so = pmatch[bt].rm_so;
+	  eo = pmatch[bt].rm_eo;
+	  bt_len = eo - so;
+
+	  if (len < 0)
+	    {
+	      result = strncmp((char*)string + so, str_byte - 1, bt_len);
+	    }
+	  else if (len - pos < bt_len)
+	    result = 1;
+	  else
+	    result = memcmp((char*)string + so, str_byte - 1, bt_len);
+
+	  /* We can ignore multibyte characters here because the backref
+	     string is already aligned at character boundaries. */
+	  if (result == 0)
+	    {
+	      /* Back reference matched.  Check for infinite loop. */
+	      if (bt_len == 0)
+		empty_br_match = 1;
+	      if (empty_br_match && states_seen[trans_i->state_id])
+		{
+		  DPRINT(("  avoid loop\n"));
+		  goto backtrack;
+		}
+
+	      states_seen[trans_i->state_id] = empty_br_match;
+
+	      /* Advance in input string and resync `prev_c', `next_c'
+		 and pos. */
+	      DPRINT(("	 back reference matched\n"));
+	      str_byte += bt_len - 1;
+	      pos += bt_len - 1;
+	      GET_NEXT_WCHAR();
+	      DPRINT(("	 pos now %d\n", pos));
+	    }
+	  else
+	    {
+	      DPRINT(("	 back reference did not match\n"));
+	      goto backtrack;
+	    }
+	}
+      else
+	{
+	  /* Check for end of string. */
+	  if (len < 0)
+	    {
+	      if (next_c == L'\0')
+		goto backtrack;
+	    }
+	  else
+	    {
+	      if (pos >= len)
+		goto backtrack;
+	    }
+
+	  /* Read the next character. */
+	  GET_NEXT_WCHAR();
+	}
+
+      next_state = NULL;
+      for (trans_i = state; trans_i->state; trans_i++)
+	{
+	  DPRINT(("  transition %d-%d (%c-%c) %d to %d\n",
+		  trans_i->code_min, trans_i->code_max,
+		  trans_i->code_min, trans_i->code_max,
+		  trans_i->assertions, trans_i->state_id));
+	  if (trans_i->code_min <= prev_c && trans_i->code_max >= prev_c)
+	    {
+	      if (trans_i->assertions
+		  && (CHECK_ASSERTIONS(trans_i->assertions)
+		      /* Handle character class transitions. */
+		      || ((trans_i->assertions & ASSERT_CHAR_CLASS)
+			  && !(cflags & REG_ICASE)
+			  && !tre_isctype((tre_cint_t)prev_c, trans_i->u.class))
+		      || ((trans_i->assertions & ASSERT_CHAR_CLASS)
+			  && (cflags & REG_ICASE)
+			  && (!tre_isctype(tre_tolower((tre_cint_t)prev_c),
+					   trans_i->u.class)
+			      && !tre_isctype(tre_toupper((tre_cint_t)prev_c),
+					      trans_i->u.class)))
+		      || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG)
+			  && tre_neg_char_classes_match(trans_i->neg_classes,
+							(tre_cint_t)prev_c,
+							cflags & REG_ICASE))))
+		{
+		  DPRINT(("  assertion failed\n"));
+		  continue;
+		}
+
+	      if (next_state == NULL)
+		{
+		  /* First matching transition. */
+		  DPRINT(("  Next state is %d\n", trans_i->state_id));
+		  next_state = trans_i->state;
+		  next_tags = trans_i->tags;
+		}
+	      else
+		{
+		  /* Second mathing transition.	 We may need to backtrack here
+		     to take this transition instead of the first one, so we
+		     push this transition in the backtracking stack so we can
+		     jump back here if needed. */
+		  DPRINT(("  saving state %d for backtracking\n",
+			  trans_i->state_id));
+		  BT_STACK_PUSH(pos, str_byte, str_wide, trans_i->state,
+				trans_i->state_id, next_c, tags, mbstate);
+		  {
+		    int *tmp;
+		    for (tmp = trans_i->tags; tmp && *tmp >= 0; tmp++)
+		      stack->item.tags[*tmp] = pos;
+		  }
+#if 0 /* XXX - it's important not to look at all transitions here to keep
+	 the stack small! */
+		  break;
+#endif
+		}
+	    }
+	}
+
+      if (next_state != NULL)
+	{
+	  /* Matching transitions were found.  Take the first one. */
+	  state = next_state;
+
+	  /* Update the tag values. */
+	  if (next_tags)
+	    while (*next_tags >= 0)
+	      tags[*next_tags++] = pos;
+	}
+      else
+	{
+	backtrack:
+	  /* A matching transition was not found.  Try to backtrack. */
+	  if (stack->prev)
+	    {
+	      DPRINT(("	 backtracking\n"));
+	      if (stack->item.state->assertions && ASSERT_BACKREF)
+		{
+		  DPRINT(("  states_seen[%d] = 0\n",
+			  stack->item.state_id));
+		  states_seen[stack->item.state_id] = 0;
+		}
+
+	      BT_STACK_POP();
+	    }
+	  else if (match_eo < 0)
+	    {
+	      /* Try starting from a later position in the input string. */
+	      /* Check for end of string. */
+	      if (len < 0)
+		{
+		  if (next_c == L'\0')
+		    {
+		      DPRINT(("end of string.\n"));
+		      break;
+		    }
+		}
+	      else
+		{
+		  if (pos >= len)
+		    {
+		      DPRINT(("end of string.\n"));
+		      break;
+		    }
+		}
+	      DPRINT(("restarting from next start position\n"));
+	      next_c = next_c_start;
+#ifdef TRE_MBSTATE
+	      mbstate = mbstate_start;
+#endif /* TRE_MBSTATE */
+	      str_byte = str_byte_start;
+	      goto retry;
+	    }
+	  else
+	    {
+	      DPRINT(("finished\n"));
+	      break;
+	    }
+	}
+    }
+
+  ret = match_eo >= 0 ? REG_OK : REG_NOMATCH;
+  *match_end_ofs = match_eo;
+
+ error_exit:
+  tre_bt_mem_destroy(mem);
+#ifndef TRE_USE_ALLOCA
+  if (tags)
+    xfree(tags);
+  if (pmatch)
+    xfree(pmatch);
+  if (states_seen)
+    xfree(states_seen);
+#endif /* !TRE_USE_ALLOCA */
+
+  return ret;
+}
+
+
+/***********************************************************************
+ from regexec.c
+***********************************************************************/
+
+/* Fills the POSIX.2 regmatch_t array according to the TNFA tag and match
+   endpoint values. */
+static void
+tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
+		const tre_tnfa_t *tnfa, int *tags, int match_eo)
+{
+  tre_submatch_data_t *submatch_data;
+  unsigned int i, j;
+  int *parents;
+
+  i = 0;
+  if (match_eo >= 0 && !(cflags & REG_NOSUB))
+    {
+      /* Construct submatch offsets from the tags. */
+      DPRINT(("end tag = t%d = %d\n", tnfa->end_tag, match_eo));
+      submatch_data = tnfa->submatch_data;
+      while (i < tnfa->num_submatches && i < nmatch)
+	{
+	  if (submatch_data[i].so_tag == tnfa->end_tag)
+	    pmatch[i].rm_so = match_eo;
+	  else
+	    pmatch[i].rm_so = tags[submatch_data[i].so_tag];
+
+	  if (submatch_data[i].eo_tag == tnfa->end_tag)
+	    pmatch[i].rm_eo = match_eo;
+	  else
+	    pmatch[i].rm_eo = tags[submatch_data[i].eo_tag];
+
+	  /* If either of the endpoints were not used, this submatch
+	     was not part of the match. */
+	  if (pmatch[i].rm_so == -1 || pmatch[i].rm_eo == -1)
+	    pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+
+	  DPRINT(("pmatch[%d] = {t%d = %d, t%d = %d}\n", i,
+		  submatch_data[i].so_tag, pmatch[i].rm_so,
+		  submatch_data[i].eo_tag, pmatch[i].rm_eo));
+	  i++;
+	}
+      /* Reset all submatches that are not within all of their parent
+	 submatches. */
+      i = 0;
+      while (i < tnfa->num_submatches && i < nmatch)
+	{
+	  if (pmatch[i].rm_eo == -1)
+	    assert(pmatch[i].rm_so == -1);
+	  assert(pmatch[i].rm_so <= pmatch[i].rm_eo);
+
+	  parents = submatch_data[i].parents;
+	  if (parents != NULL)
+	    for (j = 0; parents[j] >= 0; j++)
+	      {
+		DPRINT(("pmatch[%d] parent %d\n", i, parents[j]));
+		if (pmatch[i].rm_so < pmatch[parents[j]].rm_so
+		    || pmatch[i].rm_eo > pmatch[parents[j]].rm_eo)
+		  pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+	      }
+	  i++;
+	}
+    }
+
+  while (i < nmatch)
+    {
+      pmatch[i].rm_so = -1;
+      pmatch[i].rm_eo = -1;
+      i++;
+    }
+}
+
+
+/*
+  Wrapper functions for POSIX compatible regexp matching.
+*/
+
+static int
+tre_match(const tre_tnfa_t *tnfa, const void *string, size_t len,
+	  size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+  reg_errcode_t status;
+  int *tags = NULL, eo;
+  if (tnfa->num_tags > 0 && nmatch > 0)
+    {
+#ifdef TRE_USE_ALLOCA
+      tags = alloca(sizeof(*tags) * tnfa->num_tags);
+#else /* !TRE_USE_ALLOCA */
+      tags = xmalloc(sizeof(*tags) * tnfa->num_tags);
+#endif /* !TRE_USE_ALLOCA */
+      if (tags == NULL)
+	return REG_ESPACE;
+    }
+
+  /* Dispatch to the appropriate matcher. */
+  if (tnfa->have_backrefs)
+    {
+      /* The regex has back references, use the backtracking matcher. */
+      status = tre_tnfa_run_backtrack(tnfa, string, len, tags, eflags, &eo);
+    }
+  else
+    {
+      /* Exact matching, no back references, use the parallel matcher. */
+      status = tre_tnfa_run_parallel(tnfa, string, len, tags, eflags, &eo);
+    }
+
+  if (status == REG_OK)
+    /* A match was found, so fill the submatch registers. */
+    tre_fill_pmatch(nmatch, pmatch, tnfa->cflags, tnfa, tags, eo);
+#ifndef TRE_USE_ALLOCA
+  if (tags)
+    xfree(tags);
+#endif /* !TRE_USE_ALLOCA */
+  return status;
+}
+
+int
+regexec(const regex_t *preg, const char *str,
+	size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+  return tre_match((void *)preg->TRE_REGEX_T_FIELD, str, -1,
+                   nmatch, pmatch, eflags);
+}
+
+/* EOF */
diff --git a/src/regex/tre-mem.c b/src/regex/tre-mem.c
new file mode 100644
index 00000000..d7bdd3db
--- /dev/null
+++ b/src/regex/tre-mem.c
@@ -0,0 +1,163 @@
+/*
+  tre-mem.c - TRE memory allocator
+
+  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/*
+  This memory allocator is for allocating small memory blocks efficiently
+  in terms of memory overhead and execution speed.  The allocated blocks
+  cannot be freed individually, only all at once.  There can be multiple
+  allocators, though.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tre.h"
+
+
+/* Returns a new memory allocator or NULL if out of memory. */
+tre_mem_t
+tre_mem_new_impl(int provided, void *provided_block)
+{
+  tre_mem_t mem;
+  if (provided)
+    {
+      mem = provided_block;
+      memset(mem, 0, sizeof(*mem));
+    }
+  else
+    mem = xcalloc(1, sizeof(*mem));
+  if (mem == NULL)
+    return NULL;
+  return mem;
+}
+
+
+/* Frees the memory allocator and all memory allocated with it. */
+void
+tre_mem_destroy(tre_mem_t mem)
+{
+  tre_list_t *tmp, *l = mem->blocks;
+
+  while (l != NULL)
+    {
+      xfree(l->data);
+      tmp = l->next;
+      xfree(l);
+      l = tmp;
+    }
+  xfree(mem);
+}
+
+
+/* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the
+   allocated block or NULL if an underlying malloc() failed. */
+void *
+tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
+		   int zero, size_t size)
+{
+  void *ptr;
+
+  if (mem->failed)
+    {
+      DPRINT(("tre_mem_alloc: oops, called after failure?!\n"));
+      return NULL;
+    }
+
+#ifdef MALLOC_DEBUGGING
+  if (!provided)
+    {
+      ptr = xmalloc(1);
+      if (ptr == NULL)
+	{
+	  DPRINT(("tre_mem_alloc: xmalloc forced failure\n"));
+	  mem->failed = 1;
+	  return NULL;
+	}
+      xfree(ptr);
+    }
+#endif /* MALLOC_DEBUGGING */
+
+  if (mem->n < size)
+    {
+      /* We need more memory than is available in the current block.
+	 Allocate a new block. */
+      tre_list_t *l;
+      if (provided)
+	{
+	  DPRINT(("tre_mem_alloc: using provided block\n"));
+	  if (provided_block == NULL)
+	    {
+	      DPRINT(("tre_mem_alloc: provided block was NULL\n"));
+	      mem->failed = 1;
+	      return NULL;
+	    }
+	  mem->ptr = provided_block;
+	  mem->n = TRE_MEM_BLOCK_SIZE;
+	}
+      else
+	{
+	  int block_size;
+	  if (size * 8 > TRE_MEM_BLOCK_SIZE)
+	    block_size = size * 8;
+	  else
+	    block_size = TRE_MEM_BLOCK_SIZE;
+	  DPRINT(("tre_mem_alloc: allocating new %d byte block\n",
+		  block_size));
+	  l = xmalloc(sizeof(*l));
+	  if (l == NULL)
+	    {
+	      mem->failed = 1;
+	      return NULL;
+	    }
+	  l->data = xmalloc(block_size);
+	  if (l->data == NULL)
+	    {
+	      xfree(l);
+	      mem->failed = 1;
+	      return NULL;
+	    }
+	  l->next = NULL;
+	  if (mem->current != NULL)
+	    mem->current->next = l;
+	  if (mem->blocks == NULL)
+	    mem->blocks = l;
+	  mem->current = l;
+	  mem->ptr = l->data;
+	  mem->n = block_size;
+	}
+    }
+
+  /* Make sure the next pointer will be aligned. */
+  size += ALIGN(mem->ptr + size, long);
+
+  /* Allocate from current block. */
+  ptr = mem->ptr;
+  mem->ptr += size;
+  mem->n -= size;
+
+  /* Set to zero if needed. */
+  if (zero)
+    memset(ptr, 0, size);
+
+  return ptr;
+}
+
+/* EOF */
diff --git a/src/regex/tre.h b/src/regex/tre.h
new file mode 100644
index 00000000..bfd171f4
--- /dev/null
+++ b/src/regex/tre.h
@@ -0,0 +1,269 @@
+/*
+  tre-internal.h - TRE internal definitions
+
+  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <regex.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define TRE_MULTIBYTE 1
+#undef  TRE_MBSTATE
+#define TRE_WCHAR 1
+#define TRE_USE_SYSTEM_WCTYPE 1
+#define HAVE_WCSTOMBS 1
+#define TRE_MB_CUR_MAX MB_CUR_MAX
+
+#define NDEBUG
+
+#define TRE_REGEX_T_FIELD __opaque
+typedef int reg_errcode_t;
+
+typedef wchar_t tre_char_t;
+
+
+#ifdef TRE_DEBUG
+#include <stdio.h>
+#define DPRINT(msg) do {printf msg; fflush(stdout);} while(0)
+#else /* !TRE_DEBUG */
+#define DPRINT(msg) do { } while(0)
+#endif /* !TRE_DEBUG */
+
+#define elementsof(x)	( sizeof(x) / sizeof(x[0]) )
+
+#if 1
+int __mbtowc(wchar_t *, const char *);
+#define tre_mbrtowc(pwc, s, n, ps) (__mbtowc((pwc), (s)))
+#else
+#define tre_mbrtowc(pwc, s, n, ps) (mbtowc((pwc), (s), (n)))
+#endif
+
+/* Wide characters. */
+typedef wint_t tre_cint_t;
+#define TRE_CHAR_MAX WCHAR_MAX
+
+#ifdef TRE_MULTIBYTE
+#define TRE_MB_CUR_MAX MB_CUR_MAX
+#else /* !TRE_MULTIBYTE */
+#define TRE_MB_CUR_MAX 1
+#endif /* !TRE_MULTIBYTE */
+
+#define tre_isalnum iswalnum
+#define tre_isalpha iswalpha
+#define tre_isblank iswblank
+#define tre_iscntrl iswcntrl
+#define tre_isdigit iswdigit
+#define tre_isgraph iswgraph
+#define tre_islower iswlower
+#define tre_isprint iswprint
+#define tre_ispunct iswpunct
+#define tre_isspace iswspace
+#define tre_isupper iswupper
+#define tre_isxdigit iswxdigit
+
+#define tre_tolower towlower
+#define tre_toupper towupper
+#define tre_strlen  wcslen
+
+/* Use system provided iswctype() and wctype(). */
+typedef wctype_t tre_ctype_t;
+#define tre_isctype iswctype
+#define tre_ctype   wctype
+
+/* Returns number of bytes to add to (char *)ptr to make it
+   properly aligned for the type. */
+#define ALIGN(ptr, type) \
+  ((((long)ptr) % sizeof(type)) \
+   ? (sizeof(type) - (((long)ptr) % sizeof(type))) \
+   : 0)
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
+#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
+
+/* Define STRF to the correct printf formatter for strings. */
+#define STRF "ls"
+
+/* TNFA transition type. A TNFA state is an array of transitions,
+   the terminator is a transition with NULL `state'. */
+typedef struct tnfa_transition tre_tnfa_transition_t;
+
+struct tnfa_transition {
+  /* Range of accepted characters. */
+  tre_cint_t code_min;
+  tre_cint_t code_max;
+  /* Pointer to the destination state. */
+  tre_tnfa_transition_t *state;
+  /* ID number of the destination state. */
+  int state_id;
+  /* -1 terminated array of tags (or NULL). */
+  int *tags;
+  /* Assertion bitmap. */
+  int assertions;
+  /* Assertion parameters. */
+  union {
+    /* Character class assertion. */
+    tre_ctype_t class;
+    /* Back reference assertion. */
+    int backref;
+  } u;
+  /* Negative character class assertions. */
+  tre_ctype_t *neg_classes;
+};
+
+
+/* Assertions. */
+#define ASSERT_AT_BOL		  1   /* Beginning of line. */
+#define ASSERT_AT_EOL		  2   /* End of line. */
+#define ASSERT_CHAR_CLASS	  4   /* Character class in `class'. */
+#define ASSERT_CHAR_CLASS_NEG	  8   /* Character classes in `neg_classes'. */
+#define ASSERT_AT_BOW		 16   /* Beginning of word. */
+#define ASSERT_AT_EOW		 32   /* End of word. */
+#define ASSERT_AT_WB		 64   /* Word boundary. */
+#define ASSERT_AT_WB_NEG	128   /* Not a word boundary. */
+#define ASSERT_BACKREF		256   /* A back reference in `backref'. */
+#define ASSERT_LAST		256
+
+/* Tag directions. */
+typedef enum {
+  TRE_TAG_MINIMIZE = 0,
+  TRE_TAG_MAXIMIZE = 1
+} tre_tag_direction_t;
+
+/* Instructions to compute submatch register values from tag values
+   after a successful match.  */
+struct tre_submatch_data {
+  /* Tag that gives the value for rm_so (submatch start offset). */
+  int so_tag;
+  /* Tag that gives the value for rm_eo (submatch end offset). */
+  int eo_tag;
+  /* List of submatches this submatch is contained in. */
+  int *parents;
+};
+
+typedef struct tre_submatch_data tre_submatch_data_t;
+
+
+/* TNFA definition. */
+typedef struct tnfa tre_tnfa_t;
+
+struct tnfa {
+  tre_tnfa_transition_t *transitions;
+  unsigned int num_transitions;
+  tre_tnfa_transition_t *initial;
+  tre_tnfa_transition_t *final;
+  tre_submatch_data_t *submatch_data;
+  unsigned int num_submatches;
+  tre_tag_direction_t *tag_directions;
+  int num_tags;
+  int end_tag;
+  int num_states;
+  int cflags;
+  int have_backrefs;
+};
+
+#if 0
+static int
+tre_compile(regex_t *preg, const tre_char_t *regex, size_t n, int cflags);
+
+static void
+tre_free(regex_t *preg);
+
+static void
+tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
+		const tre_tnfa_t *tnfa, int *tags, int match_eo);
+
+static reg_errcode_t
+tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len,
+		      tre_str_type_t type, int *match_tags, int eflags,
+		      int *match_end_ofs);
+
+static reg_errcode_t
+tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len,
+		      tre_str_type_t type, int *match_tags, int eflags,
+		      int *match_end_ofs);
+
+static reg_errcode_t
+tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string,
+		       int len, tre_str_type_t type, int *match_tags,
+		       int eflags, int *match_end_ofs);
+#endif
+
+/* from tre-mem.h: */
+
+#define TRE_MEM_BLOCK_SIZE 1024
+
+typedef struct tre_list {
+  void *data;
+  struct tre_list *next;
+} tre_list_t;
+
+typedef struct tre_mem_struct {
+  tre_list_t *blocks;
+  tre_list_t *current;
+  char *ptr;
+  size_t n;
+  int failed;
+  void **provided;
+} *tre_mem_t;
+
+#define tre_mem_new_impl   __tre_mem_new_impl
+#define tre_mem_alloc_impl __tre_mem_alloc_impl
+#define tre_mem_destroy    __tre_mem_destroy
+
+tre_mem_t tre_mem_new_impl(int provided, void *provided_block);
+void *tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
+			 int zero, size_t size);
+
+/* Returns a new memory allocator or NULL if out of memory. */
+#define tre_mem_new()  tre_mem_new_impl(0, NULL)
+
+/* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the
+   allocated block or NULL if an underlying malloc() failed. */
+#define tre_mem_alloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 0, size)
+
+/* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the
+   allocated block or NULL if an underlying malloc() failed.  The memory
+   is set to zero. */
+#define tre_mem_calloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 1, size)
+
+#ifdef TRE_USE_ALLOCA
+/* alloca() versions.  Like above, but memory is allocated with alloca()
+   instead of malloc(). */
+
+#define tre_mem_newa() \
+  tre_mem_new_impl(1, alloca(sizeof(struct tre_mem_struct)))
+
+#define tre_mem_alloca(mem, size)					      \
+  ((mem)->n >= (size)							      \
+   ? tre_mem_alloc_impl((mem), 1, NULL, 0, (size))			      \
+   : tre_mem_alloc_impl((mem), 1, alloca(TRE_MEM_BLOCK_SIZE), 0, (size)))
+#endif /* TRE_USE_ALLOCA */
+
+
+/* Frees the memory allocator and all memory allocated with it. */
+void tre_mem_destroy(tre_mem_t mem);
+
+#define xmalloc malloc
+#define xcalloc calloc
+#define xfree free
+#define xrealloc realloc
+
+/* EOF */
diff --git a/src/select/poll.c b/src/select/poll.c
new file mode 100644
index 00000000..e92943e1
--- /dev/null
+++ b/src/select/poll.c
@@ -0,0 +1,12 @@
+#include <poll.h>
+#include "syscall.h"
+#include "libc.h"
+
+int poll(struct pollfd *fds, nfds_t n, int timeout)
+{
+	int r;
+	CANCELPT_BEGIN;
+	r = syscall3(__NR_poll, (long)fds, n, timeout);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/select/pselect.c b/src/select/pselect.c
new file mode 100644
index 00000000..795c5b0d
--- /dev/null
+++ b/src/select/pselect.c
@@ -0,0 +1,15 @@
+#include <sys/select.h>
+#include "syscall.h"
+#include "libc.h"
+
+int pselect(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, const struct timespec *ts, const sigset_t *mask)
+{
+	int r;
+	long data[2] = { (long)mask, 8 };
+	struct timespec ts_tmp;
+	if (ts) ts_tmp = *ts;
+	CANCELPT_BEGIN;
+	r = syscall6(__NR_pselect6, n, (long)rfds, (long)wfds, (long)efds, ts ? (long)&ts_tmp : 0, (long)data);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/select/select.c b/src/select/select.c
new file mode 100644
index 00000000..a604d094
--- /dev/null
+++ b/src/select/select.c
@@ -0,0 +1,12 @@
+#include <sys/select.h>
+#include "syscall.h"
+#include "libc.h"
+
+int select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv)
+{
+	int r;
+	CANCELPT_BEGIN;
+	r = syscall5(__NR__newselect, n, (long)rfds, (long)wfds, (long)efds, (long)tv);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/setjmp/i386/longjmp.s b/src/setjmp/i386/longjmp.s
new file mode 100644
index 00000000..c1a956c3
--- /dev/null
+++ b/src/setjmp/i386/longjmp.s
@@ -0,0 +1,22 @@
+.global _longjmp
+.global longjmp
+.type _longjmp,%function
+.type longjmp,%function
+_longjmp:
+longjmp:
+	movl  4(%esp),%edx
+	movl  8(%esp),%eax
+	testl    %eax,%eax
+	jnz .L0
+	incl     %eax
+.L0:
+	movl   (%edx),%ebx
+	movl  4(%edx),%esi
+	movl  8(%edx),%edi
+	movl 12(%edx),%ebp
+	movl 16(%edx),%ecx
+	movl     %ecx,%esp
+	movl 20(%edx),%ecx
+	jmp *%ecx
+.size _longjmp,.-_longjmp
+.size longjmp,.-longjmp
diff --git a/src/setjmp/i386/setjmp.s b/src/setjmp/i386/setjmp.s
new file mode 100644
index 00000000..6c078b10
--- /dev/null
+++ b/src/setjmp/i386/setjmp.s
@@ -0,0 +1,23 @@
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp,%function
+.type _setjmp,%function
+.type setjmp,%function
+__setjmp:
+_setjmp:
+setjmp:
+	movl 4(%esp), %eax
+	movl    %ebx, (%eax)
+	movl    %esi, 4(%eax)
+	movl    %edi, 8(%eax)
+	movl    %ebp, 12(%eax)
+	leal 4(%esp), %ecx
+	movl    %ecx, 16(%eax)
+	movl  (%esp), %ecx
+	movl    %ecx, 20(%eax)
+	xorl    %eax, %eax
+	ret
+.size __setjmp,.-__setjmp
+.size _setjmp,.-_setjmp
+.size setjmp,.-setjmp
diff --git a/src/setjmp/longjmp.c b/src/setjmp/longjmp.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/setjmp/longjmp.c
diff --git a/src/setjmp/setjmp.c b/src/setjmp/setjmp.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/setjmp/setjmp.c
diff --git a/src/signal/bsd_signal.c b/src/signal/bsd_signal.c
new file mode 100644
index 00000000..0b9a6855
--- /dev/null
+++ b/src/signal/bsd_signal.c
@@ -0,0 +1,6 @@
+#include <signal.h>
+
+void (*bsd_signal(int sig, void (*func)(int)))(int)
+{
+	return signal(sig, func);
+}
diff --git a/src/signal/getitimer.c b/src/signal/getitimer.c
new file mode 100644
index 00000000..222d113e
--- /dev/null
+++ b/src/signal/getitimer.c
@@ -0,0 +1,12 @@
+#include <sys/time.h>
+#include "syscall.h"
+
+int getitimer(int which, struct itimerval *old)
+{
+	int ret;
+	long kold[4];
+
+	if (!(ret = syscall2(__NR_getitimer, which, (long)&kold)))
+		*old = (struct itimerval){ { kold[0], kold[1] }, { kold[2], kold[3] } };
+	return ret;
+}
diff --git a/src/signal/i386/sigsetjmp.s b/src/signal/i386/sigsetjmp.s
new file mode 100644
index 00000000..0e7eefb0
--- /dev/null
+++ b/src/signal/i386/sigsetjmp.s
@@ -0,0 +1,13 @@
+.global sigsetjmp
+sigsetjmp:
+	mov 4(%esp),%eax
+	mov 8(%esp),%ecx
+	mov %ecx,24(%eax)
+	jecxz 1f
+	add $28,%eax
+	push %eax
+	push $0
+	push $2
+	call sigprocmask
+	add $12,%esp
+1:	jmp setjmp
diff --git a/src/signal/kill.c b/src/signal/kill.c
new file mode 100644
index 00000000..cc4b51e1
--- /dev/null
+++ b/src/signal/kill.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include "syscall.h"
+
+int kill(pid_t pid, int sig)
+{
+	return syscall2(__NR_kill, pid, sig);
+}
diff --git a/src/signal/killpg.c b/src/signal/killpg.c
new file mode 100644
index 00000000..315ed447
--- /dev/null
+++ b/src/signal/killpg.c
@@ -0,0 +1,11 @@
+#include <signal.h>
+#include <errno.h>
+
+int killpg(pid_t pgid, int sig)
+{
+	if (pgid < 0) {
+		errno = EINVAL;
+		return -1;
+	}
+	return kill(-pgid, sig);
+}
diff --git a/src/signal/raise.c b/src/signal/raise.c
new file mode 100644
index 00000000..52f8b428
--- /dev/null
+++ b/src/signal/raise.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include "syscall.h"
+
+int raise(int sig)
+{
+	return __syscall_kill(__syscall_getpid(), sig);
+}
diff --git a/src/signal/setitimer.c b/src/signal/setitimer.c
new file mode 100644
index 00000000..cacab036
--- /dev/null
+++ b/src/signal/setitimer.c
@@ -0,0 +1,15 @@
+#include <sys/time.h>
+#include "syscall.h"
+
+int setitimer(int which, const struct itimerval *new, struct itimerval *old)
+{
+	int ret;
+	long knew[4] = {
+		new->it_interval.tv_sec, new->it_interval.tv_usec,
+		new->it_value.tv_sec, new->it_value.tv_usec
+	}, kold[4];
+
+	if (!(ret = syscall3(__NR_setitimer, which, (long)&knew, old ? (long)&kold : 0)) && old)
+		*old = (struct itimerval){ { kold[0], kold[1] }, { kold[2], kold[3] } };
+	return ret;
+}
diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c
new file mode 100644
index 00000000..4acd1730
--- /dev/null
+++ b/src/signal/sigaction.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include "syscall.h"
+#include "pthread_impl.h"
+
+static void restorer()
+{
+	syscall0(__NR_rt_sigreturn);
+}
+
+int __libc_sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
+{
+	struct {
+		void *handler;
+		unsigned long flags;
+		void (*restorer)(void);
+		sigset_t mask;
+	} ksa, kold;
+	long pksa=0, pkold=0;
+	if (sa) {
+		ksa.handler = sa->sa_handler;
+		ksa.flags = sa->sa_flags;
+		ksa.restorer = restorer;
+		ksa.mask = sa->sa_mask;
+		pksa = (long)&ksa;
+	}
+	if (old) pkold = (long)&kold;
+	if (syscall4(__NR_rt_sigaction, sig, pksa, pkold, 8))
+		return -1;
+	if (old) {
+		old->sa_handler = kold.handler;
+		old->sa_flags = kold.flags;
+		old->sa_mask = kold.mask;
+	}
+	return 0;
+}
+
+int __sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
+{
+	if (sig == SIGCANCEL || sig == SIGSYSCALL) {
+		errno = EINVAL;
+		return -1;
+	}
+	return __libc_sigaction(sig, sa, old);
+}
+
+weak_alias(__sigaction, sigaction);
diff --git a/src/signal/sigaddset.c b/src/signal/sigaddset.c
new file mode 100644
index 00000000..23e655db
--- /dev/null
+++ b/src/signal/sigaddset.c
@@ -0,0 +1,13 @@
+#include <signal.h>
+#include <errno.h>
+
+int sigaddset(sigset_t *set, int sig)
+{
+	unsigned s = sig-1;
+	if (s >= 8*sizeof(sigset_t)) {
+		errno = EINVAL;
+		return -1;
+	}
+	set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1);
+	return 0;
+}
diff --git a/src/signal/sigaltstack.c b/src/signal/sigaltstack.c
new file mode 100644
index 00000000..3cc2d456
--- /dev/null
+++ b/src/signal/sigaltstack.c
@@ -0,0 +1,8 @@
+#include <signal.h>
+#include "syscall.h"
+
+int sigaltstack(const stack_t *ss, stack_t *old)
+{
+	/* depends on kernel struct matching */
+	return syscall2(__NR_sigaltstack, (long)ss, (long)old);
+}
diff --git a/src/signal/sigdelset.c b/src/signal/sigdelset.c
new file mode 100644
index 00000000..14042fb8
--- /dev/null
+++ b/src/signal/sigdelset.c
@@ -0,0 +1,13 @@
+#include <signal.h>
+#include <errno.h>
+
+int sigdelset(sigset_t *set, int sig)
+{
+	unsigned s = sig-1;
+	if (s >= 8*sizeof(sigset_t)) {
+		errno = EINVAL;
+		return -1;
+	}
+	set->__bits[s/8/sizeof *set->__bits] &=~(1UL<<(s&8*sizeof *set->__bits-1));
+	return 0;
+}
diff --git a/src/signal/sigemptyset.c b/src/signal/sigemptyset.c
new file mode 100644
index 00000000..91f77adf
--- /dev/null
+++ b/src/signal/sigemptyset.c
@@ -0,0 +1,8 @@
+#include <signal.h>
+#include <string.h>
+
+int sigemptyset(sigset_t *set)
+{
+	memset(set, 0, sizeof *set);
+	return 0;
+}
diff --git a/src/signal/sigfillset.c b/src/signal/sigfillset.c
new file mode 100644
index 00000000..fab50a52
--- /dev/null
+++ b/src/signal/sigfillset.c
@@ -0,0 +1,8 @@
+#include <signal.h>
+#include <string.h>
+
+int sigfillset(sigset_t *set)
+{
+	memset(set, -1, sizeof *set);
+	return 0;
+}
diff --git a/src/signal/sighold.c b/src/signal/sighold.c
new file mode 100644
index 00000000..5b0f6b18
--- /dev/null
+++ b/src/signal/sighold.c
@@ -0,0 +1,11 @@
+#include <signal.h>
+#include <stdlib.h>
+
+int sighold(int sig)
+{
+	sigset_t mask;
+
+	sigemptyset(&mask);
+	if (sigaddset(&mask, sig) < 0) return -1;
+	return sigprocmask(SIG_BLOCK, &mask, NULL);
+}
diff --git a/src/signal/sigignore.c b/src/signal/sigignore.c
new file mode 100644
index 00000000..98dff61e
--- /dev/null
+++ b/src/signal/sigignore.c
@@ -0,0 +1,12 @@
+#include <signal.h>
+#include <stdlib.h>
+
+int sigignore(int sig)
+{
+	struct sigaction sa;
+
+	sigemptyset(&sa.sa_mask);
+	sa.sa_handler = SIG_IGN;
+	sa.sa_flags = 0;
+	return sigaction(sig, &sa, NULL);
+}
diff --git a/src/signal/siginterrupt.c b/src/signal/siginterrupt.c
new file mode 100644
index 00000000..60b34054
--- /dev/null
+++ b/src/signal/siginterrupt.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+#include <signal.h>
+
+int siginterrupt(int sig, int flag)
+{
+	struct sigaction sa;
+
+	sigaction(sig, NULL, &sa);
+	if (flag) sa.sa_flags &= ~SA_RESTART;
+	else sa.sa_flags |= SA_RESTART;
+
+	return sigaction(sig, &sa, NULL);
+}
diff --git a/src/signal/sigismember.c b/src/signal/sigismember.c
new file mode 100644
index 00000000..afd29e52
--- /dev/null
+++ b/src/signal/sigismember.c
@@ -0,0 +1,12 @@
+#include <signal.h>
+#include <errno.h>
+
+int sigismember(const sigset_t *set, int sig)
+{
+	unsigned s = sig-1;
+	if (s >= 8*sizeof(sigset_t)) {
+		errno = EINVAL;
+		return -1;
+	}
+	return !!(set->__bits[s/8/sizeof *set->__bits] & 1UL<<(s&8*sizeof *set->__bits-1));
+}
diff --git a/src/signal/siglongjmp.c b/src/signal/siglongjmp.c
new file mode 100644
index 00000000..33ac30ea
--- /dev/null
+++ b/src/signal/siglongjmp.c
@@ -0,0 +1,12 @@
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+
+void siglongjmp(sigjmp_buf buf, int ret)
+{
+	long *flag = buf + sizeof(jmp_buf)/sizeof(long);
+	sigset_t *mask = (void *)(flag + 1);
+	if (*flag)
+		sigprocmask (SIG_SETMASK, mask, NULL);
+	longjmp((void *)buf, ret);
+}
diff --git a/src/signal/signal.c b/src/signal/signal.c
new file mode 100644
index 00000000..08902760
--- /dev/null
+++ b/src/signal/signal.c
@@ -0,0 +1,13 @@
+#include <signal.h>
+#include <stddef.h>
+#include "syscall.h"
+
+int __sigaction(int, const struct sigaction *, struct sigaction *);
+
+void (*signal(int sig, void (*func)(int)))(int)
+{
+	struct sigaction sa = { .sa_handler = func, .sa_flags = SA_RESTART };
+	if (__sigaction(sig, &sa, &sa) < 0)
+		return SIG_ERR;
+	return sa.sa_handler;
+}
diff --git a/src/signal/sigpause.c b/src/signal/sigpause.c
new file mode 100644
index 00000000..263c00f5
--- /dev/null
+++ b/src/signal/sigpause.c
@@ -0,0 +1,11 @@
+#include <signal.h>
+#include <stdlib.h>
+
+int sigpause(int sig)
+{
+	sigset_t mask;
+
+	if (sigprocmask(0, NULL, &mask) < 0 || sigdelset(&mask, sig) < 0)
+		return -1;
+	return sigsuspend(&mask);
+}
diff --git a/src/signal/sigpending.c b/src/signal/sigpending.c
new file mode 100644
index 00000000..7deda256
--- /dev/null
+++ b/src/signal/sigpending.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include "syscall.h"
+
+int sigpending(sigset_t *set)
+{
+	return syscall2(__NR_rt_sigpending, (long)set, SYSCALL_SIGSET_SIZE);
+}
diff --git a/src/signal/sigprocmask.c b/src/signal/sigprocmask.c
new file mode 100644
index 00000000..e89f8765
--- /dev/null
+++ b/src/signal/sigprocmask.c
@@ -0,0 +1,23 @@
+#include <signal.h>
+#include "syscall.h"
+#include "libc.h"
+
+int __libc_sigprocmask(int how, const sigset_t *set, sigset_t *old)
+{
+	return syscall4(__NR_rt_sigprocmask, how, (long)set, (long)old, 8);
+}
+
+int __sigprocmask(int how, const sigset_t *set, sigset_t *old)
+{
+	sigset_t tmp;
+	/* Quickly mask out bits 32 and 33 (thread control signals) */
+	if (0 && how != SIG_UNBLOCK && (set->__bits[4/sizeof *set->__bits] & 3UL<<(32&8*sizeof *set->__bits-1))) {
+		tmp = *set;
+		set = &tmp;
+		tmp.__bits[4/sizeof *set->__bits] &= ~(3UL<<(32&8*sizeof *set->__bits-1));
+	}
+	return __libc_sigprocmask(how, set, old);
+}
+
+weak_alias(__sigprocmask, sigprocmask);
+weak_alias(__sigprocmask, pthread_sigmask);
diff --git a/src/signal/sigqueue.c b/src/signal/sigqueue.c
new file mode 100644
index 00000000..ce3abf6c
--- /dev/null
+++ b/src/signal/sigqueue.c
@@ -0,0 +1,14 @@
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include "syscall.h"
+
+int sigqueue(pid_t pid, int sig, const union sigval value)
+{
+	siginfo_t si = {
+		.si_signo = sig,
+		.si_code = -1,
+		.si_value = value,
+	};
+	return syscall3(__NR_rt_sigqueueinfo, pid, sig, (long)&si);
+}
diff --git a/src/signal/sigrelse.c b/src/signal/sigrelse.c
new file mode 100644
index 00000000..b0b3024b
--- /dev/null
+++ b/src/signal/sigrelse.c
@@ -0,0 +1,11 @@
+#include <signal.h>
+#include <stdlib.h>
+
+int sigrelse(int sig)
+{
+	sigset_t mask;
+
+	sigemptyset(&mask);
+	if (sigaddset(&mask, sig) < 0) return -1;
+	return sigprocmask(SIG_UNBLOCK, &mask, NULL);
+}
diff --git a/src/signal/sigrtmax.c b/src/signal/sigrtmax.c
new file mode 100644
index 00000000..0ef29873
--- /dev/null
+++ b/src/signal/sigrtmax.c
@@ -0,0 +1,4 @@
+int __libc_current_sigrtmax()
+{
+	return 64;
+}
diff --git a/src/signal/sigrtmin.c b/src/signal/sigrtmin.c
new file mode 100644
index 00000000..7ad06d22
--- /dev/null
+++ b/src/signal/sigrtmin.c
@@ -0,0 +1,4 @@
+int __libc_current_sigrtmin()
+{
+	return 34;
+}
diff --git a/src/signal/sigset.c b/src/signal/sigset.c
new file mode 100644
index 00000000..1b6b38fd
--- /dev/null
+++ b/src/signal/sigset.c
@@ -0,0 +1,28 @@
+#include <signal.h>
+#include <stdlib.h>
+
+void (*sigset(int sig, void (*handler)(int)))(int)
+{
+	struct sigaction sa, sa_old;
+	sigset_t mask;
+
+	sigemptyset(&mask);
+	if (sigaddset(&mask, sig) < 0)
+		return SIG_ERR;
+	
+	if (handler == SIG_HOLD) {
+		if (sigaction(sig, NULL, &sa_old) < 0)
+			return SIG_ERR;
+		if (sigprocmask(SIG_BLOCK, &mask, &mask) < 0)
+			return SIG_ERR;
+	} else {
+		sa.sa_handler = handler;
+		sa.sa_flags = 0;
+		sigemptyset(&sa.sa_mask);
+		if (sigaction(sig, &sa, &sa_old) < 0)
+			return SIG_ERR;
+		if (sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
+			return SIG_ERR;
+	}
+	return sigismember(&mask, sig) ? SIG_HOLD : sa_old.sa_handler;
+}
diff --git a/src/signal/sigsetjmp.c b/src/signal/sigsetjmp.c
new file mode 100644
index 00000000..a6667a27
--- /dev/null
+++ b/src/signal/sigsetjmp.c
@@ -0,0 +1,17 @@
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+
+/* !!! This function will not work unless the compiler performs
+ * tail call optimization. Machine-specific asm versions should
+ * be created instead even though the workaround (tail call)
+ * is entirely non-machine-specific... */
+
+int sigsetjmp(sigjmp_buf buf, int save)
+{
+	long *flag = buf + sizeof(jmp_buf)/sizeof(long);
+	sigset_t *mask = (void *)(flag + 1);
+	if ((*flag = save))
+		sigprocmask (SIG_SETMASK, NULL, mask);
+	return setjmp((void *)buf);
+}
diff --git a/src/signal/sigsuspend.c b/src/signal/sigsuspend.c
new file mode 100644
index 00000000..1acdab06
--- /dev/null
+++ b/src/signal/sigsuspend.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include "syscall.h"
+
+int sigsuspend(const sigset_t *mask)
+{
+	return syscall2(__NR_rt_sigsuspend, (long)mask, sizeof(sigset_t));
+}
diff --git a/src/signal/sigtimedwait.c b/src/signal/sigtimedwait.c
new file mode 100644
index 00000000..155185de
--- /dev/null
+++ b/src/signal/sigtimedwait.c
@@ -0,0 +1,12 @@
+#include <signal.h>
+#include "syscall.h"
+
+int sigtimedwait(const sigset_t *mask, siginfo_t *si, const struct timespec *timeout)
+{
+	long k_timeout[2];
+	if (timeout) {
+		k_timeout[0] = timeout->tv_sec;
+		k_timeout[1] = timeout->tv_nsec;
+	}
+	return syscall4(__NR_rt_sigtimedwait, (long)mask, (long)si, timeout ? (long)k_timeout : 0, SYSCALL_SIGSET_SIZE);
+}
diff --git a/src/signal/sigwait.c b/src/signal/sigwait.c
new file mode 100644
index 00000000..9569d6b0
--- /dev/null
+++ b/src/signal/sigwait.c
@@ -0,0 +1,11 @@
+#include <signal.h>
+#include <stddef.h>
+
+int sigwait(const sigset_t *mask, int *sig)
+{
+	siginfo_t si;
+	if (sigtimedwait(mask, &si, NULL) < 0)
+		return -1;
+	*sig = si.si_signo;
+	return 0;
+}
diff --git a/src/signal/sigwaitinfo.c b/src/signal/sigwaitinfo.c
new file mode 100644
index 00000000..e79feb91
--- /dev/null
+++ b/src/signal/sigwaitinfo.c
@@ -0,0 +1,7 @@
+#include <signal.h>
+#include <stddef.h>
+
+int sigwaitinfo(const sigset_t *mask, siginfo_t *si)
+{
+	return sigtimedwait(mask, si, NULL);
+}
diff --git a/src/stat/chmod.c b/src/stat/chmod.c
new file mode 100644
index 00000000..cb310fec
--- /dev/null
+++ b/src/stat/chmod.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+int chmod(const char *path, mode_t mode)
+{
+	return syscall2(__NR_chmod, (long)path, mode);
+}
diff --git a/src/stat/fchmod.c b/src/stat/fchmod.c
new file mode 100644
index 00000000..91897383
--- /dev/null
+++ b/src/stat/fchmod.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+int fchmod(int fd, mode_t mode)
+{
+	return syscall2(__NR_fchmod, fd, mode);
+}
diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
new file mode 100644
index 00000000..f4f22b2c
--- /dev/null
+++ b/src/stat/fchmodat.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+int fchmodat(int fd, const char *path, mode_t mode, int flag)
+{
+	return syscall4(__NR_fchmodat, fd, (long)path, mode, flag);
+}
diff --git a/src/stat/fstat.c b/src/stat/fstat.c
new file mode 100644
index 00000000..5f643301
--- /dev/null
+++ b/src/stat/fstat.c
@@ -0,0 +1,10 @@
+#include <sys/stat.h>
+#include "syscall.h"
+#include "libc.h"
+
+int fstat(int fd, struct stat *buf)
+{
+	return syscall2(__NR_fstat64, fd, (long)buf);
+}
+
+LFS64(fstat);
diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
new file mode 100644
index 00000000..22bc2934
--- /dev/null
+++ b/src/stat/fstatat.c
@@ -0,0 +1,10 @@
+#include <sys/stat.h>
+#include "syscall.h"
+#include "libc.h"
+
+int fstatat(int fd, const char *path, struct stat *buf, int flag)
+{
+	return syscall4(__NR_fstatat64, fd, (long)path, (long)buf, flag);
+}
+
+LFS64(fstatat);
diff --git a/src/stat/fstatvfs.c b/src/stat/fstatvfs.c
new file mode 100644
index 00000000..83bd7486
--- /dev/null
+++ b/src/stat/fstatvfs.c
@@ -0,0 +1,13 @@
+#include <sys/statvfs.h>
+#include "syscall.h"
+#include "libc.h"
+
+int fstatvfs(int fd, struct statvfs *buf)
+{
+	return syscall2(__NR_fstatfs64, fd, (long)buf);
+}
+
+weak_alias(fstatvfs, fstatfs);
+
+LFS64(fstatvfs);
+LFS64(fstatfs);
diff --git a/src/stat/lstat.c b/src/stat/lstat.c
new file mode 100644
index 00000000..afdb5538
--- /dev/null
+++ b/src/stat/lstat.c
@@ -0,0 +1,10 @@
+#include <sys/stat.h>
+#include "syscall.h"
+#include "libc.h"
+
+int lstat(const char *path, struct stat *buf)
+{
+	return syscall2(__NR_lstat64, (long)path, (long)buf);
+}
+
+LFS64(lstat);
diff --git a/src/stat/mkdir.c b/src/stat/mkdir.c
new file mode 100644
index 00000000..8295cad5
--- /dev/null
+++ b/src/stat/mkdir.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+int mkdir(const char *path, mode_t mode)
+{
+	return syscall2(__NR_mkdir, (long)path, mode);
+}
diff --git a/src/stat/mkdirat.c b/src/stat/mkdirat.c
new file mode 100644
index 00000000..1fb38250
--- /dev/null
+++ b/src/stat/mkdirat.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+int mkdirat(int fd, const char *path, mode_t mode)
+{
+	return syscall3(__NR_mkdirat, fd, (long)path, mode);
+}
diff --git a/src/stat/mkfifo.c b/src/stat/mkfifo.c
new file mode 100644
index 00000000..60efcf73
--- /dev/null
+++ b/src/stat/mkfifo.c
@@ -0,0 +1,6 @@
+#include <sys/stat.h>
+
+int mkfifo(const char *path, mode_t mode)
+{
+	return mknod(path, mode | S_IFIFO, 0);
+}
diff --git a/src/stat/mkfifoat.c b/src/stat/mkfifoat.c
new file mode 100644
index 00000000..d3a1f970
--- /dev/null
+++ b/src/stat/mkfifoat.c
@@ -0,0 +1,6 @@
+#include <sys/stat.h>
+
+int mkfifoat(int fd, const char *path, mode_t mode)
+{
+	return mknodat(fd, path, mode | S_IFIFO, 0);
+}
diff --git a/src/stat/mknod.c b/src/stat/mknod.c
new file mode 100644
index 00000000..0123eeef
--- /dev/null
+++ b/src/stat/mknod.c
@@ -0,0 +1,10 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+int mknod(const char *path, mode_t mode, dev_t dev)
+{
+	/* since dev_t is system-specific anyway we defer to the idiotic
+	 * legacy-compatible bitfield mapping of the type.. at least we've
+	 * made it large enough to leave space for future expansion.. */
+	return syscall3(__NR_mknod, (long)path, mode, dev & 0xffff);
+}
diff --git a/src/stat/mknodat.c b/src/stat/mknodat.c
new file mode 100644
index 00000000..b5687e47
--- /dev/null
+++ b/src/stat/mknodat.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+int mknodat(int fd, const char *path, mode_t mode, dev_t dev)
+{
+	return syscall4(__NR_mknodat, fd, (long)path, mode, dev & 0xffff);
+}
diff --git a/src/stat/stat.c b/src/stat/stat.c
new file mode 100644
index 00000000..67640cc1
--- /dev/null
+++ b/src/stat/stat.c
@@ -0,0 +1,10 @@
+#include <sys/stat.h>
+#include "syscall.h"
+#include "libc.h"
+
+int stat(const char *path, struct stat *buf)
+{
+	return syscall2(__NR_stat64, (long)path, (long)buf);
+}
+
+LFS64(stat);
diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c
new file mode 100644
index 00000000..55a05d52
--- /dev/null
+++ b/src/stat/statvfs.c
@@ -0,0 +1,13 @@
+#include <sys/statvfs.h>
+#include "syscall.h"
+#include "libc.h"
+
+int statvfs(const char *path, struct statvfs *buf)
+{
+	return syscall2(__NR_statfs64, (long)path, (long)buf);
+}
+
+weak_alias(statvfs, statfs);
+
+LFS64(statvfs);
+LFS64(statfs);
diff --git a/src/stat/umask.c b/src/stat/umask.c
new file mode 100644
index 00000000..49cb48a6
--- /dev/null
+++ b/src/stat/umask.c
@@ -0,0 +1,7 @@
+#include <sys/stat.h>
+#include "syscall.h"
+
+mode_t umask(mode_t mode)
+{
+	return syscall1(__NR_umask, mode);
+}
diff --git a/src/stdio/__fclose_ca.c b/src/stdio/__fclose_ca.c
new file mode 100644
index 00000000..e0b12a15
--- /dev/null
+++ b/src/stdio/__fclose_ca.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int __fclose_ca(FILE *f)
+{
+	return f->close(f);
+}
diff --git a/src/stdio/__fdopen.c b/src/stdio/__fdopen.c
new file mode 100644
index 00000000..6ad7c57d
--- /dev/null
+++ b/src/stdio/__fdopen.c
@@ -0,0 +1,52 @@
+#include "stdio_impl.h"
+
+FILE *__fdopen(int fd, const char *mode)
+{
+	FILE *f;
+	struct termios tio;
+	int plus = !!strchr(mode, '+');
+
+	/* Check for valid initial mode character */
+	if (!strchr("rwa", *mode)) return 0;
+
+	/* Allocate FILE+buffer or fail */
+	if (!(f=malloc(sizeof *f + UNGET + BUFSIZ))) return 0;
+
+	/* Zero-fill only the struct, not the buffer */
+	memset(f, 0, sizeof *f);
+
+	/* Impose mode restrictions */
+	if (!plus) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
+
+	/* Set append mode on fd if opened for append */
+	if (*mode == 'a') {
+		int flags = __syscall_fcntl(fd, F_GETFL, 0);
+		__syscall_fcntl(fd, F_SETFL, flags | O_APPEND);
+	}
+
+	f->fd = fd;
+	f->buf = (unsigned char *)f + sizeof *f + UNGET;
+	f->buf_size = BUFSIZ;
+
+	/* Activate line buffered mode for terminals */
+	f->lbf = EOF;
+	if (!(f->flags & F_NOWR) && !__syscall_ioctl(fd, TCGETS, &tio))
+		f->lbf = '\n';
+
+	/* Initialize op ptrs. No problem if some are unneeded. */
+	f->read = __stdio_read;
+	f->write = __stdio_write;
+	f->seek = __stdio_seek;
+	f->close = __stdio_close;
+
+	/* Add new FILE to open file list */
+	OFLLOCK();
+	f->next = ofl_head;
+	if (ofl_head) ofl_head->prev = f;
+	ofl_head = f;
+	OFLUNLOCK();
+
+	return f;
+}
+
+weak_alias(__fdopen, fdopen);
diff --git a/src/stdio/__fopen_rb_ca.c b/src/stdio/__fopen_rb_ca.c
new file mode 100644
index 00000000..57d9b73c
--- /dev/null
+++ b/src/stdio/__fopen_rb_ca.c
@@ -0,0 +1,18 @@
+#include "stdio_impl.h"
+
+FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t len)
+{
+	memset(f, 0, sizeof *f);
+
+	f->fd = __syscall_open(filename, O_RDONLY, 0);
+	if (f->fd < 0) return 0;
+
+	f->flags = F_NOWR | F_PERM;
+	f->buf = buf + UNGET;
+	f->buf_size = len - UNGET;
+	f->read = __stdio_read;
+	f->seek = __stdio_seek;
+	f->close = __stdio_close;
+
+	return f;
+}
diff --git a/src/stdio/__fpending.c b/src/stdio/__fpending.c
new file mode 100644
index 00000000..a4334e23
--- /dev/null
+++ b/src/stdio/__fpending.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+size_t __fpending(FILE *f)
+{
+	return f->wend ? f->wpos - f->wbase : 0;
+}
diff --git a/src/stdio/__ofl.c b/src/stdio/__ofl.c
new file mode 100644
index 00000000..7d9652c8
--- /dev/null
+++ b/src/stdio/__ofl.c
@@ -0,0 +1,3 @@
+#include "stdio_impl.h"
+
+struct ofl __ofl;
diff --git a/src/stdio/__overflow.c b/src/stdio/__overflow.c
new file mode 100644
index 00000000..e35104de
--- /dev/null
+++ b/src/stdio/__overflow.c
@@ -0,0 +1,52 @@
+#include "stdio_impl.h"
+
+static int overflow(FILE *f, int c)
+{
+	/* Initialize if we're not already writing */
+	if (!f->wend) {
+		/* Fail if we're in error state or unwritable. */
+		if (f->flags & (F_ERR|F_NOWR)) return EOF;
+
+		/* Set byte orientation -1,0=>-1; 1=>1 */
+		f->mode |= f->mode-1;
+
+		/* Clear read buffer (easier than summoning nasal demons) */
+		f->rpos = f->rend = f->rstop = 0;
+
+		/* Activate write through the buffer */
+		f->wpos = f->wbase = f->buf;
+		f->wend = f->buf + f->buf_size;
+		f->wstop = (f->lbf < 0) ? f->wend - 1 : 0;
+	}
+
+	/* Buffer can always hold at least 1 byte... */
+	if (c != EOF) {
+		*f->wpos++ = c;
+		if (f->wpos <= f->wstop && c != f->lbf) return c;
+	}
+	/* ...since if the next call fails, buffer is empty. */
+	if (f->write(f, f->wbase, f->wpos - f->wbase) < 0) {
+		f->flags |= F_ERR;
+		f->wpos = f->wbase = f->wend = f->wstop = 0;
+		return EOF;
+	}
+
+	/* Buffer is empty so reset position to beginning */
+	f->wpos = f->wbase;
+
+	return c;
+}
+
+int __overflow(FILE *f, int c)
+{
+	return overflow(f, c & 0xff);
+}
+
+int __oflow(FILE *f)
+{
+	overflow(f, EOF);
+	return (f->flags & F_ERR) ? EOF : 0;
+}
+
+/* Link flush-on-exit code iff any stdio write functions are linked. */
+int (*const __fflush_on_exit)(FILE *) = fflush;
diff --git a/src/stdio/__scanf.c b/src/stdio/__scanf.c
new file mode 100644
index 00000000..185615d3
--- /dev/null
+++ b/src/stdio/__scanf.c
@@ -0,0 +1,487 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <float.h>
+
+#include "__scanf.h"
+
+static int read(rctx_t *r)
+{
+	if (--r->w < 0) return r->w = -1;
+	if (r->u) r->u = 0;
+	else r->read(r);
+	return r->c;
+}
+
+static void unread(rctx_t *r)
+{
+	//if (r->u || r->w < 0) return;
+	if (r->w < 0) return;
+	r->w++;
+	r->u = 1;
+}
+
+#define SIZE_hh -2
+#define SIZE_h  -1
+#define SIZE_def 0
+#define SIZE_l   1
+#define SIZE_ll  2
+#define SIZE_L   3
+
+static void store_int(void *dest, int size, int neg, unsigned long long i)
+{
+	if (!dest) return;
+	if (neg) i = -i;
+	switch (size) {
+	case SIZE_hh:
+		*(char *)dest = i;
+		break;
+	case SIZE_h:
+		*(short *)dest = i;
+		break;
+	case SIZE_def:
+		*(int *)dest = i;
+		break;
+	case SIZE_l:
+		*(long *)dest = i;
+		break;
+	case SIZE_ll:
+		*(long long *)dest = i;
+		break;
+	}
+}
+
+static void *arg_n(va_list ap, unsigned int n)
+{
+	void *p;
+	unsigned int i;
+	va_list ap2;
+	va_copy(ap2, ap);
+	for (i=n; i>1; i--) va_arg(ap2, void *);
+	p = va_arg(ap2, void *);
+	va_end(ap2);
+	return p;
+}
+
+int __scanf(rctx_t *r, const wchar_t *fmt, va_list ap)
+{
+	int mode=0;
+	int width;
+	int size;
+	const wchar_t *p, *z;
+	int c, l, t, m;
+	long long dummy;
+	char *s;
+	wchar_t *wcs;
+	mbstate_t st;
+	int wide = r->wide;
+	void *dest=NULL;
+	int invert;
+	unsigned long long i=0;
+	int neg=0;
+	int matches=0;
+	long double f;
+	int (*is_space)(int) = r->is_space;
+
+	for (p=fmt; *p; ) {
+		if (is_space(*p)) {
+			do p++; while (is_space(*p));
+			do r->w=1; while (is_space(read(r)));
+			unread(r);
+			continue;
+		} else if (*p != '%' || p[1] == '%') {
+			if (*p == '%') p++;
+			r->w = 1;
+			if (*p++ != read(r))
+				goto match_fail;
+			continue;
+		}
+		p++;
+		if (mode != 1) {
+			for (z=p; isdigit(*z); z++);
+			if (*z != '$' && *z != '*') {
+				if (mode == 0) mode = 1;
+				else goto fmt_fail;
+			} else if (*z != '*') {
+				int pos = 0;
+				mode = 2;
+				for (; p<z; p++) {
+					pos = 10*pos + *p - '0';
+				}
+				p++;
+				if (!pos) goto fmt_fail;
+				dest = arg_n(ap, pos);
+			}
+		}
+		if (*p == '*') {
+			dest = NULL;
+			p++;
+		} else if (mode == 1) {
+			dest = va_arg(ap, void *);
+		}
+		
+		if (!*p) goto fmt_fail;
+
+		width = 0;
+		for (; isdigit(*p); p++) {
+			width = 10*width + *p - '0';
+		}
+
+		size = 0;
+		switch (*p++) {
+		case 0:
+			goto fmt_fail;
+		case 'h':
+			if (*p == 'h') p++, size = SIZE_hh;
+			else size = SIZE_h;
+			break;
+		case 'l':
+			if (*p == 'l') p++, size = SIZE_ll;
+			else size = SIZE_l;
+			break;
+		case 'j':
+			size = SIZE_ll;
+			break;
+		case 'z':
+		case 't':
+			size = SIZE_l;
+			break;
+		case 'L':
+			size = SIZE_L;
+			break;
+		case 'd': case 'i': case 'o': case 'u': case 'x':
+		case 'a': case 'e': case 'f': case 'g':
+		case 'A': case 'E': case 'F': case 'G': case 'X':
+		case 's': case 'c': case '[':
+		case 'S': case 'C':
+		case 'p': case 'n':
+			p--;
+			break;
+		default:
+			goto fmt_fail;
+		}
+
+		t = *p++;
+
+		switch (t) {
+		case 'C':
+		case 'c':
+			if (width < 1) width = 1;
+		case 's':
+			if (size == SIZE_l) t &= ~0x20;
+		case 'd': case 'i': case 'o': case 'u': case 'x':
+		case 'a': case 'e': case 'f': case 'g':
+		case 'A': case 'E': case 'F': case 'G': case 'X':
+		case '[': case 'S':
+		case 'p': case 'n':
+			if (width < 1) width = INT_MAX;
+			break;
+		default:
+			goto fmt_fail;
+		}
+
+		r->w = width;
+
+		if (t != 'n') {
+			if (read(r) < 0) goto input_fail;
+			unread(r);
+		}
+
+		switch (t) {
+		case 'n':
+			store_int(dest, size, 0, r->l - r->u);
+			/* do not increment match count, etc! */
+			continue;
+		case 'C':
+			wcs = dest ? dest : (void *)&dummy;
+			st = (mbstate_t){ 0 };
+			while ((c=read(r)) >= 0) {
+				if (wide) {
+					if (dest) *wcs++ = c;
+				} else {
+					char ch = c;
+					switch (mbrtowc(wcs, &ch, 1, &st)) {
+					case -1:
+						goto enc_fail;
+					case -2:
+						break;
+					default:
+						if (dest) wcs++;
+					}
+				}
+			}
+			if (r->w > 0) goto match_fail;
+			break;
+		case 'c':
+			s = dest ? dest : (void *)&dummy;
+			while ((c=read(r)) >= 0) {
+				if (wide) {
+					if ((l=wctomb(s, c)) < 0)
+						goto enc_fail;
+					if (dest) s += l;
+				} else {
+					if (dest) *s++ = c;
+				}
+			}
+			if (r->w > 0) goto match_fail;
+			break;
+		case '[':
+			wcs = dest ? dest : (void *)&dummy;
+			s = dest ? dest : (void *)&dummy;
+			if (!wide && size == SIZE_l) st = (mbstate_t){ 0 };
+
+			if (*p == '^') p++, invert = 1;
+			else invert = 0;
+
+			if (wide) {
+				for (m=0; (c=read(r)) >= 0; m=1) {
+					for (z=p; *z && *z != c && (*z != ']' || z==p); z++);
+					if (!*z) goto fmt_fail;
+					if (*z == c && (*z != ']' || z==p)) {
+						if (invert) break;
+					} else {
+						if (!invert) break;
+					}
+					if (size == SIZE_l) {
+						if (dest) *wcs++ = c;
+					} else {
+						if ((l=wctomb(s, c)) < 0)
+							goto enc_fail;
+						if (dest) s += l;
+					}
+				}
+				for (p++; *p && *p != ']'; p++);
+				p++;
+			} else {
+				unsigned char scanset[257];
+				memset(scanset, invert, sizeof scanset);
+				scanset[0] = 0;
+				for (z=p; *z && (*z != ']' || z==p); z++)
+					scanset[1+*z] = 1-invert;
+				if (!*z) goto fmt_fail;
+				p=z+1;
+				c=0;
+				for (m=0; scanset[(c=read(r))+1]; m=1) {
+					if (size == SIZE_l) {
+						char ch = c;
+						switch (mbrtowc(wcs, &ch, 1, &st)) {
+						case -1:
+							goto enc_fail;
+						case -2:
+							break;
+						default:
+							if (dest) wcs++;
+						}
+					} else {
+						if (dest) *s++ = c;
+					}
+				}
+			}
+			if (!m) goto match_fail;
+			if (dest) {
+				if (size == SIZE_l) *wcs++ = 0;
+				else *s++ = 0;
+			}
+			break;
+		default:
+			/* read unlimited number of spaces, then reset width */
+			do r->w = 1; while (is_space(c = read(r)));
+			if (c < 0) goto input_fail;
+			unread(r);
+			r->w = width;
+		}
+
+		switch (t) {
+		case 'p':
+		case 'X':
+			t = 'x';
+		case 'd':
+		case 'i':
+		case 'o':
+		case 'u':
+		case 'x':
+			i = m = neg = 0;
+			if ((c=read(r)) == '-') neg=1;
+			else if (c != '+') unread(r);
+			switch (t) {
+			case 'i':
+			case 'x':
+				if ((c=read(r)) != '0') {
+					if (t == 'i') t = 'd';
+					unread(r);
+					break;
+				}
+				if (((c=read(r))|0x20) != 'x') {
+					if (t == 'i') {
+						t = 'o';
+						/* lone 0 is valid octal */
+						if ((unsigned)(c-'0') >= 8) {
+							m = 1;
+							goto int_finish;
+						}
+					}
+					unread(r);
+					break;
+				}
+				t = 'x';
+			}
+		}
+		
+		switch (t) {
+		case 'd':
+		case 'u':
+			for (m=0; isdigit(c=read(r)); m=1)
+				i = 10*i + c-'0';
+			goto int_finish;
+		case 'o':
+			for (m=0; (unsigned)(c=read(r))-'0' < 8; m=1)
+				i = (i<<3) + c-'0';
+			goto int_finish;
+		case 'x':
+			for (m=0; ; m=1) {
+				if (isdigit(c=read(r))) {
+					i = (i<<4) + c-'0';
+				} else if ((unsigned)(c|0x20)-'a' < 6) {
+					i = (i<<4) + (c|0x20)-'a'+10;
+				} else break;
+			}
+		int_finish:
+			if (!m) goto match_fail;
+			store_int(dest, size, neg, i);
+			break;
+		case 'a':
+		case 'e':
+		case 'f':
+		case 'g':
+			f = 0.0;
+			neg = m = 0;
+			if ((c=read(r)) == '-') neg=1;
+			else if (c != '+') unread(r);
+			/* FIXME: check for INF/NAN strings here */
+			if (read(r)=='0' && (m=1, (read(r)|0x20) == 'x'))
+				goto hexfloat;
+			else unread(r);
+			for (; isdigit(c=read(r)); m=1)
+				f = 10.0 * f + (c-'0');
+			if (c=='.') {
+				double mag = 10.0;
+				for (; isdigit(c=read(r)); mag*=10.0)
+					f += (c-'0')/mag;
+			}
+			if ((c|0x20)=='e') {
+				int ex=0, en=0;
+				m = 0;
+				if ((c=read(r))=='-') en=1;
+				else if (c!='+') unread(r);
+				for (; isdigit(c=read(r)); m=1)
+					if (ex < LDBL_MAX_10_EXP)
+						ex = 10 * ex + (c-'0');
+				if (ex > LDBL_MAX_10_EXP)
+					f = en ? 0 : INFINITY;
+				else {
+					if (en) while (ex--) f/=10.0;
+					else while (ex--) f*=10.0;
+				}
+			}
+			goto writefloat;
+hexfloat:
+			m = 0;
+			for (; isxdigit(c=read(r)); m=1)
+				if (isdigit(c)) f = 16.0*f + (c-'0');
+				else f = 16.0*f + ((c|32)-'a'+10);
+			if (c=='.') {
+				double mag = 1/16.0;
+				for (; isxdigit(c=read(r)); mag*=1/16.0)
+					if (isdigit(c)) f += (c-'0')*mag;
+					else f += ((c|32)-'a'+10)*mag;
+			}
+			if ((c|0x20)=='p') {
+				int ex=0, en=0;
+				m = 0;
+				if ((c=read(r))=='-') en=1;
+				else if (c!='+') unread(r);
+				for (; isdigit(c=read(r)); m=1)
+					if (ex < LDBL_MAX_EXP)
+						ex = 10 * ex + (c-'0');
+				if (ex > LDBL_MAX_EXP)
+					f = en ? 0 : INFINITY;
+				else {
+					if (en) while (ex--) f*=0.5;
+					else while (ex--) f*=2.0;
+				}
+			}
+writefloat:
+			if (!m) goto match_fail;
+			if (neg) f *= -1.0;
+			if (dest) switch (size) {
+			case SIZE_def:
+				*(float *)dest = f;
+				break;
+			case SIZE_l:
+				*(double *)dest = f;
+				break;
+			case SIZE_L:
+				*(long double *)dest = f;
+				break;
+			}
+			break;
+		case 'S':
+			wcs = dest ? dest : (void *)&dummy;
+			st = (mbstate_t){ 0 };
+			while((c=read(r)) >= 0) {
+				if (wide) {
+					if (is_space(c)) break;
+					if (dest) *wcs++ = c;
+				} else {
+					char ch = c;
+					if (is_space(c)) break;
+					switch (mbrtowc(wcs, &ch, 1, &st)) {
+					case -1:
+						goto enc_fail;
+					case -2:
+						break;
+					default:
+						if (dest) wcs++;
+					}
+				}
+			}
+			if (dest) *wcs++ = 0;
+			break;
+		case 's':
+			s = dest ? dest : (void *)&dummy;
+			while((c=read(r)) >= 0) {
+				if (wide) {
+					if (is_space(c)) break;
+					if ((l=wctomb(s, c)) < 0)
+						goto enc_fail;
+					if (dest) s += l;
+				} else {
+					if (is_space(c)) break;
+					if (dest) *s++ = c;
+				}
+			}
+			if (dest) *s++ = 0;
+			break;
+		}
+
+		/* unread will do nothing if field width was exhausted */
+		unread(r);
+		if (dest) matches++;
+	}
+	return matches;
+enc_fail:
+	errno = EILSEQ;
+fmt_fail:
+input_fail:
+	if (!matches) matches--;
+match_fail:
+	unread(r);
+	return matches;
+}
diff --git a/src/stdio/__scanf.h b/src/stdio/__scanf.h
new file mode 100644
index 00000000..e549b979
--- /dev/null
+++ b/src/stdio/__scanf.h
@@ -0,0 +1,16 @@
+#include <wchar.h>
+
+typedef struct rctx
+{
+	void (*read)(struct rctx *);
+	void *opaque;
+	int wide;
+	int (*is_space)();
+	int l;
+	int e;
+	int c;
+	int u;
+	int w;
+} rctx_t;
+
+int __scanf(rctx_t *, const wchar_t *, va_list);
diff --git a/src/stdio/__stdio_close.c b/src/stdio/__stdio_close.c
new file mode 100644
index 00000000..24fef33f
--- /dev/null
+++ b/src/stdio/__stdio_close.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int __stdio_close(FILE *f)
+{
+	return __syscall_close(f->fd);
+}
diff --git a/src/stdio/__stdio_read.c b/src/stdio/__stdio_read.c
new file mode 100644
index 00000000..ee7e1258
--- /dev/null
+++ b/src/stdio/__stdio_read.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
+{
+	return __syscall_read(f->fd, buf, len);
+}
diff --git a/src/stdio/__stdio_seek.c b/src/stdio/__stdio_seek.c
new file mode 100644
index 00000000..fdb9fe7f
--- /dev/null
+++ b/src/stdio/__stdio_seek.c
@@ -0,0 +1,15 @@
+#include "stdio_impl.h"
+
+static off_t retneg1(FILE *f, off_t off, int whence)
+{
+	return -1;
+}
+
+off_t __stdio_seek(FILE *f, off_t off, int whence)
+{
+	off_t ret = __syscall_lseek(f->fd, off, whence);
+	/* Detect unseekable files and optimize future failures out */
+	if (ret < 0 && off == 0 && whence == SEEK_CUR)
+		f->seek = retneg1;
+	return ret;
+}
diff --git a/src/stdio/__stdio_write.c b/src/stdio/__stdio_write.c
new file mode 100644
index 00000000..78545626
--- /dev/null
+++ b/src/stdio/__stdio_write.c
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+
+size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
+{
+	const unsigned char *stop = buf+len;
+	ssize_t cnt = 1;
+	for (; buf<stop && (cnt=__syscall_write(f->fd, buf, len))>0; buf+=cnt);
+	return len-(stop-buf);
+}
diff --git a/src/stdio/__uflow.c b/src/stdio/__uflow.c
new file mode 100644
index 00000000..5a51d610
--- /dev/null
+++ b/src/stdio/__uflow.c
@@ -0,0 +1,7 @@
+#include "stdio_impl.h"
+
+int __uflow(FILE *f)
+{
+	if (__underflow(f) < 0) return EOF;
+	else return *f->rpos++;
+}
diff --git a/src/stdio/__underflow.c b/src/stdio/__underflow.c
new file mode 100644
index 00000000..b769f4e4
--- /dev/null
+++ b/src/stdio/__underflow.c
@@ -0,0 +1,38 @@
+#include "stdio_impl.h"
+
+int __underflow(FILE *f)
+{
+	ssize_t cnt;
+
+	/* Read from buffer (Do we ever get called when this is true??) */
+	if (f->rpos < f->rstop) return *f->rpos;
+
+	/* Initialize if we're not already reading */
+	if (!f->rstop) {
+		/* Fail immediately if unreadable, eof, or error state. */
+		if (f->flags & (F_EOF|F_ERR|F_NORD)) return EOF;
+
+		/* Set byte orientation -1,0=>-1; 1=>1 */
+		f->mode |= f->mode-1;
+
+		/* Flush any unwritten output; fail on error. */
+		if (f->wpos > f->buf && __oflow(f)) return EOF;
+
+		/* Disallow writes to buffer. */
+		f->wstop = 0;
+	}
+
+	/* Perform the underlying read operation */
+	if ((cnt=f->read(f, f->buf, f->buf_size)) + 1 <= 1) {
+		/* Set flags and leave read mode */
+		f->flags |= F_EOF | (cnt & F_ERR);
+		f->rpos = f->rend = f->rstop = 0;
+		return EOF;
+	}
+
+	/* Setup buffer pointers for reading from buffer */
+	f->rpos = f->buf;
+	f->rend = f->rstop = f->buf + cnt;
+
+	return *f->rpos;
+}
diff --git a/src/stdio/asprintf.c b/src/stdio/asprintf.c
new file mode 100644
index 00000000..79e59c2d
--- /dev/null
+++ b/src/stdio/asprintf.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int vasprintf(char **, const char *, va_list);
+
+int asprintf(char **s, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vasprintf(s, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/clearerr.c b/src/stdio/clearerr.c
new file mode 100644
index 00000000..3bf94d30
--- /dev/null
+++ b/src/stdio/clearerr.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+void clearerr(FILE *f)
+{
+	FLOCK(f);
+	f->flags &= ~(F_EOF|F_ERR);
+	FUNLOCK(f);
+}
+
+weak_alias(clearerr, clearerr_unlocked);
diff --git a/src/stdio/dprintf.c b/src/stdio/dprintf.c
new file mode 100644
index 00000000..fa28322f
--- /dev/null
+++ b/src/stdio/dprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int dprintf(int fd, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vdprintf(fd, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/fclose.c b/src/stdio/fclose.c
new file mode 100644
index 00000000..26bc37e8
--- /dev/null
+++ b/src/stdio/fclose.c
@@ -0,0 +1,21 @@
+#include "stdio_impl.h"
+
+int fclose(FILE *f)
+{
+	int r;
+	int perm = f->flags & F_PERM;
+
+	if (!perm) {
+		OFLLOCK();
+		if (f->prev) f->prev->next = f->next;
+		if (f->next) f->next->prev = f->prev;
+		if (ofl_head == f) ofl_head = f->next;
+		OFLUNLOCK();
+	}
+
+	r = fflush(f) | f->close(f);
+
+	if (!perm) free(f);
+	
+	return r;
+}
diff --git a/src/stdio/feof.c b/src/stdio/feof.c
new file mode 100644
index 00000000..f2b739b5
--- /dev/null
+++ b/src/stdio/feof.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+#undef feof
+
+int feof(FILE *f)
+{
+	return !!(f->flags & F_EOF);
+}
+
+weak_alias(feof, feof_unlocked);
diff --git a/src/stdio/ferror.c b/src/stdio/ferror.c
new file mode 100644
index 00000000..f535fbed
--- /dev/null
+++ b/src/stdio/ferror.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+#undef ferror
+
+int ferror(FILE *f)
+{
+	return !!(f->flags & F_ERR);
+}
+
+weak_alias(ferror, ferror_unlocked);
diff --git a/src/stdio/fflush.c b/src/stdio/fflush.c
new file mode 100644
index 00000000..cf3f5b0e
--- /dev/null
+++ b/src/stdio/fflush.c
@@ -0,0 +1,50 @@
+#include "stdio_impl.h"
+
+static int __fflush_unlocked(FILE *f)
+{
+	/* If writing, flush output. */
+	if (f->wpos > f->buf && __oflow(f)) return -1;
+
+	/* If reading, sync position, per POSIX */
+	if (f->rpos < f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
+	f->rpos = f->rend;
+
+	/* Hook for special behavior on flush */
+	if (f->flush) f->flush(f);
+
+	return (f->flags & F_ERR) ? EOF : 0;
+}
+
+/* stdout.c will override this if linked */
+static FILE *const __dummy = 0;
+weak_alias(__dummy, __stdout_to_flush);
+
+int fflush(FILE *f)
+{
+	int r;
+	FILE *next;
+
+	if (f) {
+		FLOCK(f);
+		r = __fflush_unlocked(f);
+		FUNLOCK(f);
+		return r;
+	}
+
+	r = __stdout_to_flush ? fflush(__stdout_to_flush) : 0;
+
+	OFLLOCK();
+	for (f=ofl_head; f; f=next) {
+		FLOCK(f);
+		OFLUNLOCK();
+		r |= __fflush_unlocked(f);
+		OFLLOCK();
+		next = f->next;
+		FUNLOCK(f);
+	}
+	OFLUNLOCK();
+	
+	return r;
+}
+
+weak_alias(__fflush_unlocked, fflush_unlocked);
diff --git a/src/stdio/fgetc.c b/src/stdio/fgetc.c
new file mode 100644
index 00000000..3a7f1e30
--- /dev/null
+++ b/src/stdio/fgetc.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+int fgetc(FILE *f)
+{
+	int c;
+	FLOCK(f);
+	c = f->rpos < f->rstop ? *f->rpos++ : __uflow(f);
+	FUNLOCK(f);
+	return c;
+}
diff --git a/src/stdio/fgetpos.c b/src/stdio/fgetpos.c
new file mode 100644
index 00000000..5b663d1e
--- /dev/null
+++ b/src/stdio/fgetpos.c
@@ -0,0 +1,11 @@
+#include "stdio_impl.h"
+
+int fgetpos(FILE *f, fpos_t *pos)
+{
+	off_t off = __ftello(f);
+	if (off < 0) return -1;
+	*(off_t *)pos = off;
+	return 0;
+}
+
+LFS64(fgetpos);
diff --git a/src/stdio/fgets.c b/src/stdio/fgets.c
new file mode 100644
index 00000000..7939303e
--- /dev/null
+++ b/src/stdio/fgets.c
@@ -0,0 +1,34 @@
+#include "stdio_impl.h"
+
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+char *fgets(char *s, int n, FILE *f)
+{
+	char *p = s;
+	unsigned char *z;
+	size_t k;
+
+	if (!n--) return 0;
+
+	FLOCK(f);
+
+	while (n && !feof(f)) {
+		z = memchr(f->rpos, '\n', f->rend - f->rpos);
+		k = z ? z - f->rpos + 1 : f->rend - f->rpos;
+		k = MIN(k, n);
+		memcpy(p, f->rpos, k);
+		f->rpos += k;
+		p += k;
+		n -= k;
+		if (z) break;
+		__underflow(f);
+	}
+	*p = 0;
+	if (ferror(f)) p = s;
+
+	FUNLOCK(f);
+
+	return (p == s) ? 0 : s;
+}
+
+weak_alias(fgets, fgets_unlocked);
diff --git a/src/stdio/fgetwc.c b/src/stdio/fgetwc.c
new file mode 100644
index 00000000..c990545f
--- /dev/null
+++ b/src/stdio/fgetwc.c
@@ -0,0 +1,51 @@
+#include "stdio_impl.h"
+
+wint_t __fgetwc_unlocked(FILE *f)
+{
+	mbstate_t st = { 0 };
+	wchar_t wc;
+	int c;
+	unsigned char b;
+	size_t l;
+
+	f->mode |= f->mode+1;
+
+	/* Convert character from buffer if possible */
+	if (f->rpos < f->rend) {
+		l = mbrtowc(&wc, f->rpos, f->rend - f->rpos, &st);
+		if (l+2 >= 2) {
+			f->rpos += l + !l; /* l==0 means 1 byte, null */
+			return wc;
+		}
+		if (l == -1) {
+			f->rpos++;
+			return WEOF;
+		}
+	} else l = -2;
+
+	/* Convert character byte-by-byte from __uflow */
+	while (l == -2) {
+		b = c = __uflow(f);
+		if (c < 0) {
+			if (!mbsinit(&st)) errno = EILSEQ;
+			return WEOF;
+		}
+		l = mbrtowc(&wc, &b, 1, &st);
+		if (l == -1) return WEOF;
+	}
+
+	FUNLOCK(f);
+	return wc;
+}
+
+wint_t fgetwc(FILE *f)
+{
+	wint_t c;
+	FLOCK(f);
+	c = __fgetwc_unlocked(f);
+	FUNLOCK(f);
+	return c;
+}
+
+weak_alias(__fgetwc_unlocked, fgetwc_unlocked);
+weak_alias(__fgetwc_unlocked, getwc_unlocked);
diff --git a/src/stdio/fgetws.c b/src/stdio/fgetws.c
new file mode 100644
index 00000000..2e76b565
--- /dev/null
+++ b/src/stdio/fgetws.c
@@ -0,0 +1,27 @@
+#include "stdio_impl.h"
+
+wint_t __fgetwc_unlocked(FILE *);
+
+wchar_t *fgetws(wchar_t *s, int n, FILE *f)
+{
+	wchar_t *p = s;
+
+	if (!n--) return s;
+
+	FLOCK(f);
+
+	for (; n; n--) {
+		wint_t c = __fgetwc_unlocked(f);
+		if (c == WEOF) break;
+		*p++ = c;
+		if (c == '\n') break;
+	}
+	*p = 0;
+	if (ferror(f)) p = s;
+
+	FUNLOCK(f);
+
+	return (p == s) ? NULL : s;
+}
+
+weak_alias(fgetws, fgetws_unlocked);
diff --git a/src/stdio/fileno.c b/src/stdio/fileno.c
new file mode 100644
index 00000000..9ffb26d5
--- /dev/null
+++ b/src/stdio/fileno.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+int fileno(FILE *f)
+{
+	return f->fd;
+}
+
+weak_alias(fileno, fileno_unlocked);
diff --git a/src/stdio/fmemopen.c b/src/stdio/fmemopen.c
new file mode 100644
index 00000000..77a60746
--- /dev/null
+++ b/src/stdio/fmemopen.c
@@ -0,0 +1,16 @@
+#if 0
+#include "stdio_impl.h"
+
+static ssize_t mread(FILE *f, unsigned char *buf, size_t len)
+{
+	memcpy(buf, 
+}
+
+FILE *fmemopen(void *buf, size_t size, const char *mode)
+{
+	FILE *f = calloc(sizeof(FILE), 1);
+	if (!f) return 0;
+	
+	//
+}
+#endif
diff --git a/src/stdio/fopen.c b/src/stdio/fopen.c
new file mode 100644
index 00000000..670cf5f3
--- /dev/null
+++ b/src/stdio/fopen.c
@@ -0,0 +1,34 @@
+#include "stdio_impl.h"
+
+FILE *fopen(const char *filename, const char *mode)
+{
+	FILE *f;
+	int fd;
+	int flags;
+	int plus = !!strchr(mode, '+');
+
+	/* Check for valid initial mode character */
+	if (!strchr("rwa", *mode)) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	/* Compute the flags to pass to open() */
+	if (plus) flags = O_RDWR;
+	else if (*mode == 'r') flags = O_RDONLY;
+	else flags = O_WRONLY;
+	if (*mode != 'r') flags |= O_CREAT;
+	if (*mode == 'w') flags |= O_TRUNC;
+	if (*mode == 'a') flags |= O_APPEND;
+
+	fd = __syscall_open(filename, flags, 0666);
+	if (fd < 0) return 0;
+
+	f = __fdopen(fd, mode);
+	if (f) return f;
+
+	__syscall_close(fd);
+	return 0;
+}
+
+LFS64(fopen);
diff --git a/src/stdio/fprintf.c b/src/stdio/fprintf.c
new file mode 100644
index 00000000..a220cc10
--- /dev/null
+++ b/src/stdio/fprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int fprintf(FILE *f, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vfprintf(f, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/fputc.c b/src/stdio/fputc.c
new file mode 100644
index 00000000..ec859385
--- /dev/null
+++ b/src/stdio/fputc.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+int fputc(int c, FILE *f)
+{
+	FLOCK(f);
+	if (c != f->lbf && f->wpos + 1 < f->wend) *f->wpos++ = c;
+	else c = __overflow(f, c);
+	FUNLOCK(f);
+	return c;
+}
diff --git a/src/stdio/fputs.c b/src/stdio/fputs.c
new file mode 100644
index 00000000..e6bdb204
--- /dev/null
+++ b/src/stdio/fputs.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+int fputs(const char *s, FILE *f)
+{
+	size_t l = strlen(s);
+	if (!l) return 0;
+	return (int)fwrite(s, l, 1, f) - 1;
+}
+
+weak_alias(fputs, fputs_unlocked);
diff --git a/src/stdio/fputwc.c b/src/stdio/fputwc.c
new file mode 100644
index 00000000..b48bb74d
--- /dev/null
+++ b/src/stdio/fputwc.c
@@ -0,0 +1,33 @@
+#include "stdio_impl.h"
+
+wint_t __fputwc_unlocked(wchar_t c, FILE *f)
+{
+	char mbc[MB_LEN_MAX];
+	int l;
+
+	f->mode |= f->mode+1;
+
+	if (isascii(c)) {
+		if (c != f->lbf && f->wpos + 1 < f->wend) *f->wpos++ = c;
+		else c = __overflow(f, c);
+	} else if (f->wpos + MB_LEN_MAX < f->wend) {
+		l = wctomb(f->wpos, c);
+		if (l < 0) c = WEOF;
+		else f->wpos += l;
+	} else {
+		l = wctomb(mbc, c);
+		if (l < 0 || __fwritex(mbc, l, f) < l) c = WEOF;
+	}
+	return c;
+}
+
+wint_t fputwc(wchar_t c, FILE *f)
+{
+	FLOCK(f);
+	c = __fputwc_unlocked(c, f);
+	FUNLOCK(f);
+	return 0;
+}
+
+weak_alias(__fputwc_unlocked, fputwc_unlocked);
+weak_alias(__fputwc_unlocked, putwc_unlocked);
diff --git a/src/stdio/fputws.c b/src/stdio/fputws.c
new file mode 100644
index 00000000..9057853b
--- /dev/null
+++ b/src/stdio/fputws.c
@@ -0,0 +1,23 @@
+#include "stdio_impl.h"
+
+int fputws(const wchar_t *ws, FILE *f)
+{
+	unsigned char buf[BUFSIZ];
+	size_t l=0;
+
+	FLOCK(f);
+
+	f->mode |= f->mode+1;
+
+	while (ws && (l = wcsrtombs(buf, (void*)&ws, sizeof buf, 0))+1 > 1)
+		if (__fwritex(buf, l, f) < l) {
+			FUNLOCK(f);
+			return -1;
+		}
+
+	FUNLOCK(f);
+
+	return l; /* 0 or -1 */
+}
+
+weak_alias(fputws, fputws_unlocked);
diff --git a/src/stdio/fread.c b/src/stdio/fread.c
new file mode 100644
index 00000000..0fa0b2aa
--- /dev/null
+++ b/src/stdio/fread.c
@@ -0,0 +1,49 @@
+#include "stdio_impl.h"
+
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+size_t fread(void *destv, size_t size, size_t nmemb, FILE *f)
+{
+	unsigned char *dest = destv;
+	size_t len = size*nmemb, l = len, k;
+
+	/* Never touch the file if length is zero.. */
+	if (!l) return 0;
+
+	FLOCK(f);
+
+	for (;;) {
+		/* First exhaust the buffer. */
+		k = MIN(f->rend - f->rpos, l);
+		memcpy(dest, f->rpos, k);
+		f->rpos += k;
+		dest += k;
+		l -= k;
+
+		/* Stop on EOF or errors */
+		if (f->flags & (F_EOF|F_ERR|F_NORD)) goto eof;
+
+		/* Done? Or going unbuffered? */
+		if (!l || l > f->buf_size/2) break;
+
+		/* Otherwise, refill & read thru buffer. */
+		__underflow(f);
+	}
+
+	/* Read the remainder directly */
+	for (; l; l-=k, dest+=k) {
+		k = f->read(f, dest, l);
+		if (k+1<=1) {
+			f->flags |= F_EOF | (F_ERR & k);
+			goto eof;
+		}
+	}
+
+	FUNLOCK(f);
+	return nmemb;
+eof:
+	FUNLOCK(f);
+	return (len-l)/size;
+}
+
+weak_alias(fread, fread_unlocked);
diff --git a/src/stdio/freopen.c b/src/stdio/freopen.c
new file mode 100644
index 00000000..8d3af9fc
--- /dev/null
+++ b/src/stdio/freopen.c
@@ -0,0 +1,47 @@
+#include "stdio_impl.h"
+
+/* The basic idea of this implementation is to open a new FILE,
+ * hack the necessary parts of the new FILE into the old one, then
+ * close the new FILE. */
+
+/* Locking is not necessary because, in the event of failure, the stream
+ * passed to freopen is invalid as soon as freopen is called. */
+
+FILE *freopen(const char *filename, const char *mode, FILE *f)
+{
+	int fl;
+	FILE *f2;
+
+	fflush(f);
+
+	if (!filename) {
+		f2 = fopen("/dev/null", mode);
+		if (!f2) goto fail;
+		fl = __syscall_fcntl(f2->fd, F_GETFL, 0);
+		if (fl < 0 || __syscall_fcntl(f->fd, F_SETFL, fl) < 0)
+			goto fail2;
+	} else {
+		f2 = fopen(filename, mode);
+		if (!f2) goto fail;
+		if (__syscall_dup2(f2->fd, f->fd) < 0)
+			goto fail2;
+	}
+
+	f->flags = (f->flags & F_PERM) | f2->flags;
+	f->read = f2->read;
+	f->write = f2->write;
+	f->seek = f2->seek;
+	f->close = f2->close;
+	f->flush = f2->flush;
+
+	fclose(f2);
+	return f;
+
+fail2:
+	fclose(f2);
+fail:
+	fclose(f);
+	return NULL;
+}
+
+LFS64(freopen);
diff --git a/src/stdio/fscanf.c b/src/stdio/fscanf.c
new file mode 100644
index 00000000..51fc9b30
--- /dev/null
+++ b/src/stdio/fscanf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int fscanf(FILE *f, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vfscanf(f, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/fseek.c b/src/stdio/fseek.c
new file mode 100644
index 00000000..bfaad375
--- /dev/null
+++ b/src/stdio/fseek.c
@@ -0,0 +1,38 @@
+#include "stdio_impl.h"
+
+int __fseeko_unlocked(FILE *f, off_t off, int whence)
+{
+	/* Adjust relative offset for unread data in buffer, if any. */
+	if (whence == SEEK_CUR) off -= f->rend - f->rpos;
+
+	/* If writing, flush output. */
+	if (f->wpos > f->buf && __oflow(f)) return -1;
+
+	/* Perform the underlying seek operation. */
+	if (f->seek(f, off, whence) < 0) return -1;
+
+	/* If seek succeeded, file is seekable and we discard read buffer. */
+	f->rpos = f->rend = f->rstop = 0;
+	f->flags &= ~F_EOF;
+	
+	FUNLOCK(f);	
+	return 0;
+}
+
+int __fseeko(FILE *f, off_t off, int whence)
+{
+	int result;
+	FLOCK(f);
+	result = __fseeko_unlocked(f, off, whence);
+	FUNLOCK(f);
+	return result;
+}
+
+int fseek(FILE *f, long off, int whence)
+{
+	return __fseeko(f, off, whence);
+}
+
+weak_alias(__fseeko, fseeko);
+
+LFS64(fseeko);
diff --git a/src/stdio/fsetpos.c b/src/stdio/fsetpos.c
new file mode 100644
index 00000000..5d76c8cd
--- /dev/null
+++ b/src/stdio/fsetpos.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+int fsetpos(FILE *f, const fpos_t *pos)
+{
+	return __fseeko(f, *(const off_t *)pos, SEEK_SET);
+}
+
+LFS64(fsetpos);
diff --git a/src/stdio/ftell.c b/src/stdio/ftell.c
new file mode 100644
index 00000000..aa1f5381
--- /dev/null
+++ b/src/stdio/ftell.c
@@ -0,0 +1,35 @@
+#include "stdio_impl.h"
+
+off_t __ftello_unlocked(FILE *f)
+{
+	off_t pos = f->seek(f, 0, SEEK_CUR);
+	if (pos < 0) {
+		FUNLOCK(f);
+		return pos;
+	}
+	/* Adjust for data in buffer. */
+	return pos - (f->rend - f->rpos) + (f->wpos - f->wbase);
+}
+
+off_t __ftello(FILE *f)
+{
+	off_t pos;
+	FLOCK(f);
+	pos = __ftello_unlocked(f);
+	FUNLOCK(f);
+	return pos;
+}
+
+long ftell(FILE *f)
+{
+	off_t pos = __ftello(f);
+	if (pos > LONG_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return pos;
+}
+
+weak_alias(__ftello, ftello);
+
+LFS64(ftello);
diff --git a/src/stdio/fwide.c b/src/stdio/fwide.c
new file mode 100644
index 00000000..f4da47f6
--- /dev/null
+++ b/src/stdio/fwide.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+#define SH (8*sizeof(int)-1)
+#define NORMALIZE(x) ((x)>>SH | -((-(x))>>SH))
+
+int fwide(FILE *f, int mode)
+{
+	if (!f->mode) f->mode = NORMALIZE(mode);
+	return f->mode;
+}
diff --git a/src/stdio/fwrite.c b/src/stdio/fwrite.c
new file mode 100644
index 00000000..23974fe1
--- /dev/null
+++ b/src/stdio/fwrite.c
@@ -0,0 +1,51 @@
+#include "stdio_impl.h"
+
+size_t __fwritex(const unsigned char *s, size_t l, FILE *f)
+{
+	size_t i = 0;
+	size_t k = f->wend - f->wpos;
+
+	/* Handle line-buffered mode by breaking into 2 parts */
+	if (f->lbf >= 0) {
+		/* Match /^(.*\n|)/ */
+		for (i=l; i && s[i-1] != '\n'; i--);
+		if (i) {
+			f->lbf = EOF;
+			__fwritex(s, i, f);
+			f->lbf = '\n';
+			__oflow(f);
+			return ferror(f) ? 0 : i + __fwritex(s+i, l-i, f);
+		}
+	}
+
+	/* Buffer initial segment */
+	if (k > l) k = l;
+	memcpy(f->wpos, s, k);
+	f->wpos += k;
+	if (f->wpos < f->wend) return l;
+
+	/* If there's work left to do, flush buffer */
+	__oflow(f);
+	if (ferror(f)) return 0;
+
+	/* If the remainder will not fit in buffer, write it directly */
+	if (l - k >= f->wend - f->wpos)
+		return k + f->write(f, s+k, l-k);
+
+	/* Otherwise, buffer the remainder */
+	memcpy(f->wpos, s+k, l-k);
+	f->wpos += l-k;
+	return l;
+}
+
+size_t fwrite(const void *src, size_t size, size_t nmemb, FILE *f)
+{
+	size_t l = size*nmemb;
+	if (!l) return l;
+	FLOCK(f);
+	l = __fwritex(src, l, f);
+	FUNLOCK(f);
+	return l/size;
+}
+
+weak_alias(fwrite, fwrite_unlocked);
diff --git a/src/stdio/fwscanf.c b/src/stdio/fwscanf.c
new file mode 100644
index 00000000..a6892cf6
--- /dev/null
+++ b/src/stdio/fwscanf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int fwscanf(FILE *f, const wchar_t *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vfwscanf(f, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/getc.c b/src/stdio/getc.c
new file mode 100644
index 00000000..b739b0a5
--- /dev/null
+++ b/src/stdio/getc.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int getc(FILE *f)
+{
+	return fgetc(f);
+}
diff --git a/src/stdio/getc_unlocked.c b/src/stdio/getc_unlocked.c
new file mode 100644
index 00000000..629223ea
--- /dev/null
+++ b/src/stdio/getc_unlocked.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+int getc_unlocked(FILE *f)
+{
+	return f->rpos < f->rstop ? *f->rpos++ : __uflow(f);
+}
+
+weak_alias (getc_unlocked, fgetc_unlocked);
diff --git a/src/stdio/getchar.c b/src/stdio/getchar.c
new file mode 100644
index 00000000..c1012658
--- /dev/null
+++ b/src/stdio/getchar.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int getchar(void)
+{
+	return fgetc(stdin);
+}
diff --git a/src/stdio/getchar_unlocked.c b/src/stdio/getchar_unlocked.c
new file mode 100644
index 00000000..299cb958
--- /dev/null
+++ b/src/stdio/getchar_unlocked.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int getchar_unlocked(void)
+{
+	return stdin->rpos < stdin->rstop ? *stdin->rpos++ : __uflow(stdin);
+}
diff --git a/src/stdio/getdelim.c b/src/stdio/getdelim.c
new file mode 100644
index 00000000..f770d20b
--- /dev/null
+++ b/src/stdio/getdelim.c
@@ -0,0 +1,59 @@
+#include "stdio_impl.h"
+
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+ssize_t getdelim(char **s, size_t *n, int delim, FILE *f)
+{
+	char *tmp;
+	unsigned char *z;
+	size_t k;
+	size_t i=0;
+
+	if (!n || !s) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (!*s) *n=0;
+
+	FLOCK(f);
+
+	while (!feof(f)) {
+		z = memchr(f->rpos, delim, f->rend - f->rpos);
+		k = z ? z - f->rpos + 1 : f->rend - f->rpos;
+		if (i+k >= *n) {
+			if (k >= SIZE_MAX-i) goto oom;
+			*n = i+k+1;
+			if (*n < SIZE_MAX/2) *n *= 2;
+			tmp = realloc(*s, *n);
+			if (!tmp) {
+				*n = i+k+1;
+				tmp = realloc(*s, *n);
+				if (!tmp) goto oom;
+			}
+			*s = tmp;
+		}
+		memcpy(*s+i, f->rpos, k);
+		f->rpos += k;
+		i += k;
+		if (z) break;
+		__underflow(f);
+	}
+	(*s)[i] = 0;
+	if (feof(f) || ferror(f)) {
+		FUNLOCK(f);
+		return -1;
+	}
+
+	FUNLOCK(f);
+
+	if (i > SSIZE_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+
+	return i;
+oom:
+	errno = ENOMEM;
+	return -1;
+}
diff --git a/src/stdio/getline.c b/src/stdio/getline.c
new file mode 100644
index 00000000..a3a6651b
--- /dev/null
+++ b/src/stdio/getline.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+ssize_t getline(char **s, size_t *n, FILE *f)
+{
+	return getdelim(s, n, '\n', f);
+}
diff --git a/src/stdio/gets.c b/src/stdio/gets.c
new file mode 100644
index 00000000..24319eb2
--- /dev/null
+++ b/src/stdio/gets.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+char *gets(char *s)
+{
+	char *ret = fgets(s, INT_MAX, stdin);
+	if (ret && s[strlen(s)-1] == '\n') s[strlen(s)-1] = 0;
+	return ret;
+}
diff --git a/src/stdio/getw.c b/src/stdio/getw.c
new file mode 100644
index 00000000..de9e985a
--- /dev/null
+++ b/src/stdio/getw.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int getw(FILE *f)
+{
+	int x;
+	return fread(&x, sizeof x, 1, f) ? x : EOF;
+}
diff --git a/src/stdio/getwc.c b/src/stdio/getwc.c
new file mode 100644
index 00000000..a2818bc4
--- /dev/null
+++ b/src/stdio/getwc.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+wint_t getwc(FILE *f)
+{
+	return fgetwc(f);
+}
diff --git a/src/stdio/getwchar.c b/src/stdio/getwchar.c
new file mode 100644
index 00000000..2295bd40
--- /dev/null
+++ b/src/stdio/getwchar.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+wint_t getwchar(void)
+{
+	return fgetwc(stdin);
+}
+
+weak_alias(getwchar, getwchar_unlocked);
diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c
new file mode 100644
index 00000000..c2fe7a24
--- /dev/null
+++ b/src/stdio/pclose.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+int pclose(FILE *f)
+{
+	int status;
+	fclose(f);
+	while (waitpid(f->pipe_pid, &status, 0) == -1)
+		if (errno != EINTR) return -1;
+	return status;
+}
diff --git a/src/stdio/perror.c b/src/stdio/perror.c
new file mode 100644
index 00000000..e4637c8a
--- /dev/null
+++ b/src/stdio/perror.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "stdio_impl.h"
+
+void perror(const char *msg)
+{
+#if 1
+	if (msg) fprintf(stderr, "%s: %m\n", msg, strerror(errno));
+	else fprintf(stderr, "%m\n");
+#else
+	FILE *f = stderr;
+	char *errstr = strerror(errno);
+
+	FLOCK(f);
+	
+	if (msg) {
+		__fwritex(msg, strlen(msg), f);
+		__putc_unlocked(':', f);
+		__putc_unlocked(' ', f);
+	}
+	__fwritex(errstr, strlen(errstr), f);
+	__putc_unlocked('\n', f);
+
+	FUNLOCK(f);
+#endif
+}
diff --git a/src/stdio/popen.c b/src/stdio/popen.c
new file mode 100644
index 00000000..1d33e9d6
--- /dev/null
+++ b/src/stdio/popen.c
@@ -0,0 +1,43 @@
+#include "stdio_impl.h"
+
+FILE *popen(const char *cmd, const char *mode)
+{
+	int p[2];
+	int op;
+	pid_t pid;
+	FILE *f;
+	const char *modes = "rw", *mi = strchr(modes, *mode);
+
+	if (mi) {
+		op = mi-modes;
+	} else {
+		errno = EINVAL;
+		return 0;
+	}
+	
+	if (pipe(p)) return NULL;
+	f = fdopen(p[op], mode);
+	if (!f) {
+		close(p[0]);
+		close(p[1]);
+		return NULL;
+	}
+	
+	pid = fork();
+	switch (pid) {
+	case -1:
+		fclose(f);
+		close(p[0]);
+		close(p[1]);
+		return NULL;
+	case 0:
+		dup2(p[1-op], 1-op);
+		close(p[0]);
+		close(p[1]);
+		execl("/bin/sh", "sh", "-c", cmd, (char *)0);
+		_exit(127);
+	}
+	close(p[1-op]);
+	f->pipe_pid = pid;
+	return f;
+}
diff --git a/src/stdio/printf.c b/src/stdio/printf.c
new file mode 100644
index 00000000..efeb8b33
--- /dev/null
+++ b/src/stdio/printf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int printf(const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vprintf(fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/putc.c b/src/stdio/putc.c
new file mode 100644
index 00000000..3c9dc11e
--- /dev/null
+++ b/src/stdio/putc.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+int putc(int c, FILE *f)
+{
+	return fputc(c, f);
+}
+
+weak_alias(putc, _IO_putc);
diff --git a/src/stdio/putc_unlocked.c b/src/stdio/putc_unlocked.c
new file mode 100644
index 00000000..f01da717
--- /dev/null
+++ b/src/stdio/putc_unlocked.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+int putc_unlocked(int c, FILE *f)
+{
+	return f->wpos < f->wstop ? (*f->wpos++ = c) : __overflow(f, c);
+}
+
+weak_alias(putc_unlocked, fputc_unlocked);
diff --git a/src/stdio/putchar.c b/src/stdio/putchar.c
new file mode 100644
index 00000000..945636d5
--- /dev/null
+++ b/src/stdio/putchar.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int putchar(int c)
+{
+	return fputc(c, stdout);
+}
diff --git a/src/stdio/putchar_unlocked.c b/src/stdio/putchar_unlocked.c
new file mode 100644
index 00000000..72d47d15
--- /dev/null
+++ b/src/stdio/putchar_unlocked.c
@@ -0,0 +1,7 @@
+#include "stdio_impl.h"
+
+int putchar_unlocked(int c)
+{
+	return stdout->wpos < stdout->wstop ?
+		(*stdout->wpos++ = c) : __overflow(stdout, c);
+}
diff --git a/src/stdio/puts.c b/src/stdio/puts.c
new file mode 100644
index 00000000..eb70efdc
--- /dev/null
+++ b/src/stdio/puts.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+int puts(const char *s)
+{
+	return -(fputs(s, stdout) < 0 || putchar('\n') < 0);
+}
diff --git a/src/stdio/putw.c b/src/stdio/putw.c
new file mode 100644
index 00000000..137832ee
--- /dev/null
+++ b/src/stdio/putw.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int putw(int x, FILE *f)
+{
+	return fwrite(&x, sizeof x, 1, f) ? x : EOF;
+}
diff --git a/src/stdio/putwc.c b/src/stdio/putwc.c
new file mode 100644
index 00000000..80b54a47
--- /dev/null
+++ b/src/stdio/putwc.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+wint_t putwc(wchar_t c, FILE *f)
+{
+	return fputwc(c, f);
+}
diff --git a/src/stdio/putwchar.c b/src/stdio/putwchar.c
new file mode 100644
index 00000000..3aacc1cf
--- /dev/null
+++ b/src/stdio/putwchar.c
@@ -0,0 +1,8 @@
+#include "stdio_impl.h"
+
+wint_t putwchar(wchar_t c)
+{
+	return fputwc(c, stdout);
+}
+
+weak_alias(putwchar, putwchar_unlocked);
diff --git a/src/stdio/remove.c b/src/stdio/remove.c
new file mode 100644
index 00000000..8e338277
--- /dev/null
+++ b/src/stdio/remove.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "syscall.h"
+
+int remove(const char *path)
+{
+	return __syscall_unlink(path);
+}
diff --git a/src/stdio/rename.c b/src/stdio/rename.c
new file mode 100644
index 00000000..4eced08a
--- /dev/null
+++ b/src/stdio/rename.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "syscall.h"
+
+int rename(const char *old, const char *new)
+{
+	return syscall2(__NR_rename, (long)old, (long)new);
+}
diff --git a/src/stdio/rewind.c b/src/stdio/rewind.c
new file mode 100644
index 00000000..7944b434
--- /dev/null
+++ b/src/stdio/rewind.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void rewind(FILE *f)
+{
+	fseek(f, 0, SEEK_SET);
+}
diff --git a/src/stdio/scanf.c b/src/stdio/scanf.c
new file mode 100644
index 00000000..a04a4402
--- /dev/null
+++ b/src/stdio/scanf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int scanf(const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vscanf(fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/setbuf.c b/src/stdio/setbuf.c
new file mode 100644
index 00000000..205afcfe
--- /dev/null
+++ b/src/stdio/setbuf.c
@@ -0,0 +1,6 @@
+#include "stdio_impl.h"
+
+void setbuf(FILE *f, char *buf)
+{
+	setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
diff --git a/src/stdio/setvbuf.c b/src/stdio/setvbuf.c
new file mode 100644
index 00000000..2985d3f1
--- /dev/null
+++ b/src/stdio/setvbuf.c
@@ -0,0 +1,22 @@
+#include "stdio_impl.h"
+
+/* This function makes no attempt to protect the user from his/her own
+ * stupidity. If called any time but when then ISO C standard specifically
+ * allows it, all hell can and will break loose, especially with threads!
+ *
+ * This implementation ignores all arguments except the buffering type,
+ * and uses the existing buffer allocated alongside the FILE object.
+ * In the case of stderr where the preexisting buffer is length 1, it
+ * is not possible to set line buffering or full buffering. */
+
+int setvbuf(FILE *f, char *buf, int type, size_t size)
+{
+	f->lbf = EOF;
+
+	if (type == _IONBF)
+		f->buf_size = 1;
+	else if (type == _IOLBF)
+		f->lbf = '\n';
+
+	return 0;
+}
diff --git a/src/stdio/snprintf.c b/src/stdio/snprintf.c
new file mode 100644
index 00000000..4071c2f6
--- /dev/null
+++ b/src/stdio/snprintf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int snprintf(char *s, size_t n, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vsnprintf(s, n, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+
diff --git a/src/stdio/sprintf.c b/src/stdio/sprintf.c
new file mode 100644
index 00000000..6b225409
--- /dev/null
+++ b/src/stdio/sprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int sprintf(char *s, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vsprintf(s, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/sscanf.c b/src/stdio/sscanf.c
new file mode 100644
index 00000000..a1cea699
--- /dev/null
+++ b/src/stdio/sscanf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int sscanf(const char *s, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vsscanf(s, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/stderr.c b/src/stdio/stderr.c
new file mode 100644
index 00000000..4a79d4e7
--- /dev/null
+++ b/src/stdio/stderr.c
@@ -0,0 +1,13 @@
+#include "stdio_impl.h"
+
+static unsigned char buf[1+UNGET];
+static FILE f = {
+	.buf = buf+UNGET,
+	.buf_size = 1,
+	.fd = 2,
+	.flags = F_PERM | F_NORD,
+	.write = __stdio_write,
+	.seek = __stdio_seek,
+	.close = __stdio_close,
+};
+FILE *const stderr = &f;
diff --git a/src/stdio/stdin.c b/src/stdio/stdin.c
new file mode 100644
index 00000000..51c99232
--- /dev/null
+++ b/src/stdio/stdin.c
@@ -0,0 +1,13 @@
+#include "stdio_impl.h"
+
+static unsigned char buf[BUFSIZ+UNGET];
+static FILE f = {
+	.buf = buf+UNGET,
+	.buf_size = sizeof buf-UNGET,
+	.fd = 0,
+	.flags = F_PERM | F_NOWR,
+	.read = __stdio_read,
+	.seek = __stdio_seek,
+	.close = __stdio_close,
+};
+FILE *const stdin = &f;
diff --git a/src/stdio/stdout.c b/src/stdio/stdout.c
new file mode 100644
index 00000000..bf6eea6c
--- /dev/null
+++ b/src/stdio/stdout.c
@@ -0,0 +1,17 @@
+#include "stdio_impl.h"
+
+static unsigned char buf[BUFSIZ+UNGET];
+static FILE f = {
+	.buf = buf+UNGET,
+	.buf_size = sizeof buf-UNGET,
+	.fd = 1,
+	.flags = F_PERM | F_NORD,
+	.lbf = '\n',
+	.write = __stdio_write,
+	.seek = __stdio_seek,
+	.close = __stdio_close,
+};
+FILE *const stdout = &f;
+
+/* overrides symbol in fflush.c, used for flushing NULL */
+FILE *const __stdout_to_flush = &f;
diff --git a/src/stdio/swscanf.c b/src/stdio/swscanf.c
new file mode 100644
index 00000000..b66ad03e
--- /dev/null
+++ b/src/stdio/swscanf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int swscanf(const wchar_t *s, const wchar_t *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vswscanf(s, fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdio/tempnam.c b/src/stdio/tempnam.c
new file mode 100644
index 00000000..2cbcb864
--- /dev/null
+++ b/src/stdio/tempnam.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include "libc.h"
+
+char *tempnam(const char *dir, const char *pfx)
+{
+	static int lock;
+	static int index;
+	char *s;
+	int pid = getpid();
+	int l;
+
+	if (!dir) dir = P_tmpdir;
+	if (!pfx) pfx = "temp";
+
+	if (access(dir, R_OK|W_OK|X_OK) != 0)
+		return NULL;
+
+	l = strlen(dir) + 1 + strlen(pfx) + 2 + sizeof(int)*3*2 + 1;
+	s = malloc(l);
+	if (!s) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	LOCK(&lock);
+	for (; index < TMP_MAX; index++) {
+		snprintf(s, l, "%s/%s-%d-%d", dir, pfx, pid, index);
+		if (access(s, F_OK) != 0) {
+			UNLOCK(&lock);
+			return s;
+		}
+	}
+	UNLOCK(&lock);
+	free(s);
+	return NULL;	
+}
diff --git a/src/stdio/tmpfile.c b/src/stdio/tmpfile.c
new file mode 100644
index 00000000..185025f1
--- /dev/null
+++ b/src/stdio/tmpfile.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "stdio_impl.h"
+
+FILE *tmpfile(void)
+{
+	char buf[L_tmpnam], *s;
+	int fd;
+	FILE *f;
+	for (;;) {
+		s = tmpnam(buf);
+		if (!s) return NULL;
+		fd = __syscall_open(s, O_RDWR | O_CREAT | O_EXCL, 0600);
+		if (fd >= 0) {
+			f = __fdopen(fd, "w+");
+			remove(s);
+			return f;
+		}
+	}
+}
+
+LFS64(tmpfile);
diff --git a/src/stdio/tmpnam.c b/src/stdio/tmpnam.c
new file mode 100644
index 00000000..14d59220
--- /dev/null
+++ b/src/stdio/tmpnam.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include "libc.h"
+
+char *tmpnam(char *s)
+{
+	static int lock;
+	static int index;
+	static char *s2;
+	int pid = getpid();
+	char *dir = getenv("TMPDIR");
+
+	if (!s) {
+		if (!s2) s2 = malloc(L_tmpnam);
+		s = s2;
+	}
+
+	/* this interface is insecure anyway but at least we can try.. */
+	if (!dir || strlen(dir) > L_tmpnam-32)
+		dir = P_tmpdir;
+
+	if (access(dir, R_OK|W_OK|X_OK) != 0)
+		return NULL;
+
+	LOCK(&lock);
+	for (index++; index < TMP_MAX; index++) {
+		snprintf(s, L_tmpnam, "%s/temp%d-%d", dir, pid, index);
+		if (access(s, F_OK) != 0) {
+			UNLOCK(&lock);
+			return s;
+		}
+	}
+	UNLOCK(&lock);
+	return NULL;
+}
diff --git a/src/stdio/ungetc.c b/src/stdio/ungetc.c
new file mode 100644
index 00000000..07181684
--- /dev/null
+++ b/src/stdio/ungetc.c
@@ -0,0 +1,33 @@
+#include "stdio_impl.h"
+
+int ungetc(int c, FILE *f)
+{
+	if (c == EOF) return c;
+
+	FLOCK(f);
+
+	/* Fail if unreadable or writing and unable to flush */
+	if ((f->flags & (F_ERR|F_NORD)) || (f->wpos && __oflow(f))) {
+		FUNLOCK(f);
+		return EOF;
+	}
+
+	/* Clear write mode */
+	f->wbase = f->wpos = f->wstop = f->wend = 0;
+
+	/* Put the file in read mode */
+	if (!f->rpos) f->rpos = f->rend = f->buf;
+
+	/* If unget buffer is already full, fail. */
+	if (f->rpos <= f->buf - UNGET) {
+		FUNLOCK(f);
+		return EOF;
+	}
+
+	/* Put a byte back into the buffer */
+	*--f->rpos = c;
+	f->flags &= ~F_EOF;
+
+	FUNLOCK(f);
+	return c;
+}
diff --git a/src/stdio/ungetwc.c b/src/stdio/ungetwc.c
new file mode 100644
index 00000000..f7cde2e0
--- /dev/null
+++ b/src/stdio/ungetwc.c
@@ -0,0 +1,45 @@
+#include "stdio_impl.h"
+
+wint_t ungetwc(wint_t c, FILE *f)
+{
+	unsigned char mbc[MB_LEN_MAX];
+	int l=1;
+
+	if (c == WEOF) return c;
+
+	/* Try conversion early so we can fail without locking if invalid */
+	if (!isascii(c) && (l = wctomb(mbc, c)) < 0)
+		return WEOF;
+
+	FLOCK(f);
+
+	f->mode |= f->mode+1;
+
+	/* Fail if unreadable or writing and unable to flush */
+	if ((f->flags & (F_ERR|F_NORD)) || (f->wpos && __oflow(f))) {
+		FUNLOCK(f);
+		return EOF;
+	}
+
+	/* Clear write mode */
+	f->wpos = f->wstop = f->wend = 0;
+
+	/* Put the file in read mode */
+	if (!f->rpos) f->rpos = f->rend = f->buf;
+
+	/* If unget buffer is nonempty, fail. */
+	if (f->rpos < f->buf) {
+		FUNLOCK(f);
+		return WEOF;
+	}
+
+	/* Put character back into the buffer */
+	if (isascii(c)) *--f->rpos = c;
+	else memcpy(f->rpos -= l, mbc, l);
+
+	/* Clear EOF */
+	f->flags &= ~F_EOF;
+
+	FUNLOCK(f);
+	return c;
+}
diff --git a/src/stdio/vasprintf.c b/src/stdio/vasprintf.c
new file mode 100644
index 00000000..f2bbc7aa
--- /dev/null
+++ b/src/stdio/vasprintf.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define GUESS 240U
+
+int vasprintf(char **s, const char *fmt, va_list ap)
+{
+	va_list ap2;
+	char *a;
+	int l=GUESS;
+
+	if (!(a=malloc(GUESS))) return -1;
+
+	va_copy(ap2, ap);
+	l=vsnprintf(a, GUESS, fmt, ap2);
+	va_end(ap2);
+
+	if (l<GUESS) {
+		char *b = realloc(a, l+1U);
+		*s = b ? b : a;
+		return l;
+	}
+	free(a);
+	if (l<0 || !(*s=malloc(l+1U))) return -1;
+	return vsnprintf(*s, l+1U, fmt, ap);
+}
diff --git a/src/stdio/vdprintf.c b/src/stdio/vdprintf.c
new file mode 100644
index 00000000..bfb1b0a9
--- /dev/null
+++ b/src/stdio/vdprintf.c
@@ -0,0 +1,14 @@
+#include "stdio_impl.h"
+
+int vdprintf(int fd, const char *fmt, va_list ap)
+{
+	int r;
+	char buf[BUFSIZ];
+	FILE f = {
+		.fd = fd, .lbf = EOF, .write = __stdio_write,
+		.buf = buf+UNGET, .buf_size = sizeof buf - UNGET
+	};
+	r = vfprintf(&f, fmt, ap);
+	__oflow(&f);
+	return r;
+}
diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
new file mode 100644
index 00000000..5e19acc5
--- /dev/null
+++ b/src/stdio/vfprintf.c
@@ -0,0 +1,640 @@
+#include "stdio_impl.h"
+
+/* Some useful macros */
+
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#define CONCAT2(x,y) x ## y
+#define CONCAT(x,y) CONCAT2(x,y)
+
+/* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+
+#define ALT_FORM   (1U<<'#'-' ')
+#define ZERO_PAD   (1U<<'0'-' ')
+#define LEFT_ADJ   (1U<<'-'-' ')
+#define PAD_POS    (1U<<' '-' ')
+#define MARK_POS   (1U<<'+'-' ')
+#define GROUPED    (1U<<'\''-' ')
+
+#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
+
+#if UINT_MAX == ULONG_MAX
+#define LONG_IS_INT
+#endif
+
+#if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX
+#define ODD_TYPES
+#endif
+
+/* State machine to accept length modifiers + conversion specifiers.
+ * Result is 0 on failure, or an argument type to pop on success. */
+
+enum {
+	BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
+	ZTPRE, JPRE,
+	STOP,
+	PTR, INT, UINT, ULLONG,
+#ifndef LONG_IS_INT
+	LONG, ULONG,
+#else
+#define LONG INT
+#define ULONG UINT
+#endif
+	SHORT, USHORT, CHAR, UCHAR,
+#ifdef ODD_TYPES
+	LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
+#else
+#define LLONG ULLONG
+#define SIZET ULONG
+#define IMAX LLONG
+#define UMAX ULLONG
+#define PDIFF LONG
+#define UIPTR ULONG
+#endif
+	DBL, LDBL,
+	NOARG,
+	MAXSTATE
+};
+
+#define S(x) [(x)-'A']
+
+static const unsigned char states[]['z'-'A'+1] = {
+	{ /* 0: bare types */
+		S('d') = INT, S('i') = INT,
+		S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
+		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
+		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
+		S('c') = CHAR, S('C') = INT,
+		S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
+		S('m') = NOARG,
+		S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
+		S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
+	}, { /* 1: l-prefixed */
+		S('d') = LONG, S('i') = LONG,
+		S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
+		S('c') = INT, S('s') = PTR, S('n') = PTR,
+		S('l') = LLPRE,
+	}, { /* 2: ll-prefixed */
+		S('d') = LLONG, S('i') = LLONG,
+		S('o') = ULLONG, S('u') = ULLONG,
+		S('x') = ULLONG, S('X') = ULLONG,
+		S('n') = PTR,
+	}, { /* 3: h-prefixed */
+		S('d') = SHORT, S('i') = SHORT,
+		S('o') = USHORT, S('u') = USHORT,
+		S('x') = USHORT, S('X') = USHORT,
+		S('n') = PTR,
+		S('h') = HHPRE,
+	}, { /* 4: hh-prefixed */
+		S('d') = CHAR, S('i') = CHAR,
+		S('o') = UCHAR, S('u') = UCHAR,
+		S('x') = UCHAR, S('X') = UCHAR,
+		S('n') = PTR,
+	}, { /* 5: L-prefixed */
+		S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
+		S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
+		S('n') = PTR,
+	}, { /* 6: z- or t-prefixed (assumed to be same size) */
+		S('d') = PDIFF, S('i') = PDIFF,
+		S('o') = SIZET, S('u') = SIZET,
+		S('x') = SIZET, S('X') = SIZET,
+		S('n') = PTR,
+	}, { /* 7: j-prefixed */
+		S('d') = IMAX, S('i') = IMAX,
+		S('o') = UMAX, S('u') = UMAX,
+		S('x') = UMAX, S('X') = UMAX,
+		S('n') = PTR,
+	}
+};
+
+#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
+
+union arg
+{
+	uintmax_t i;
+	long double f;
+	void *p;
+};
+
+static void pop_arg(union arg *arg, int type, va_list *ap)
+{
+	/* Give the compiler a hint for optimizing the switch. */
+	if ((unsigned)type > MAXSTATE) return;
+	switch (type) {
+	       case PTR:	arg->p = va_arg(*ap, void *);
+	break; case INT:	arg->i = va_arg(*ap, int);
+	break; case UINT:	arg->i = va_arg(*ap, unsigned int);
+#ifndef LONG_IS_INT
+	break; case LONG:	arg->i = va_arg(*ap, long);
+	break; case ULONG:	arg->i = va_arg(*ap, unsigned long);
+#endif
+	break; case ULLONG:	arg->i = va_arg(*ap, unsigned long long);
+	break; case SHORT:	arg->i = (short)va_arg(*ap, int);
+	break; case USHORT:	arg->i = (unsigned short)va_arg(*ap, int);
+	break; case CHAR:	arg->i = (signed char)va_arg(*ap, int);
+	break; case UCHAR:	arg->i = (unsigned char)va_arg(*ap, int);
+#ifdef ODD_TYPES
+	break; case LLONG:	arg->i = va_arg(*ap, long long);
+	break; case SIZET:	arg->i = va_arg(*ap, size_t);
+	break; case IMAX:	arg->i = va_arg(*ap, intmax_t);
+	break; case UMAX:	arg->i = va_arg(*ap, uintmax_t);
+	break; case PDIFF:	arg->i = va_arg(*ap, ptrdiff_t);
+	break; case UIPTR:	arg->i = (uintptr_t)va_arg(*ap, void *);
+#endif
+	break; case DBL:	arg->f = va_arg(*ap, double);
+	break; case LDBL:	arg->f = va_arg(*ap, long double);
+	}
+}
+
+static void out(FILE *f, const char *s, size_t l)
+{
+	__fwritex(s, l, f);
+}
+
+static void pad(FILE *f, char c, int w, int l, int fl)
+{
+	char pad[256];
+	if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
+	l = w - l;
+	memset(pad, c, l>sizeof pad ? sizeof pad : l);
+	for (; l >= sizeof pad; l -= sizeof pad)
+		out(f, pad, sizeof pad);
+	out(f, pad, l);
+}
+
+static const char xdigits[16] = {
+	"0123456789ABCDEF"
+};
+
+static char *fmt_x(uintmax_t x, char *s, int lower)
+{
+	for (; x; x>>=4) *--s = xdigits[(x&15)]|lower;
+	return s;
+}
+
+static char *fmt_o(uintmax_t x, char *s)
+{
+	for (; x; x>>=3) *--s = '0' + (x&7);
+	return s;
+}
+
+static char *fmt_u(uintmax_t x, char *s)
+{
+	unsigned long y;
+	for (   ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
+	for (y=x;           y; y/=10) *--s = '0' + y%10;
+	return s;
+}
+
+static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
+{
+	uint32_t big[(LDBL_MAX_EXP+LDBL_MANT_DIG)/9+1];
+	uint32_t *a, *d, *r, *z;
+	int e2=0, e, i, j, l;
+	char buf[9+LDBL_MANT_DIG/4], *s;
+	const char *prefix="-+ ";
+	int pl;
+	char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
+
+	pl=1;
+	if (y<0 || 1/y<0) {
+		y=-y;
+	} else if (fl & MARK_POS) {
+		prefix++;
+	} else if (fl & PAD_POS) {
+		prefix+=2;
+	} else pl=0;
+
+	if (!isfinite(y)) {
+		char *s = (t&32)?"inf":"INF";
+		if (y!=y) s=(t&32)?"nan":"NAN", pl=0;
+		pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
+		out(f, prefix, pl);
+		out(f, s, 3);
+		pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
+		return MAX(w, 3+pl);
+	}
+
+	y = frexpl(y, &e2) * 2;
+	if (y) e2--;
+
+	if ((t|32)=='a') {
+		long double round = 8.0;
+		int re;
+
+		if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
+		else re=LDBL_MANT_DIG/4-1-p;
+
+		if (re) {
+			if (pl && *prefix=='-') y=-y;
+			while (re--) round*=16;
+			y+=round;
+			y-=round;
+			if (y<0) y=-y;
+		}
+
+		estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
+		if (estr==ebuf) *--estr='0';
+		*--estr = (e2<0 ? '-' : '+');
+		*--estr = t+('p'-'a');
+
+		s=buf;
+		*s++='0';
+		*s++=t+('x'-'a');
+		do {
+			int x=y;
+			*s++=xdigits[x]|(t&32);
+			y=16*(y-x);
+			if (s-buf==3 && (y||p>0||(fl&ALT_FORM))) *s++='.';
+		} while (y);
+
+		if (p<0) p = s-buf-4;
+		l = 1 + p + (p || (fl&ALT_FORM)) + ebuf-estr;
+
+		pad(f, ' ', w, pl+l, fl);
+		out(f, prefix, pl);
+		pad(f, '0', w, pl+l, fl^ZERO_PAD);
+		out(f, buf, s-buf);
+		pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
+		out(f, estr, ebuf-estr);
+		pad(f, '0', w, pl+l, fl^LEFT_ADJ);
+		return MAX(w, pl+l);
+	}
+	if (p<0) p=6;
+
+	y *= 0x1p28; e2-=28;
+
+	if (e2<0) a=r=z=big;
+	else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+
+	do {
+		*z = y;
+		y = 1000000000*(y-*z++);
+	} while (y);
+
+	while (e2>0) {
+		uint32_t carry=0;
+		int sh=MIN(29,e2);
+		for (d=z-1; d>=a; d--) {
+			uint64_t x = ((uint64_t)*d<<sh)+carry;
+			*d = x % 1000000000;
+			carry = x / 1000000000;
+		}
+		if (!z[-1] && z>a) z--;
+		if (carry) *--a = carry;
+		e2-=sh;
+	}
+	while (e2<0) {
+		uint32_t carry=0, *z2;
+		int sh=MIN(9,-e2);
+		for (d=a; d<z; d++) {
+			uint32_t rm = *d & (1<<sh)-1;
+			*d = (*d>>sh) + carry;
+			carry = (1000000000>>sh) * rm;
+		}
+		if (!*a) a++;
+		if (carry) *z++ = carry;
+		/* Avoid (slow!) computation past requested precision */
+		z2 = ((t|32)=='f' ? r : a) + 2 + p/9;
+		z = MIN(z, z2);
+		e2+=sh;
+	}
+
+	if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+	else e=0;
+
+	/* Perform rounding: j is precision after the radix (possibly neg) */
+	j = p - ((t|32)!='f')*e - ((t|32)=='g');
+	if (j < 9*(z-r-1)) {
+		uint32_t x;
+		/* We avoid C's broken division of negative numbers */
+		d = r + 1 + (j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP;
+		j += 9*LDBL_MAX_EXP;
+		j %= 9;
+		for (i=10, j++; j<9; i*=10, j++);
+		x = *d % i;
+		/* Are there any significant digits past j? */
+		if (x || d+1!=z) {
+			long double round = CONCAT(0x1p,LDBL_MANT_DIG);
+			long double small;
+			if (x<i/2) small=0x01p-1;
+			else if (i==i/2 && d+1==z) small=0x10p-1;
+			else small=0x11p-1;
+			if (pl && *prefix=='-') round*=-1, small*=-1;
+			/* Decide whether to round by probing round+small */
+			if (round+small != round) {
+				*d = *d - x + i;
+				while (*d > 999999999) {
+					*d--=0;
+					(*d)++;
+				}
+				if (d<a) a=d;
+				for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+			}
+		}
+		for (; !z[-1] && z>a; z--);
+	}
+	
+	if ((t|32)=='g') {
+		if (!p) p++;
+		if (p>e && e>=-4) {
+			t--;
+			p-=e+1;
+		} else {
+			t-=2;
+			p--;
+		}
+		if (!(fl&ALT_FORM)) {
+			/* Count trailing zeros in last place */
+			if (z>a) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
+			else j=9;
+			if ((t|32)=='f')
+				p = MIN(p,MAX(0,9*(z-r-1)-j));
+			else
+				p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+		}
+	}
+	l = 1 + p + (p || (fl&ALT_FORM));
+	if ((t|32)=='f') {
+		if (e>0) l+=e;
+	} else {
+		estr=fmt_u(e<0 ? -e : e, ebuf);
+		while(ebuf-estr<2) *--estr='0';
+		*--estr = (e<0 ? '-' : '+');
+		*--estr = t;
+		l += ebuf-estr;
+	}
+
+	pad(f, ' ', w, pl+l, fl);
+	out(f, prefix, pl);
+	pad(f, '0', w, pl+l, fl^ZERO_PAD);
+
+	if ((t|32)=='f') {
+		if (a>r) a=r;
+		for (d=a; d<=r; d++) {
+			char *s = fmt_u(*d, buf+9);
+			if (d!=a) while (s>buf) *--s='0';
+			else if (s==buf+9) *--s='0';
+			out(f, s, buf+9-s);
+		}
+		if (p || (fl&ALT_FORM)) out(f, ".", 1);
+		for (; d<z && p>0; d++, p-=9) {
+			char *s = fmt_u(*d, buf+9);
+			while (s>buf) *--s='0';
+			out(f, s, MIN(9,p));
+		}
+		pad(f, '0', p+9, 9, 0);
+	} else {
+		if (z<=a) z=a+1;
+		for (d=a; d<z && p>=0; d++) {
+			char *s = fmt_u(*d, buf+9);
+			if (s==buf+9) *--s='0';
+			if (d!=a) while (s>buf) *--s='0';
+			else {
+				out(f, s++, 1);
+				if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
+			}
+			out(f, s, MIN(buf+9-s, p));
+			p -= buf+9-s;
+		}
+		pad(f, '0', p+18, 18, 0);
+		out(f, estr, ebuf-estr);
+	}
+
+	pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+
+	return MAX(w, pl+l);
+}
+
+static int getint(char **s) {
+	int i;
+	for (i=0; isdigit(**s); (*s)++)
+		i = 10*i + (**s-'0');
+	return i;
+}
+
+static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
+{
+	char *a, *z, *s=(char *)fmt;
+	unsigned l10n=0, litpct, fl;
+	int w, p;
+	union arg arg;
+	int argpos;
+	unsigned st, ps;
+	int cnt=0, l=0;
+	int i;
+	char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
+	const char *prefix;
+	int t, pl;
+	wchar_t wc[2], *ws;
+	char mb[4];
+
+	for (;;) {
+		/* Update output count, end loop when fmt is exhausted */
+		if (cnt >= 0) {
+			if (l > INT_MAX - cnt) {
+				if (!ferror(f)) errno = EOVERFLOW;
+				cnt = -1;
+			} else cnt += l;
+		}
+		if (!*s) break;
+
+		/* Handle literal text and %% format specifiers */
+		for (a=s; *s && *s!='%'; s++);
+		litpct = strspn(s, "%")/2; /* Optimize %%%% runs */
+		z = s+litpct;
+		s += 2*litpct;
+		l = z-a;
+		if (f) out(f, a, l);
+		if (l) continue;
+
+		if (isdigit(s[1]) && s[2]=='$') {
+			l10n=1;
+			argpos = s[1]-'0';
+			s+=3;
+		} else {
+			argpos = -1;
+			s++;
+		}
+
+		/* Read modifier flags */
+		for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
+			fl |= 1U<<*s-' ';
+
+		/* Read field width */
+		if (*s=='*') {
+			if (isdigit(s[1]) && s[2]=='$') {
+				l10n=1;
+				nl_type[s[1]-'0'] = INT;
+				w = nl_arg[s[1]-'0'].i;
+				s+=3;
+			} else if (!l10n) {
+				w = f ? va_arg(*ap, int) : 0;
+				s++;
+			} else return -1;
+			if (w<0) fl|=LEFT_ADJ, w=-w;
+		} else if ((w=getint(&s))<0) return -1;
+
+		/* Read precision */
+		if (*s=='.' && s[1]=='*') {
+			if (isdigit(s[2]) && s[3]=='$') {
+				nl_type[s[2]-'0'] = INT;
+				p = nl_arg[s[2]-'0'].i;
+				s+=4;
+			} else if (!l10n) {
+				p = f ? va_arg(*ap, int) : 0;
+				s+=2;
+			} else return -1;
+		} else if (*s=='.') {
+			s++;
+			p = getint(&s);
+		} else p = -1;
+
+		/* Format specifier state machine */
+		st=0;
+		do {
+			if (OOB(*s)) return -1;
+			ps=st;
+			st=states[st]S(*s++);
+		} while (st-1<STOP);
+		if (!st) return -1;
+
+		/* Check validity of argument type (nl/normal) */
+		if (st==NOARG) {
+			if (argpos>=0) return -1;
+			else if (!f) continue;
+		} else {
+			if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
+			else if (f) pop_arg(&arg, st, ap);
+			else return 0;
+		}
+
+		if (!f) continue;
+
+		z = buf + sizeof(buf);
+		prefix = "-+   0X0x";
+		pl = 0;
+		t = s[-1];
+
+		/* Transform ls,lc -> S,C */
+		if (ps && (t&15)==3) t&=~32;
+
+		/* - and 0 flags are mutually exclusive */
+		if (fl & LEFT_ADJ) fl &= ~ZERO_PAD;
+
+		switch(t) {
+		case 'n':
+			switch(ps) {
+			case BARE: *(int *)arg.p = l;
+			case LPRE: *(long *)arg.p = l;
+			case LLPRE: *(long long *)arg.p = l;
+			case HPRE: *(unsigned short *)arg.p = l;
+			case HHPRE: *(unsigned char *)arg.p = l;
+			case ZTPRE: *(size_t *)arg.p = l;
+			case JPRE: *(uintmax_t *)arg.p = l;
+			}
+			continue;
+		case 'p':
+			p = MAX(p, 2*sizeof(void*));
+			t = 'x';
+			fl |= ALT_FORM;
+		case 'x': case 'X':
+			a = fmt_x(arg.i, z, t&32);
+			if (fl & ALT_FORM) prefix+=(t>>4), pl=2;
+			if (0) {
+		case 'o':
+			a = fmt_o(arg.i, z);
+			if ((fl&ALT_FORM) && arg.i) prefix+=5, pl=1;
+			} if (0) {
+		case 'd': case 'i':
+			pl=1;
+			if (arg.i>INTMAX_MAX) {
+				arg.i=-arg.i;
+			} else if (fl & MARK_POS) {
+				prefix++;
+			} else if (fl & PAD_POS) {
+				prefix+=2;
+			} else pl=0;
+		case 'u':
+			a = fmt_u(arg.i, z);
+			}
+			if (!arg.i && !p) continue;
+			if (p>=0) fl &= ~ZERO_PAD;
+			p = MAX(p, z-a + !arg.i);
+			break;
+		case 'c':
+			*(a=z-(p=1))=arg.i;
+			fl &= ~ZERO_PAD;
+			break;
+		case 'm':
+			if (1) a = strerror(errno); else
+		case 's':
+			a = arg.p;
+			z = memchr(a, 0, p);
+			if (!z) z=a+p;
+			else p=z-a;
+			fl &= ~ZERO_PAD;
+			break;
+		case 'C':
+			wc[0] = arg.i;
+			wc[1] = 0;
+			arg.p = wc;
+			p = -1;
+		case 'S':
+			ws = arg.p;
+			for (i=0; *ws && (l=wctomb(mb, *ws++))>=0 && l<=0U+p-i; i+=l);
+			if (l<0) return -1;
+			p = i;
+			pad(f, ' ', w, p, fl);
+			ws = arg.p;
+			for (i=0; *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l)
+				out(f, mb, l);
+			pad(f, ' ', w, p, fl^LEFT_ADJ);
+			l = w>p ? w : p;
+			continue;
+		case 'e': case 'f': case 'g': case 'a':
+		case 'E': case 'F': case 'G': case 'A':
+			l = fmt_fp(f, arg.f, w, p, fl, t);
+			continue;
+		}
+
+		if (p < z-a) p = z-a;
+		if (w < pl+p) w = pl+p;
+
+		pad(f, ' ', w, pl+p, fl);
+		out(f, prefix, pl);
+		pad(f, '0', w, pl+p, fl^ZERO_PAD);
+		pad(f, '0', p, z-a, 0);
+		out(f, a, z-a);
+		pad(f, ' ', w, pl+p, fl^LEFT_ADJ);
+
+		l = w;
+	}
+
+	if (f) return cnt;
+	if (!l10n) return 0;
+
+	for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
+		pop_arg(nl_arg+i, nl_type[i], ap);
+	for (; i<=NL_ARGMAX && !nl_type[i]; i++);
+	if (i<=NL_ARGMAX) return -1;
+	return 1;
+}
+
+int vfprintf(FILE *f, const char *fmt, va_list ap)
+{
+	va_list ap2;
+	int nl_type[NL_ARGMAX] = {0};
+	union arg nl_arg[NL_ARGMAX];
+	int ret;
+
+	va_copy(ap2, ap);
+	if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) return -1;
+
+	FLOCK(f);
+	ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
+	FUNLOCK(f);
+	va_end(ap2);
+	return ret;
+}
diff --git a/src/stdio/vfscanf.c b/src/stdio/vfscanf.c
new file mode 100644
index 00000000..69f45081
--- /dev/null
+++ b/src/stdio/vfscanf.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "stdio_impl.h"
+#include "__scanf.h"
+
+static void f_read(rctx_t *r)
+{
+	FILE *f = r->opaque;
+	if ((r->c = __uflow(f)) >= 0) r->l++;
+}
+
+int vfscanf(FILE *f, const char *fmt, va_list ap)
+{
+	size_t l = strlen(fmt), i, result;
+	rctx_t r = { f_read, (void *)f, 0, isspace };
+	wchar_t fmt2[l+1];
+
+	if (l > 0x100000) {
+		errno = ENOMEM;
+		return -1;
+	}
+	for (i=0; i<=l; i++) fmt2[i] = (unsigned char)fmt[i];
+
+	FLOCK(f);
+
+	result = __scanf(&r, fmt2, ap);
+
+	if (r.u && r.c >= 0) {
+		/* This code takes care of the case where the caller performs
+		 * a nonmatching scanf to leave a character in the unscan
+		 * buffer, followed by an unget, followed by a scanf that
+		 * matches zero characters. In this case the final 'unread'
+		 * character must be returned to the unget buffer rather than
+		 * the unscan buffer. */
+		 f->rpos--;
+	}
+
+	FUNLOCK(f);
+	return result;
+}
diff --git a/src/stdio/vfwscanf.c b/src/stdio/vfwscanf.c
new file mode 100644
index 00000000..491c1403
--- /dev/null
+++ b/src/stdio/vfwscanf.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "stdio_impl.h"
+#include "__scanf.h"
+
+static void f_read(rctx_t *r)
+{
+	FILE *f = r->opaque;
+	if ((r->c = fgetwc(f)) >= 0) r->l++;
+}
+
+int vfwscanf(FILE *f, const wchar_t *fmt, va_list ap)
+{
+	rctx_t r = { f_read, (void *)f, 1, iswspace };
+	int result;
+
+	result = __scanf(&r, fmt, ap);
+
+	if (r.u && r.c >= 0) {
+		ungetwc(r.c, f);
+	}
+
+	return result;
+}
diff --git a/src/stdio/vprintf.c b/src/stdio/vprintf.c
new file mode 100644
index 00000000..67b38dac
--- /dev/null
+++ b/src/stdio/vprintf.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int vprintf(const char *fmt, va_list ap)
+{
+	return vfprintf(stdout, fmt, ap);
+}
diff --git a/src/stdio/vscanf.c b/src/stdio/vscanf.c
new file mode 100644
index 00000000..6f55b1c3
--- /dev/null
+++ b/src/stdio/vscanf.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int vscanf(const char *fmt, va_list ap)
+{
+	return vfscanf(stdin, fmt, ap);
+}
diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c
new file mode 100644
index 00000000..bda6b49b
--- /dev/null
+++ b/src/stdio/vsnprintf.c
@@ -0,0 +1,33 @@
+#include "stdio_impl.h"
+
+static size_t sn_write(FILE *f, const unsigned char *s, size_t l)
+{
+	/* pretend to succeed, but discard data */
+	return l;
+}
+
+int vsnprintf(char *s, size_t n, const char *fmt, va_list ap)
+{
+	int r;
+	FILE f;
+	unsigned char buf[1];
+
+	memset(&f, 0, sizeof(FILE));
+	f.lbf = EOF;
+	f.write = sn_write;
+	f.buf_size = 1;
+	f.buf = buf;
+	if (n > INT_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	} else if (n > 0) {
+		if (n > (char *)0+SIZE_MAX-s) n = (char *)0+SIZE_MAX-s;
+		f.wpos = s;
+		f.wbase = f.wend = s+n-1;
+		f.wstop = f.wend - 1;
+	}
+	r = vfprintf(&f, fmt, ap);
+	/* wpos points just after last byte written, or to s+n-1 (wbase) */
+	*f.wpos = 0;
+	return r;
+}
diff --git a/src/stdio/vsprintf.c b/src/stdio/vsprintf.c
new file mode 100644
index 00000000..7836ccb2
--- /dev/null
+++ b/src/stdio/vsprintf.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <limits.h>
+
+int vsprintf(char *s, const char *fmt, va_list ap)
+{
+	return vsnprintf(s, INT_MAX, fmt, ap);
+}
diff --git a/src/stdio/vsscanf.c b/src/stdio/vsscanf.c
new file mode 100644
index 00000000..fd48f709
--- /dev/null
+++ b/src/stdio/vsscanf.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "__scanf.h"
+
+static void s_read(rctx_t *r)
+{
+	unsigned char *s = r->opaque;
+	if (!s[r->l]) r->c = -1;
+	else r->c = s[r->l++];
+}
+
+int vsscanf(const char *s, const char *fmt, va_list ap)
+{
+	size_t l = strlen(fmt), i;
+	wchar_t fmt2[l+1];
+	rctx_t r = { s_read, (void *)s, 0, isspace };
+	for (i=0; i<=l; i++) fmt2[i] = (unsigned char)fmt[i];
+	return __scanf(&r, fmt2, ap);
+}
diff --git a/src/stdio/vswscanf.c b/src/stdio/vswscanf.c
new file mode 100644
index 00000000..2c4ffbe0
--- /dev/null
+++ b/src/stdio/vswscanf.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "__scanf.h"
+
+static void s_read(rctx_t *r)
+{
+	wchar_t *s = r->opaque;
+	if (!s[r->l]) r->c = -1;
+	else r->c = s[r->l++];
+}
+
+int vswscanf(const wchar_t *s, const wchar_t *fmt, va_list ap)
+{
+	rctx_t r = { s_read, (void *)s, 1, iswspace };
+	return __scanf(&r, fmt, ap);
+}
diff --git a/src/stdio/vwscanf.c b/src/stdio/vwscanf.c
new file mode 100644
index 00000000..86da0457
--- /dev/null
+++ b/src/stdio/vwscanf.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int vwscanf(const wchar_t *fmt, va_list ap)
+{
+	return vfwscanf(stdin, fmt, ap);
+}
diff --git a/src/stdio/wscanf.c b/src/stdio/wscanf.c
new file mode 100644
index 00000000..34b58846
--- /dev/null
+++ b/src/stdio/wscanf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+int wscanf(const wchar_t *fmt, ...)
+{
+	int ret;
+	va_list ap;
+	va_start(ap, fmt);
+	ret = vwscanf(fmt, ap);
+	va_end(ap);
+	return ret;
+}
diff --git a/src/stdlib/abs.c b/src/stdlib/abs.c
new file mode 100644
index 00000000..4806d629
--- /dev/null
+++ b/src/stdlib/abs.c
@@ -0,0 +1,4 @@
+int abs(int a)
+{
+	return a>0 ? a : -a;
+}
diff --git a/src/stdlib/atof.c b/src/stdlib/atof.c
new file mode 100644
index 00000000..f7fcd826
--- /dev/null
+++ b/src/stdlib/atof.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+double atof(const char *s)
+{
+	return strtod(s, 0);
+}
diff --git a/src/stdlib/atoi.c b/src/stdlib/atoi.c
new file mode 100644
index 00000000..648b154f
--- /dev/null
+++ b/src/stdlib/atoi.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <ctype.h>
+
+int atoi(const char *s)
+{
+	int n=0, neg=0;
+	while (isspace(*s)) s++;
+	switch (*s) {
+	case '-': neg=1;
+	case '+': s++;
+	}
+	while (isdigit(*s))
+		n = 10*n + *s++ - '0';
+	return neg ? -n : n;
+}
diff --git a/src/stdlib/atol.c b/src/stdlib/atol.c
new file mode 100644
index 00000000..9c91bba9
--- /dev/null
+++ b/src/stdlib/atol.c
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include <ctype.h>
+
+long atol(const char *s)
+{
+	long n=0;
+	int neg=0;
+	while (isspace(*s)) s++;
+	switch (*s) {
+	case '-': neg=1;
+	case '+': s++;
+	}
+	while (isdigit(*s))
+		n = 10*n + *s++ - '0';
+	return neg ? -n : n;
+}
diff --git a/src/stdlib/atoll.c b/src/stdlib/atoll.c
new file mode 100644
index 00000000..0e03e0a1
--- /dev/null
+++ b/src/stdlib/atoll.c
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include <ctype.h>
+
+long long atoll(const char *s)
+{
+	long long n=0;
+	int neg=0;
+	while (isspace(*s)) s++;
+	switch (*s) {
+	case '-': neg=1;
+	case '+': s++;
+	}
+	while (isdigit(*s))
+		n = 10*n + *s++ - '0';
+	return neg ? -n : n;
+}
diff --git a/src/stdlib/bsearch.c b/src/stdlib/bsearch.c
new file mode 100644
index 00000000..61d89367
--- /dev/null
+++ b/src/stdlib/bsearch.c
@@ -0,0 +1,20 @@
+#include <stdlib.h>
+
+void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
+{
+	void *try;
+	int sign;
+	while (nel > 0) {
+		try = (char *)base + width*(nel/2);
+		sign = cmp(key, try);
+		if (!sign) return try;
+		else if (nel == 1) break;
+		else if (sign < 0)
+			nel /= 2;
+		else {
+			base = try;
+			nel -= nel/2;
+		}
+	}
+	return NULL;
+}
diff --git a/src/stdlib/div.c b/src/stdlib/div.c
new file mode 100644
index 00000000..e42c1f14
--- /dev/null
+++ b/src/stdlib/div.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+div_t div(int num, int den)
+{
+	return (div_t){ num/den, num%den };
+}
diff --git a/src/stdlib/frexp.c b/src/stdlib/frexp.c
new file mode 100644
index 00000000..ae82cb30
--- /dev/null
+++ b/src/stdlib/frexp.c
@@ -0,0 +1,23 @@
+#include <math.h>
+#include <inttypes.h>
+
+double frexp(double x, int *e)
+{
+	union { double d; uint64_t i; } y = { x };
+	int ee = y.i>>52 & 0x7ff;
+
+	if (!ee) {
+		if (x) {
+			x = frexp(x*0x1p64, e);
+			*e -= 64;
+		} else *e = 0;
+		return x;
+	} else if (ee == 0x7ff) {
+		return x;
+	}
+
+	*e = ee - 0x3fe;
+	y.i &= 0x800fffffffffffffull;
+	y.i |= 0x3fe0000000000000ull;
+	return y.d;
+}
diff --git a/src/stdlib/frexpf.c b/src/stdlib/frexpf.c
new file mode 100644
index 00000000..ee5e910a
--- /dev/null
+++ b/src/stdlib/frexpf.c
@@ -0,0 +1,23 @@
+#include <math.h>
+#include <inttypes.h>
+
+float frexpf(float x, int *e)
+{
+	union { float f; uint32_t i; } y = { x };
+	int ee = y.i>>23 & 0xff;
+
+	if (!ee) {
+		if (x) {
+			x = frexpf(x*0x1p64, e);
+			*e -= 64;
+		} else *e = 0;
+		return x;
+	} else if (ee == 0xff) {
+		return x;
+	}
+
+	*e = ee - 0x7e;
+	y.i &= 0x807ffffful;
+	y.i |= 0x3f000000ul;
+	return y.f;
+}
diff --git a/src/stdlib/frexpl.c b/src/stdlib/frexpl.c
new file mode 100644
index 00000000..ecfff007
--- /dev/null
+++ b/src/stdlib/frexpl.c
@@ -0,0 +1,25 @@
+#include <math.h>
+#include <inttypes.h>
+
+/* This version is for 80-bit little endian long double */
+
+long double frexpl(long double x, int *e)
+{
+	union { long double ld; uint16_t hw[5]; } y = { x };
+	int ee = y.hw[4]&0x7fff;
+
+	if (!ee) {
+		if (x) {
+			x = frexpl(x*0x1p64, e);
+			*e -= 64;
+		} else *e = 0;
+		return x;
+	} else if (ee == 0x7fff) {
+		return x;
+	}
+
+	*e = ee - 0x3ffe;
+	y.hw[4] &= 0x8000;
+	y.hw[4] |= 0x3ffe;
+	return y.ld;
+}
diff --git a/src/stdlib/imaxabs.c b/src/stdlib/imaxabs.c
new file mode 100644
index 00000000..81001819
--- /dev/null
+++ b/src/stdlib/imaxabs.c
@@ -0,0 +1,6 @@
+#include <inttypes.h>
+
+intmax_t imaxabs(intmax_t a)
+{
+	return a>0 ? a : -a;
+}
diff --git a/src/stdlib/imaxdiv.c b/src/stdlib/imaxdiv.c
new file mode 100644
index 00000000..b2ce821f
--- /dev/null
+++ b/src/stdlib/imaxdiv.c
@@ -0,0 +1,6 @@
+#include <inttypes.h>
+
+imaxdiv_t imaxdiv(intmax_t num, intmax_t den)
+{
+	return (imaxdiv_t){ num/den, num%den };
+}
diff --git a/src/stdlib/labs.c b/src/stdlib/labs.c
new file mode 100644
index 00000000..675b95b8
--- /dev/null
+++ b/src/stdlib/labs.c
@@ -0,0 +1,4 @@
+long labs(long a)
+{
+	return a>0 ? a : -a;
+}
diff --git a/src/stdlib/ldiv.c b/src/stdlib/ldiv.c
new file mode 100644
index 00000000..36eb960b
--- /dev/null
+++ b/src/stdlib/ldiv.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+ldiv_t ldiv(long num, long den)
+{
+	return (ldiv_t){ num/den, num%den };
+}
diff --git a/src/stdlib/llabs.c b/src/stdlib/llabs.c
new file mode 100644
index 00000000..bec4a03d
--- /dev/null
+++ b/src/stdlib/llabs.c
@@ -0,0 +1,4 @@
+long long llabs(long long a)
+{
+	return a>0 ? a : -a;
+}
diff --git a/src/stdlib/lldiv.c b/src/stdlib/lldiv.c
new file mode 100644
index 00000000..7aaf7a0e
--- /dev/null
+++ b/src/stdlib/lldiv.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+lldiv_t lldiv(long long num, long long den)
+{
+	return (lldiv_t){ num/den, num%den };
+}
diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
new file mode 100644
index 00000000..f5bf3d02
--- /dev/null
+++ b/src/stdlib/qsort.c
@@ -0,0 +1,50 @@
+#include <stdlib.h>
+#include <string.h>
+
+/* A simple heap sort implementation.. only in-place O(nlogn) sort I know. */
+
+#define MIN(a, b) ((a)<(b) ? (a) : (b))
+
+static void swap(char *a, char *b, size_t len)
+{
+	char tmp[256];
+	size_t l;
+	while (len) {
+		l = MIN(sizeof tmp, len);
+		memcpy(tmp, a, l);
+		memcpy(a, b, l);
+		memcpy(b, tmp, l);
+		a += l;
+		b += l;
+		len -= l;
+	}
+}
+
+static void sift(char *base, size_t root, size_t nel, size_t width, int (*cmp)(const void *, const void *))
+{
+	size_t max;
+
+	while (2*root <= nel) {
+		max = 2*root;
+		if (max < nel && cmp(base+max*width, base+(max+1)*width) < 0)
+			max++;
+		if (cmp(base+root*width, base+max*width) < 0) {
+			swap(base+root*width, base+max*width, width);
+			root = max;
+		} else break;
+	}
+}
+
+void qsort(void *_base, size_t nel, size_t width, int (*cmp)(const void *, const void *))
+{
+	char *base = _base;
+	size_t i;
+
+	if (!nel) return;
+	for (i=(nel+1)/2; i; i--)
+		sift(base, i-1, nel-1, width, cmp);
+	for (i=nel-1; i; i--) {
+		swap(base, base+i*width, width);
+		sift(base, 0, i-1, width, cmp);
+	}
+}
diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c
new file mode 100644
index 00000000..388058fe
--- /dev/null
+++ b/src/stdlib/strtod.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+double strtod(const char *s, char **p)
+{
+	return strtold(s, p);
+}
diff --git a/src/stdlib/strtof.c b/src/stdlib/strtof.c
new file mode 100644
index 00000000..07b32df4
--- /dev/null
+++ b/src/stdlib/strtof.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+float strtof(const char *s, char **p)
+{
+	return strtold(s, p);
+}
diff --git a/src/stdlib/strtoimax.c b/src/stdlib/strtoimax.c
new file mode 100644
index 00000000..19691091
--- /dev/null
+++ b/src/stdlib/strtoimax.c
@@ -0,0 +1,25 @@
+#include <inttypes.h>
+#include <errno.h>
+#include <ctype.h>
+
+intmax_t strtoimax(const char *s1, char **p, int base)
+{
+	const unsigned char *s = s1;
+	int sign = 0;
+	uintmax_t x;
+
+	/* Initial whitespace */
+	for (; isspace(*s); s++);
+
+	/* Optional sign */
+	if (*s == '-') sign = *s++;
+	else if (*s == '+') s++;
+
+	x = strtoumax(s, p, base);
+	if (x > INTMAX_MAX) {
+		if (!sign || -x != INTMAX_MIN)
+			errno = ERANGE;
+		return sign ? INTMAX_MIN : INTMAX_MAX;
+	}
+	return sign ? -x : x;
+}
diff --git a/src/stdlib/strtol.c b/src/stdlib/strtol.c
new file mode 100644
index 00000000..ace820af
--- /dev/null
+++ b/src/stdlib/strtol.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+long strtol(const char *s, char **p, int base)
+{
+	intmax_t x = strtoimax(s, p, base);
+	if (x > LONG_MAX) {
+		errno = ERANGE;
+		return LONG_MAX;
+	} else if (x < LONG_MIN) {
+		errno = ERANGE;
+		return LONG_MIN;
+	}
+	return x;
+}
diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c
new file mode 100644
index 00000000..54f80469
--- /dev/null
+++ b/src/stdlib/strtold.c
@@ -0,0 +1,93 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+long double strtold(const char *s1, char **p)
+{
+	const unsigned char *s = s1;
+	long double x = 0;
+	long double frac;
+	int sign = 0;
+	int nonzero = 0;
+	int radix = '.';
+	long e;
+
+	if (!p) p = (char **)&s1;
+
+	/* Initial whitespace */
+	for (; isspace(*s); s++);
+
+	/* Optional sign */
+	if (*s == '-') sign = *s++;
+	else if (*s == '+') s++;
+
+	/* Handle infinities and NaNs. */
+	if ((s[0]|32)=='i' && (s[1]|32)=='n' && (s[2]|32)=='f') {
+		*p = (char *)s + 3;
+		return sign ? -1.0/0.0 : 1.0/0.0;
+	} else if ((s[0]|32)=='n' && (s[1]|32)=='a' && (s[2]|32)=='n') {
+		*p = (char *)s + 3;
+		return 0.0/0.0;
+	}
+
+	/* Possible hex float */
+	if (s[0]=='0' && (s[1]|32)=='x') {
+		/* Mantissa must be non-degenerate */
+		if (!isxdigit(s[2]) && (s[2]!=radix || !isxdigit(s[3]))) {
+			/* Decimal float 0, 'x' extraneous */
+			*p = (char *)++s;
+			return 0;
+		}
+		/* We have a real hex float */
+		s += 2;
+		for (; isxdigit(*s); s++) {
+			x = 16*x + (isdigit(*s)?*s-'0':(*s|32)-'a');
+			if (*s!='0') nonzero=1;
+		}
+		if (*s == radix) {
+			frac = 1.0/16.0;
+			for (s++; isxdigit(*s); s++) {
+				x += frac * (isdigit(*s)?*s-'0':(*s|32)-'a');
+				frac *= 1.0/16.0;
+				if (*s!='0') nonzero=1;
+			}
+		}
+		if ((*s|32) == 'p') {
+			e = strtol(s+1, (void *)&s, 10);
+			for (; e>0; e--) x *= 2.0;
+			for (; e<0; e++) x *= 0.5;
+		}
+		if ((nonzero && !x) || !(1.0/x))
+			errno = ERANGE;
+		*p = (char *)s;
+		return sign ? -x : x;
+	}
+
+	/* Mantissa must be non-degenerate */
+	if (!isdigit(s[0]) && (s[0]!=radix || !isdigit(s[1]))) {
+		*p = (char *)s1;
+		return 0;
+	}
+
+	for (; isdigit(*s); s++) {
+		x = 10*x + *s-'0';
+		if (*s!='0') nonzero=1;
+	}
+	if (*s == radix) {
+		frac = 10.0;
+		for (s++; isdigit(*s); s++) {
+			x += (*s-'0') / frac;
+			frac *= 10.0;
+			if (*s!='0') nonzero=1;
+		}
+	}
+	if ((*s|32)=='e') {
+		e = strtol(++s, (void *)&s, 10);
+		for (; e>0; e--) x *= 10.0;
+		for (; e<0; e++) x /= 10.0;
+	}
+	if ((nonzero && !x) || !(1.0/x))
+		errno = ERANGE;
+	*p = (char*)s;
+	return sign ? -x : x;
+}
diff --git a/src/stdlib/strtoll.c b/src/stdlib/strtoll.c
new file mode 100644
index 00000000..9ab66fd9
--- /dev/null
+++ b/src/stdlib/strtoll.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+long long strtoll(const char *s, char **p, int base)
+{
+	intmax_t x = strtoimax(s, p, base);
+	if (x > LLONG_MAX) {
+		errno = ERANGE;
+		return LLONG_MAX;
+	} else if (x < LLONG_MIN) {
+		errno = ERANGE;
+		return LLONG_MIN;
+	}
+	return x;
+}
diff --git a/src/stdlib/strtoul.c b/src/stdlib/strtoul.c
new file mode 100644
index 00000000..951d5e8c
--- /dev/null
+++ b/src/stdlib/strtoul.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+unsigned long strtoul(const char *s, char **p, int base)
+{
+	uintmax_t x = strtoumax(s, p, base);
+	if (x > ULONG_MAX) {
+		errno = ERANGE;
+		return ULONG_MAX;
+	}
+	return x;
+}
diff --git a/src/stdlib/strtoull.c b/src/stdlib/strtoull.c
new file mode 100644
index 00000000..20aa7bde
--- /dev/null
+++ b/src/stdlib/strtoull.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+unsigned long long strtoull(const char *s, char **p, int base)
+{
+	uintmax_t x = strtoumax(s, p, base);
+	if (x > ULLONG_MAX) {
+		errno = ERANGE;
+		return ULLONG_MAX;
+	}
+	return x;
+}
diff --git a/src/stdlib/strtoumax.c b/src/stdlib/strtoumax.c
new file mode 100644
index 00000000..a529f6e8
--- /dev/null
+++ b/src/stdlib/strtoumax.c
@@ -0,0 +1,123 @@
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+
+/* Lookup table for digit values. -1==255>=36 -> invalid */
+static const unsigned char digits[] = {
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
+-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
+-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+};
+
+uintmax_t strtoumax(const char *s1, char **p, int base)
+{
+	const unsigned char *s = s1;
+	size_t x1, z1;
+	uintmax_t x, z=0;
+	int sign = 0;
+	int shift;
+
+	if (!p) p = (char **)&s1;
+
+	/* Initial whitespace */
+	for (; isspace(*s); s++);
+
+	/* Optional sign */
+	if (*s == '-') sign = *s++;
+	else if (*s == '+') s++;
+
+	/* Default base 8, 10, or 16 depending on prefix */
+	if (base == 0) {
+		if (s[0] == '0') {
+			if ((s[1]|32) == 'x') base = 16;
+			else base = 8;
+		} else {
+			base = 10;
+		}
+	}
+
+	if ((unsigned)base-2 > 36-2 || digits[*s]>=base) {
+		*p = (char *)s1;
+		errno = EINVAL;
+		return 0;
+	}
+
+	/* Main loops. Only use big types if we have to. */
+	if (base == 10) {
+		for (x1=0; isdigit(*s) && x1<=SIZE_MAX/10-10; s++)
+			x1 = 10*x1 + *s-'0';
+		for (x=x1; isdigit(*s) && x<=UINTMAX_MAX/10-10; s++)
+			x = 10*x + *s-'0';
+		if (isdigit(*s)) {
+			if (isdigit(s[1]) || 10*x>UINTMAX_MAX-(*s-'0'))
+				goto overflow;
+			x = 10*x + *s-'0';
+		}
+	} else if (!(base & base/2)) {
+		if (base == 16) {
+			if (s[0]=='0' && (s[1]|32)=='x' && digits[s[2]]<16)
+				s+=2;
+			shift=4;
+			z1 = SIZE_MAX/16;
+			z = UINTMAX_MAX/16;
+		} else if (base == 8) {
+			shift=3;
+			z1 = SIZE_MAX/8;
+			z = UINTMAX_MAX/8;
+		} else if (base == 2) {
+			shift=1;
+			z1 = SIZE_MAX/2;
+			z = UINTMAX_MAX/2;
+		} else if (base == 4) {
+			shift=2;
+			z1 = SIZE_MAX/4;
+			z = UINTMAX_MAX/4;
+		} else /* if (base == 32) */ {
+			shift=5;
+			z1 = SIZE_MAX/32;
+			z = UINTMAX_MAX/32;
+		}
+		for (x1=0; digits[*s]<base && x1<=z1; s++)
+			x1 = (x1<<shift) + digits[*s];
+		for (x=x1; digits[*s]<base && x<=z; s++)
+			x = (x<<shift) + digits[*s];
+		if (digits[*s] < base) goto overflow;
+	} else {
+		z1 = SIZE_MAX/base-base;
+		for (x1=0; digits[*s]<base && x1<=z1; s++)
+			x1 = x1*base + digits[*s];
+		if (digits[*s]<base)
+			z = UINTMAX_MAX/base-base;
+		for (x=x1; digits[*s]<base && x<=z; s++)
+			x = x*base + digits[*s];
+		if (digits[*s] < base) {
+			if (digits[s[1]]<base || x*base>UINTMAX_MAX-digits[*s])
+				goto overflow;
+			x = x*base + digits[*s];
+		}
+	}
+
+	*p = (char *)s;
+	return sign ? -x : x;
+
+overflow:
+	for (; digits[*s] < base; s++);
+	*p = (char *)s;
+	errno = ERANGE;
+	return UINTMAX_MAX;
+}
diff --git a/src/stdlib/wcstoimax.c b/src/stdlib/wcstoimax.c
new file mode 100644
index 00000000..861fcb54
--- /dev/null
+++ b/src/stdlib/wcstoimax.c
@@ -0,0 +1,24 @@
+#include <wchar.h>
+#include <inttypes.h>
+#include <errno.h>
+
+intmax_t wcstoimax(const wchar_t *s, wchar_t **p, int base)
+{
+	int sign = 0;
+	uintmax_t x;
+
+	/* Initial whitespace */
+	for (; iswspace(*s); s++);
+
+	/* Optional sign */
+	if (*s == '-') sign = *s++;
+	else if (*s == '+') s++;
+
+	x = wcstoumax(s, p, base);
+	if (x > INTMAX_MAX) {
+		if (!sign || -x != INTMAX_MIN)
+			errno = ERANGE;
+		return sign ? INTMAX_MIN : INTMAX_MAX;
+	}
+	return sign ? -x : x;
+}
diff --git a/src/stdlib/wcstol.c b/src/stdlib/wcstol.c
new file mode 100644
index 00000000..aad62e5b
--- /dev/null
+++ b/src/stdlib/wcstol.c
@@ -0,0 +1,18 @@
+#include <wchar.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+long wcstol(const wchar_t *s, wchar_t **p, int base)
+{
+	intmax_t x = wcstoimax(s, p, base);
+	if (x > LONG_MAX) {
+		errno = ERANGE;
+		return LONG_MAX;
+	} else if (x < LONG_MIN) {
+		errno = ERANGE;
+		return LONG_MIN;
+	}
+	return x;
+}
diff --git a/src/stdlib/wcstoll.c b/src/stdlib/wcstoll.c
new file mode 100644
index 00000000..ddfea74b
--- /dev/null
+++ b/src/stdlib/wcstoll.c
@@ -0,0 +1,18 @@
+#include <wchar.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+long long wcstoll(const wchar_t *s, wchar_t **p, int base)
+{
+	intmax_t x = wcstoimax(s, p, base);
+	if (x > LLONG_MAX) {
+		errno = ERANGE;
+		return LLONG_MAX;
+	} else if (x < LLONG_MIN) {
+		errno = ERANGE;
+		return LLONG_MIN;
+	}
+	return x;
+}
diff --git a/src/stdlib/wcstoul.c b/src/stdlib/wcstoul.c
new file mode 100644
index 00000000..e39faafe
--- /dev/null
+++ b/src/stdlib/wcstoul.c
@@ -0,0 +1,15 @@
+#include <wchar.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+unsigned long wcstoul(const wchar_t *s, wchar_t **p, int base)
+{
+	uintmax_t x = wcstoumax(s, p, base);
+	if (x > ULONG_MAX) {
+		errno = ERANGE;
+		return ULONG_MAX;
+	}
+	return x;
+}
diff --git a/src/stdlib/wcstoull.c b/src/stdlib/wcstoull.c
new file mode 100644
index 00000000..e324dfb2
--- /dev/null
+++ b/src/stdlib/wcstoull.c
@@ -0,0 +1,15 @@
+#include <wchar.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+
+unsigned long long wcstoull(const wchar_t *s, wchar_t **p, int base)
+{
+	uintmax_t x = wcstoumax(s, p, base);
+	if (x > ULLONG_MAX) {
+		errno = ERANGE;
+		return ULLONG_MAX;
+	}
+	return x;
+}
diff --git a/src/stdlib/wcstoumax.c b/src/stdlib/wcstoumax.c
new file mode 100644
index 00000000..a8f4680f
--- /dev/null
+++ b/src/stdlib/wcstoumax.c
@@ -0,0 +1,47 @@
+#include <wchar.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+
+uintmax_t wcstoumax(const wchar_t *s, wchar_t **p, int base)
+{
+	/* Large enough for largest value in binary */
+	char buf[sizeof(uintmax_t)*8+2];
+	int sign = 0, skipped=0;
+
+	if (!p) p = (wchar_t **)&s;
+
+	if (base && (unsigned)base-2 > 36-2) {
+		*p = (wchar_t *)s;
+		errno = EINVAL;
+		return 0;
+	}
+
+	/* Initial whitespace */
+	for (; iswspace(*s); s++);
+
+	/* Optional sign */
+	if (*s == '-') sign = *s++;
+	else if (*s == '+') s++;
+
+	/* Skip leading zeros but don't allow leading zeros before "0x". */
+	for (; s[0]=='0' && s[1]=='0'; s++) skipped=1;
+	if (skipped && (base==0 || base==16) && (s[1]|32)=='x') {
+		*p = (wchar_t *)(s+1);
+		return 0;
+	}
+
+	/* Convert to normal char string so we can use strtoumax */
+	buf[0] = sign;
+	if (wcstombs(buf+!!sign, s, sizeof buf-1) < 0) return 0;
+	buf[sizeof buf-1]=0;
+
+	/* Compute final position */
+	if (p) {
+		if ((base==0 || base==16) && s[0]=='0' && (s[1]|32)=='x' && iswxdigit(s[2])) s+=2;
+		for(;*s&&((unsigned)*s-'0'<base||((unsigned)*s|32)-'a'<base-10);s++);
+		*p = (wchar_t *)s;
+	}
+
+	return strtoumax(buf, 0, base);
+}
diff --git a/src/string/bcmp.c b/src/string/bcmp.c
new file mode 100644
index 00000000..5d6a388b
--- /dev/null
+++ b/src/string/bcmp.c
@@ -0,0 +1,7 @@
+#include <string.h>
+#include <strings.h>
+
+int bcmp(const void *s1, const void *s2, size_t n)
+{
+	return memcmp(s1, s2, n);
+}
diff --git a/src/string/bcopy.c b/src/string/bcopy.c
new file mode 100644
index 00000000..e76272fc
--- /dev/null
+++ b/src/string/bcopy.c
@@ -0,0 +1,7 @@
+#include <string.h>
+#include <strings.h>
+
+void bcopy(const void *s1, void *s2, size_t n)
+{
+	memmove(s2, s1, n);
+}
diff --git a/src/string/bzero.c b/src/string/bzero.c
new file mode 100644
index 00000000..0f98b4a5
--- /dev/null
+++ b/src/string/bzero.c
@@ -0,0 +1,7 @@
+#include <string.h>
+#include <strings.h>
+
+void bzero(void *s, size_t n)
+{
+	memset(s, 0, n);
+}
diff --git a/src/string/index.c b/src/string/index.c
new file mode 100644
index 00000000..dd611251
--- /dev/null
+++ b/src/string/index.c
@@ -0,0 +1,7 @@
+#include <string.h>
+#include <strings.h>
+
+char *index(const char *s, int c)
+{
+	return strchr(s, c);
+}
diff --git a/src/string/memchr.c b/src/string/memchr.c
new file mode 100644
index 00000000..a0472f78
--- /dev/null
+++ b/src/string/memchr.c
@@ -0,0 +1,24 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+
+#define SS (sizeof(size_t))
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+void *memchr(const void *src, int c, size_t n)
+{
+	const unsigned char *s = src;
+	c = (unsigned char)c;
+	for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--);
+	if (n && *s != c) {
+		const size_t *w;
+		size_t k = ONES * c;
+		for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS);
+		for (s = (const void *)w; n && *s != c; s++, n--);
+	}
+	return n ? (void *)s : 0;
+}
diff --git a/src/string/memcmp.c b/src/string/memcmp.c
new file mode 100644
index 00000000..bdbce9f0
--- /dev/null
+++ b/src/string/memcmp.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+int memcmp(const void *vl, const void *vr, size_t n)
+{
+	const unsigned char *l=vl, *r=vr;
+	for (; n && *l == *r; n--, l++, r++);
+	return n ? *l-*r : 0;
+}
diff --git a/src/string/memcpy.c b/src/string/memcpy.c
new file mode 100644
index 00000000..02cb4694
--- /dev/null
+++ b/src/string/memcpy.c
@@ -0,0 +1,29 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define SS (sizeof(size_t))
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+	unsigned char *d = dest;
+	const unsigned char *s = src;
+
+	if (((uintptr_t)d & ALIGN) != ((uintptr_t)s & ALIGN))
+		goto misaligned;
+
+	for (; ((uintptr_t)d & ALIGN) && n; n--) *d++ = *s++;
+	if (n) {
+		size_t *wd = (void *)d;
+		const size_t *ws = (const void *)s;
+
+		for (; n>=SS; n-=SS) *wd++ = *ws++;
+		d = (void *)wd;
+		s = (const void *)ws;
+misaligned:
+		for (; n; n--) *d++ = *s++;
+	}
+	return dest;
+}
diff --git a/src/string/memmove.c b/src/string/memmove.c
new file mode 100644
index 00000000..22bb4b35
--- /dev/null
+++ b/src/string/memmove.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+	char *d = dest;
+	const char *s = src;
+	if (d==s) return d;
+	if ((size_t)(d-s) < n) {
+		while (n--) d[n] = s[n];
+		return dest;
+	}
+	/* Assumes memcpy is overlap-safe when dest < src */
+	return memcpy(d, s, n);
+}
diff --git a/src/string/mempcpy.c b/src/string/mempcpy.c
new file mode 100644
index 00000000..e54251cd
--- /dev/null
+++ b/src/string/mempcpy.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+void *mempcpy(void *dest, void *src, size_t n)
+{
+	memcpy(dest, src, n);
+	return (char *)dest + n;
+}
diff --git a/src/string/memset.c b/src/string/memset.c
new file mode 100644
index 00000000..20e47c45
--- /dev/null
+++ b/src/string/memset.c
@@ -0,0 +1,21 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+
+#define SS (sizeof(size_t))
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+
+void *memset(void *dest, int c, size_t n)
+{
+	unsigned char *s = dest;
+	c = (unsigned char)c;
+	for (; ((uintptr_t)s & ALIGN) && n; n--) *s++ = c;
+	if (n) {
+		size_t *w, k = ONES * c;
+		for (w = (void *)s; n>=SS; n-=SS, w++) *w = k;
+		for (s = (void *)w; n; n--, s++) *s = c;
+	}
+	return dest;
+}
diff --git a/src/string/rindex.c b/src/string/rindex.c
new file mode 100644
index 00000000..17df2bf2
--- /dev/null
+++ b/src/string/rindex.c
@@ -0,0 +1,7 @@
+#include <string.h>
+#include <strings.h>
+
+char *rindex(const char *s, int c)
+{
+	return strrchr(s, c);
+}
diff --git a/src/string/stpcpy.c b/src/string/stpcpy.c
new file mode 100644
index 00000000..10ca4933
--- /dev/null
+++ b/src/string/stpcpy.c
@@ -0,0 +1,29 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include "libc.h"
+
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+char *__stpcpy(char *d, const char *s)
+{
+	size_t *wd;
+	const size_t *ws;
+
+	if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
+		for (; (*d=*s) && ((uintptr_t)s & ALIGN); s++, d++);
+		if (!*s) return d;
+		wd=(void *)d; ws=(const void *)s;
+		for (; !HASZERO(*ws); *wd++ = *ws++);
+		d=(void *)wd; s=(const void *)ws;
+	}
+	for (; (*d=*s); s++, d++);
+
+	return d;
+}
+
+weak_alias(__stpcpy, stpcpy);
diff --git a/src/string/stpncpy.c b/src/string/stpncpy.c
new file mode 100644
index 00000000..a877f5fe
--- /dev/null
+++ b/src/string/stpncpy.c
@@ -0,0 +1,32 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include "libc.h"
+
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+char *__stpncpy(char *d, const char *s, size_t n)
+{
+	size_t *wd;
+	const size_t *ws;
+
+	if (((uintptr_t)s & ALIGN) != ((uintptr_t)d & ALIGN)) {
+		for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++);
+		if (!n || !*s) goto tail;
+		wd=(void *)d; ws=(const void *)s;
+		for (; n>=sizeof(size_t) && !HASZERO(*ws);
+		       n-=sizeof(size_t), ws++, *wd++) *wd = *ws;
+		d=(void *)wd; s=(const void *)ws;
+	}
+	for (; n && (*d=*s); n--, s++, d++);
+tail:
+	memset(d, 0, n);
+	return d;
+}
+
+weak_alias(__stpncpy, stpncpy);
+
diff --git a/src/string/strcasecmp.c b/src/string/strcasecmp.c
new file mode 100644
index 00000000..dd879052
--- /dev/null
+++ b/src/string/strcasecmp.c
@@ -0,0 +1,9 @@
+#include <strings.h>
+#include <ctype.h>
+
+int strcasecmp(const char *_l, const char *_r)
+{
+	const unsigned char *l=_l, *r=_r;
+	for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++);
+	return tolower(*l) - tolower(*r);
+}
diff --git a/src/string/strcasestr.c b/src/string/strcasestr.c
new file mode 100644
index 00000000..f1cb0e84
--- /dev/null
+++ b/src/string/strcasestr.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+char *strcasestr(const char *h, const char *n)
+{
+	//FIXME!
+	return strstr(h, n);
+}
diff --git a/src/string/strcat.c b/src/string/strcat.c
new file mode 100644
index 00000000..29fdb611
--- /dev/null
+++ b/src/string/strcat.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+char *strcat(char *dest, const char *src)
+{
+	strcpy(dest + strlen(dest), src);
+	return dest;
+}
diff --git a/src/string/strchr.c b/src/string/strchr.c
new file mode 100644
index 00000000..e606f4fe
--- /dev/null
+++ b/src/string/strchr.c
@@ -0,0 +1,23 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+char *strchr(const char *s, int c)
+{
+	c = (char)c;
+	if (!c) return (char *)s + strlen(s);
+	for (; ((uintptr_t)s & ALIGN) && *s && *s != c; s++);
+	if (*s && *s != c) {
+		const size_t *w;
+		size_t k = ONES * c;
+		for (w = (const void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
+		for (s = (const void *)w; *s && *s != c; s++);
+	}
+	return *s ? (char *)s : 0;
+}
diff --git a/src/string/strchrnul.c b/src/string/strchrnul.c
new file mode 100644
index 00000000..5e0c1a1a
--- /dev/null
+++ b/src/string/strchrnul.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+char *strchrnul(const char *s, int c)
+{
+	char *p = strchr(s, c);
+	return p ? p : (char *)s + strlen(s);
+}
diff --git a/src/string/strcmp.c b/src/string/strcmp.c
new file mode 100644
index 00000000..91eb7404
--- /dev/null
+++ b/src/string/strcmp.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+int strcmp(const char *l, const char *r)
+{
+	for (; *l==*r && *l && *r; l++, r++);
+	return *(unsigned char *)l - *(unsigned char *)r;
+}
diff --git a/src/string/strcpy.c b/src/string/strcpy.c
new file mode 100644
index 00000000..7675e9ce
--- /dev/null
+++ b/src/string/strcpy.c
@@ -0,0 +1,16 @@
+#include <string.h>
+
+char *__stpcpy(char *, const char *);
+
+char *strcpy(char *dest, const char *src)
+{
+#if 1
+	__stpcpy(dest, src);
+	return dest;
+#else
+	const unsigned char *s = src;
+	unsigned char *d = dest;
+	while ((*d++ = *s++));
+	return dest;
+#endif
+}
diff --git a/src/string/strcspn.c b/src/string/strcspn.c
new file mode 100644
index 00000000..439b7be4
--- /dev/null
+++ b/src/string/strcspn.c
@@ -0,0 +1,20 @@
+#include <string.h>
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+size_t strcspn(const char *_s, const char *_c)
+{
+	const unsigned char *s = _s;
+	const unsigned char *c = _c;
+	const unsigned char *a = s;
+	size_t byteset[32/sizeof(size_t)];
+
+	if (!c[0]) return strlen(s);
+	if (!c[1]) return (s=strchr(s, *c)) ? s-a : strlen(a);
+
+	memset(byteset, 0, sizeof byteset);
+	for (; *c && BITOP(byteset, *c, |=); c++);
+	for (; *s && !BITOP(byteset, *s, &); s++);
+	return s-a;
+}
diff --git a/src/string/strdup.c b/src/string/strdup.c
new file mode 100644
index 00000000..dd5f80c1
--- /dev/null
+++ b/src/string/strdup.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+#include <string.h>
+#include "libc.h"
+
+char *__strdup(const char *s)
+{
+	size_t l = strlen(s);
+	char *d = malloc(l+1);
+	if (!d) return NULL;
+	return memcpy(d, s, l+1);
+}
+
+weak_alias(__strdup, strdup);
diff --git a/src/string/strerror_r.c b/src/string/strerror_r.c
new file mode 100644
index 00000000..6fdd4ce2
--- /dev/null
+++ b/src/string/strerror_r.c
@@ -0,0 +1,11 @@
+#include <string.h>
+#include <errno.h>
+
+int strerror_r(int err, char *buf, size_t buflen)
+{
+	char *msg = strerror(err);
+	if (strlen(msg) >= buflen)
+		return ERANGE;
+	strcpy(buf, msg);
+	return 0;
+}
diff --git a/src/string/strlcat.c b/src/string/strlcat.c
new file mode 100644
index 00000000..a6b94c4c
--- /dev/null
+++ b/src/string/strlcat.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+size_t strlcat(char *d, const char *s, size_t n)
+{
+	size_t l = strnlen(d, n);
+	if (l == n) return l + strlen(s);
+	return l + strlcpy(d+l, s, n-l);
+}
diff --git a/src/string/strlcpy.c b/src/string/strlcpy.c
new file mode 100644
index 00000000..bbebf1db
--- /dev/null
+++ b/src/string/strlcpy.c
@@ -0,0 +1,32 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include "libc.h"
+
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+size_t strlcpy(char *d, const char *s, size_t n)
+{
+	char *d0 = d;
+	size_t *wd;
+	const size_t *ws;
+
+	if (!n--) goto finish;
+	if (((uintptr_t)s & ALIGN) != ((uintptr_t)d & ALIGN)) {
+		for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++);
+		if (n && *s) {
+			wd=(void *)d; ws=(const void *)s;
+			for (; n>=sizeof(size_t) && !HASZERO(*ws);
+			       n-=sizeof(size_t), ws++, *wd++) *wd = *ws;
+			d=(void *)wd; s=(const void *)ws;
+		}
+	}
+	for (; n && (*d=*s); n--, s++, d++);
+	*d = 0;
+finish:
+	return d-d0 + strlen(s);
+}
diff --git a/src/string/strlen.c b/src/string/strlen.c
new file mode 100644
index 00000000..936fb5cf
--- /dev/null
+++ b/src/string/strlen.c
@@ -0,0 +1,21 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+size_t strlen(const char *s)
+{
+	const char *a = s;
+	const size_t *w;
+	for (; ((uintptr_t)s & ALIGN) && *s; s++);
+	if (*s) {
+		for (w = (const void *)s; !HASZERO(*w); w++);
+		for (s = (const void *)w; *s; s++);
+	}
+	return s-a;
+}
diff --git a/src/string/strncasecmp.c b/src/string/strncasecmp.c
new file mode 100644
index 00000000..4f9230e1
--- /dev/null
+++ b/src/string/strncasecmp.c
@@ -0,0 +1,10 @@
+#include <strings.h>
+#include <ctype.h>
+
+int strncasecmp(const char *_l, const char *_r, size_t n)
+{
+	const unsigned char *l=_l, *r=_r;
+	if (!n--) return 0;
+	for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--);
+	return tolower(*l) - tolower(*r);
+}
diff --git a/src/string/strncat.c b/src/string/strncat.c
new file mode 100644
index 00000000..255b7a72
--- /dev/null
+++ b/src/string/strncat.c
@@ -0,0 +1,10 @@
+#include <string.h>
+
+char *strncat(char *d, const char *s, size_t n)
+{
+	char *a = d;
+	d += strlen(d);
+	while (n && (*d++ = *s++)) n--;
+	*d++ = 0;
+	return a;
+}
diff --git a/src/string/strncmp.c b/src/string/strncmp.c
new file mode 100644
index 00000000..52ba0323
--- /dev/null
+++ b/src/string/strncmp.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+int strncmp(const char *_l, const char *_r, size_t n)
+{
+	const unsigned char *l=_l, *r=_r;
+	if (!n--) return 0;
+	for (; *l && *r && n && *l == *r ; l++, r++, n--);
+	return *l - *r;
+}
diff --git a/src/string/strncpy.c b/src/string/strncpy.c
new file mode 100644
index 00000000..c0cd7974
--- /dev/null
+++ b/src/string/strncpy.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+char *__stpncpy(char *, const char *, size_t);
+
+char *strncpy(char *d, const char *s, size_t n)
+{
+	__stpncpy(d, s, n);
+	return d;
+}
diff --git a/src/string/strndup.c b/src/string/strndup.c
new file mode 100644
index 00000000..617d27ba
--- /dev/null
+++ b/src/string/strndup.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <string.h>
+
+char *strndup(const char *s, size_t n)
+{
+	size_t l = strnlen(s, n);
+	char *d = malloc(l+1);
+	if (!d) return NULL;
+	memcpy(d, s, l);
+	d[l] = 0;
+	return d;
+}
diff --git a/src/string/strnlen.c b/src/string/strnlen.c
new file mode 100644
index 00000000..6442eb79
--- /dev/null
+++ b/src/string/strnlen.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+size_t strnlen(const char *s, size_t n)
+{
+	const char *p = memchr(s, 0, n);
+	return p ? p-s : n;
+}
diff --git a/src/string/strpbrk.c b/src/string/strpbrk.c
new file mode 100644
index 00000000..55947c64
--- /dev/null
+++ b/src/string/strpbrk.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+char *strpbrk(const char *s, const char *b)
+{
+	s += strcspn(s, b);
+	return *s ? (char *)s : 0;
+}
diff --git a/src/string/strrchr.c b/src/string/strrchr.c
new file mode 100644
index 00000000..31c8e0b8
--- /dev/null
+++ b/src/string/strrchr.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+char *strrchr(const char *s, int c)
+{
+	const char *p;
+	c = (char)c;
+	for (p=s+strlen(s); p>=s && *p!=c; p--);
+	return p>=s ? (char *)p : 0;
+}
diff --git a/src/string/strsep.c b/src/string/strsep.c
new file mode 100644
index 00000000..1bfe1db1
--- /dev/null
+++ b/src/string/strsep.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+char *strsep(char **str, const char *sep)
+{
+	char *s = *str, *end;
+	if (!s) return NULL;
+	end = s + strcspn(s, sep);
+	if (*end) *end++ = 0;
+	else end = 0;
+	*str = end;
+	return s;
+}
diff --git a/src/string/strsignal.c b/src/string/strsignal.c
new file mode 100644
index 00000000..72fba8d1
--- /dev/null
+++ b/src/string/strsignal.c
@@ -0,0 +1,98 @@
+#include <signal.h>
+
+#if (SIGHUP == 1) && (SIGINT == 2) && (SIGQUIT == 3) && (SIGILL == 4) \
+ && (SIGTRAP == 5) && (SIGABRT == 6) && (SIGBUS == 7) && (SIGFPE == 8) \
+ && (SIGKILL == 9) && (SIGUSR1 == 10) && (SIGSEGV == 11) && (SIGUSR2 == 12) \
+ && (SIGPIPE == 13) && (SIGALRM == 14) && (SIGTERM == 15) && (SIGSTKFLT == 16) \
+ && (SIGCHLD == 17) && (SIGCONT == 18) && (SIGSTOP == 19) && (SIGTSTP == 20) \
+ && (SIGTTIN == 21) && (SIGTTOU == 22) && (SIGURG == 23) && (SIGXCPU == 24) \
+ && (SIGXFSZ == 25) && (SIGVTALRM == 26) && (SIGPROF == 27) && (SIGWINCH == 28) \
+ && (SIGPOLL == 29) && (SIGPWR == 30) && (SIGSYS == 31)
+
+#define sigmap(x) x
+
+#else
+
+static const char map[] = {
+	[SIGHUP]    = 1,
+	[SIGINT]    = 2,
+	[SIGQUIT]   = 3,
+	[SIGILL]    = 4,
+	[SIGTRAP]   = 5,
+	[SIGABRT]   = 6,
+	[SIGBUS]    = 7,
+	[SIGFPE]    = 8,
+	[SIGKILL]   = 9,
+	[SIGUSR1]   = 10,
+	[SIGSEGV]   = 11,
+	[SIGUSR2]   = 12,
+	[SIGPIPE]   = 13,
+	[SIGALRM]   = 14,
+	[SIGTERM]   = 15,
+	[SIGSTKFLT] = 16,
+	[SIGCHLD]   = 17,
+	[SIGCONT]   = 18,
+	[SIGSTOP]   = 19,
+	[SIGTSTP]   = 20,
+	[SIGTTIN]   = 21,
+	[SIGTTOU]   = 22,
+	[SIGURG]    = 23,
+	[SIGXCPU]   = 24,
+	[SIGXFSZ]   = 25,
+	[SIGVTALRM] = 26,
+	[SIGPROF]   = 27,
+	[SIGWINCH]  = 28,
+	[SIGPOLL]   = 29,
+	[SIGPWR]    = 30,
+	[SIGSYS]    = 31
+};
+
+#define sigmap(x) ((unsigned)(x) > sizeof map ? 0 : map[(unsigned)(x)])
+
+#endif
+
+static const char strings[] =
+	"Unknown signal\0"
+	"Hangup\0"
+	"Interrupt\0"
+	"Quit\0"
+	"Illegal instruction\0"
+	"Trace/breakpoint trap\0"
+	"Aborted\0"
+	"Bus error\0"
+	"Floating point exception\0"
+	"Killed\0"
+	"User defined signal 1\0"
+	"Segmentation fault\0"
+	"User defined signal 2\0"
+	"Broken pipe\0"
+	"Alarm clock\0"
+	"Terminated\0"
+	"Stack fault\0"
+	"Child exited\0"
+	"Continued\0"
+	"Stopped (signal)\0"
+	"Stopped\0"
+	"Stopped (tty input)\0"
+	"Stopped (tty output)\0"
+	"Urgent I/O condition\0"
+	"CPU time limit exceeded\0"
+	"File size limit exceeded\0"
+	"Virtual timer expired\0"
+	"Profiling timer expired\0"
+	"Window changed\0"
+	"I/O possible\0"
+	"Power failure\0"
+	"Bad system call";
+
+char *strsignal(int signum)
+{
+	char *s = (char *)strings;
+
+	signum = sigmap(signum);
+	if ((unsigned)signum - 1 > 31) signum = 0;
+
+	for (; signum--; s++) for (; *s; s++);
+
+	return s;
+}
diff --git a/src/string/strspn.c b/src/string/strspn.c
new file mode 100644
index 00000000..59b063e5
--- /dev/null
+++ b/src/string/strspn.c
@@ -0,0 +1,22 @@
+#include <string.h>
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+size_t strspn(const char *_s, const char *_c)
+{
+	const unsigned char *s = _s;
+	const unsigned char *c = _c;
+	const unsigned char *a = s;
+	size_t byteset[32/sizeof(size_t)] = { 0 };
+
+	if (!c[0]) return 0;
+	if (!c[1]) {
+		for (; *s == *c; s++);
+		return s-a;
+	}
+
+	for (; *c && BITOP(byteset, *c, |=); c++);
+	for (; *s && BITOP(byteset, *s, &); s++);
+	return s-a;
+}
diff --git a/src/string/strstr.c b/src/string/strstr.c
new file mode 100644
index 00000000..4d536a73
--- /dev/null
+++ b/src/string/strstr.c
@@ -0,0 +1,166 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+static char *twobyte_strstr(const unsigned char *h, const unsigned char *n)
+{
+	uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
+	for (h++; *h && hw != nw; hw = hw<<8 | *++h);
+	return *h ? (char *)h-1 : 0;
+}
+
+static char *threebyte_strstr(const unsigned char *h, const unsigned char *n)
+{
+	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8;
+	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8;
+	for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8);
+	return *h ? (char *)h-2 : 0;
+}
+
+static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n)
+{
+	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
+	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
+	for (h+=3; *h && hw != nw; hw = hw<<8 | *++h);
+	return *h ? (char *)h-3 : 0;
+}
+
+#if 0
+static char *naive_strstr(const char *h, const char *n)
+{
+	size_t i;
+	for (i=0; n[i] && h[i]; i++)
+	for (   ; n[i] != h[i]; h++, i=0);
+	return n[i] ? 0 : (char *)h;
+}
+#endif
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+static char *twoway_strstr(const unsigned char *h, const unsigned char *n)
+{
+	const unsigned char *z;
+	size_t l, ip, jp, k, p, ms, p0, mem, mem0;
+	size_t byteset[32 / sizeof(size_t)] = { 0 };
+	size_t shift[256];
+
+	/* Computing length of needle and fill shift table */
+	for (l=0; n[l] && h[l]; l++)
+		BITOP(byteset, n[l], |=), shift[n[l]] = l+1;
+	if (n[l]) return 0; /* hit the end of h */
+
+	/* Compute maximal suffix */
+	ip = -1; jp = 0; k = p = 1;
+	while (jp+k<l) {
+		if (n[ip+k] == n[jp+k]) {
+			if (k == p) {
+				jp += p;
+				k = 1;
+			} else k++;
+		} else if (n[ip+k] > n[jp+k]) {
+			jp += k;
+			k = 1;
+			p = jp - ip;
+		} else {
+			ip = jp++;
+			k = p = 1;
+		}
+	}
+	ms = ip;
+	p0 = p;
+
+	/* And with the opposite comparison */
+	ip = -1; jp = 0; k = p = 1;
+	while (jp+k<l) {
+		if (n[ip+k] == n[jp+k]) {
+			if (k == p) {
+				jp += p;
+				k = 1;
+			} else k++;
+		} else if (n[ip+k] < n[jp+k]) {
+			jp += k;
+			k = 1;
+			p = jp - ip;
+		} else {
+			ip = jp++;
+			k = p = 1;
+		}
+	}
+	if (ip+1 > ms+1) ms = ip;
+	else p = p0;
+
+	/* Periodic needle? */
+	if (memcmp(n, n+p, ms+1)) {
+		mem0 = 0;
+		p = MAX(ms, l-ms-1) + 1;
+	} else mem0 = l-p;
+	mem = 0;
+
+	/* Initialize incremental end-of-haystack pointer */
+	z = h;
+
+	/* Search loop */
+	for (;;) {
+		/* Update incremental end-of-haystack pointer */
+		if (z-h < l) {
+			/* Fast estimate for MIN(l,63) */
+			size_t grow = l | 63;
+			const char *z2 = memchr(z, 0, grow);
+			if (z2) {
+				z = z2;
+				if (z-h < l) return 0;
+			} else z += grow;
+		}
+
+		/* Check last byte first; advance by shift on mismatch */
+		if (BITOP(byteset, h[l-1], &)) {
+			k = l-shift[h[l-1]];
+			//printf("adv by %zu (on %c) at [%s] (%zu;l=%zu)\n", k, h[l-1], h, shift[h[l-1]], l);
+			if (k) {
+				if (mem0 && mem && k < p) k = l-p;
+				h += k;
+				mem = 0;
+				continue;
+			}
+		} else {
+			h += l;
+			mem = 0;
+			continue;
+		}
+
+		/* Compare right half */
+		for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
+		if (n[k]) {
+			h += k-ms;
+			mem = 0;
+			continue;
+		}
+		/* Compare left half */
+		for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
+		if (k == mem) return (char *)h;
+		h += p;
+		mem = mem0;
+	}
+}
+
+char *strstr(const char *h, const char *n)
+{
+	/* Return immediately on empty needle */
+	if (!n[0]) return (char *)h;
+
+	/* Use faster algorithms for short needles */
+	h = strchr(h, *n);
+	if (!h || !n[1]) return (char *)h;
+	if (!h[1]) return 0;
+	if (!n[2]) return twobyte_strstr(h, n);
+	if (!h[2]) return 0;
+	if (!n[3]) return threebyte_strstr(h, n);
+	if (!h[3]) return 0;
+	if (!n[4]) return fourbyte_strstr(h, n);
+
+	return twoway_strstr(h, n);
+}
diff --git a/src/string/strtok.c b/src/string/strtok.c
new file mode 100644
index 00000000..1ba221cb
--- /dev/null
+++ b/src/string/strtok.c
@@ -0,0 +1,13 @@
+#include <string.h>
+
+char *strtok(char *s, const char *sep)
+{
+	static char *p;
+	if (!s && !(s = p)) return NULL;
+	s += strspn(s, sep);
+	if (!*s) return p = 0;
+	p = s + strcspn(s, sep);
+	if (*p) *p++ = 0;
+	else p = 0;
+	return s;
+}
diff --git a/src/string/strtok_r.c b/src/string/strtok_r.c
new file mode 100644
index 00000000..c763897a
--- /dev/null
+++ b/src/string/strtok_r.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+char *strtok_r(char *s, const char *sep, char **p)
+{
+	if (!s && !(s = *p)) return NULL;
+	s += strspn(s, sep);
+	if (!*s) return *p = 0;
+	*p = s + strcspn(s, sep);
+	if (**p) *(*p)++ = 0;
+	else *p = 0;
+	return s;
+}
diff --git a/src/string/swab.c b/src/string/swab.c
new file mode 100644
index 00000000..b2132884
--- /dev/null
+++ b/src/string/swab.c
@@ -0,0 +1,13 @@
+#include <unistd.h>
+
+void swab(const void *_src, void *_dest, ssize_t n)
+{
+	const char *src = _src;
+	char *dest = _dest;
+	for (; n>0; n-=2) {
+		dest[0] = src[1];
+		dest[1] = src[0];
+		dest += 2;
+		src += 2;
+	}
+}
diff --git a/src/string/wcscat.c b/src/string/wcscat.c
new file mode 100644
index 00000000..946f16e2
--- /dev/null
+++ b/src/string/wcscat.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+wchar_t *wcscat(wchar_t *dest, const wchar_t *src)
+{
+	wcscpy(dest + wcslen(dest), src);
+	return dest;
+}
diff --git a/src/string/wcschr.c b/src/string/wcschr.c
new file mode 100644
index 00000000..8dfc2f31
--- /dev/null
+++ b/src/string/wcschr.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+wchar_t *wcschr(const wchar_t *s, wchar_t c)
+{
+	if (!c) return (wchar_t *)s + wcslen(s);
+	for (; *s && *s != c; s++);
+	return *s ? (wchar_t *)s : 0;
+}
diff --git a/src/string/wcscmp.c b/src/string/wcscmp.c
new file mode 100644
index 00000000..26eeee70
--- /dev/null
+++ b/src/string/wcscmp.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+int wcscmp(const wchar_t *l, const wchar_t *r)
+{
+	for (; *l==*r && *l && *r; l++, r++);
+	return *l - *r;
+}
diff --git a/src/string/wcscpy.c b/src/string/wcscpy.c
new file mode 100644
index 00000000..e0ac194f
--- /dev/null
+++ b/src/string/wcscpy.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+wchar_t *wcscpy(wchar_t *d, const wchar_t *s)
+{
+	wchar_t *a = d;
+	while ((*d++ = *s++));
+	return a;
+}
diff --git a/src/string/wcscspn.c b/src/string/wcscspn.c
new file mode 100644
index 00000000..c4e52722
--- /dev/null
+++ b/src/string/wcscspn.c
@@ -0,0 +1,10 @@
+#include <wchar.h>
+
+size_t wcscspn(const wchar_t *s, const wchar_t *c)
+{
+	const wchar_t *a;
+	if (!c[0]) return wcslen(s);
+	if (!c[1]) return (s=wcschr(a=s, *c)) ? s-a : wcslen(a);
+	for (a=s; *s && !wcschr(c, *s); s++);
+	return s-a;
+}
diff --git a/src/string/wcslen.c b/src/string/wcslen.c
new file mode 100644
index 00000000..1b7b6655
--- /dev/null
+++ b/src/string/wcslen.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+size_t wcslen(const wchar_t *s)
+{
+	const wchar_t *a;
+	for (a=s; *s; s++);
+	return s-a;
+}
diff --git a/src/string/wcsncat.c b/src/string/wcsncat.c
new file mode 100644
index 00000000..b07abe45
--- /dev/null
+++ b/src/string/wcsncat.c
@@ -0,0 +1,10 @@
+#include <wchar.h>
+
+wchar_t *wcsncat(wchar_t *d, const wchar_t *s, size_t n)
+{
+	wchar_t *a = d;
+	d += wcslen(d);
+	while (n && (*d++ = *s++)) n--;
+	*d++ = 0;
+	return a;
+}
diff --git a/src/string/wcsncmp.c b/src/string/wcsncmp.c
new file mode 100644
index 00000000..1b159f41
--- /dev/null
+++ b/src/string/wcsncmp.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n)
+{
+	for (; n && *l==*r && *l && *r; l++, r++);
+	return n ? *l - *r : 0;
+}
diff --git a/src/string/wcsncpy.c b/src/string/wcsncpy.c
new file mode 100644
index 00000000..0164208d
--- /dev/null
+++ b/src/string/wcsncpy.c
@@ -0,0 +1,9 @@
+#include <wchar.h>
+
+wchar_t *wcsncpy(wchar_t *d, const wchar_t *s, size_t n)
+{
+	wchar_t *a = d;
+	while (n && (*d++ = *s++)) n--;
+	wmemset(d, 0, n);
+	return a;
+}
diff --git a/src/string/wcspbrk.c b/src/string/wcspbrk.c
new file mode 100644
index 00000000..0c72c197
--- /dev/null
+++ b/src/string/wcspbrk.c
@@ -0,0 +1,7 @@
+#include <wchar.h>
+
+wchar_t *wcspbrk(const wchar_t *s, const wchar_t *b)
+{
+	s += wcscspn(s, b);
+	return *s ? (wchar_t *)s : NULL;
+}
diff --git a/src/string/wcsrchr.c b/src/string/wcsrchr.c
new file mode 100644
index 00000000..7503475a
--- /dev/null
+++ b/src/string/wcsrchr.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+wchar_t *wcsrchr(const wchar_t *s, wint_t c)
+{
+	const wchar_t *p;
+	for (p=s+wcslen(s); p>=s && *p!=c; p--);
+	return p>=s ? (wchar_t *)p : 0;
+}
diff --git a/src/string/wcsspn.c b/src/string/wcsspn.c
new file mode 100644
index 00000000..4320d8f6
--- /dev/null
+++ b/src/string/wcsspn.c
@@ -0,0 +1,8 @@
+#include <wchar.h>
+
+size_t wcsspn(const wchar_t *s, const wchar_t *c)
+{
+	const wchar_t *a;
+	for (a=s; *s && wcschr(c, *s); s++);
+	return s-a;
+}
diff --git a/src/string/wcsstr.c b/src/string/wcsstr.c
new file mode 100644
index 00000000..966174f8
--- /dev/null
+++ b/src/string/wcsstr.c
@@ -0,0 +1,117 @@
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+static wchar_t *naive_wcsstr(const wchar_t *h, const wchar_t *n)
+{
+	size_t i;
+	for (i=0; n[i] && h[i]; i++)
+	for (   ; n[i] != h[i]; h++, i=0);
+	return n[i] ? 0 : (wchar_t *)h;
+}
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n)
+{
+	const wchar_t *z;
+	size_t l, ip, jp, k, p, ms, p0, mem, mem0;
+
+	/* Computing length of needle */
+	for (l=0; n[l] && h[l]; l++);
+	if (n[l]) return 0; /* hit the end of h */
+
+	/* Compute maximal suffix */
+	ip = -1; jp = 0; k = p = 1;
+	while (jp+k<l) {
+		if (n[ip+k] == n[jp+k]) {
+			if (k == p) {
+				jp += p;
+				k = 1;
+			} else k++;
+		} else if (n[ip+k] > n[jp+k]) {
+			jp += k;
+			k = 1;
+			p = jp - ip;
+		} else {
+			ip = jp++;
+			k = p = 1;
+		}
+	}
+	ms = ip;
+	p0 = p;
+
+	/* And with the opposite comparison */
+	ip = -1; jp = 0; k = p = 1;
+	while (jp+k<l) {
+		if (n[ip+k] == n[jp+k]) {
+			if (k == p) {
+				jp += p;
+				k = 1;
+			} else k++;
+		} else if (n[ip+k] < n[jp+k]) {
+			jp += k;
+			k = 1;
+			p = jp - ip;
+		} else {
+			ip = jp++;
+			k = p = 1;
+		}
+	}
+	if (ip+1 > ms+1) ms = ip;
+	else p = p0;
+
+	/* Periodic needle? */
+	if (wmemcmp(n, n+p, ms+1)) {
+		mem0 = 0;
+		p = MAX(ms, l-ms-1) + 1;
+	} else mem0 = l-p;
+	mem = 0;
+
+	/* Initialize incremental end-of-haystack pointer */
+	z = h;
+
+	/* Search loop */
+	for (;;) {
+		/* Update incremental end-of-haystack pointer */
+		if (z-h < l) {
+			/* Fast estimate for MIN(l,63) */
+			size_t grow = l | 63;
+			const wchar_t *z2 = wmemchr(z, 0, grow);
+			if (z2) {
+				z = z2;
+				if (z-h < l) return 0;
+			} else z += grow;
+		}
+
+		/* Compare right half */
+		for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
+		if (n[k]) {
+			h += k-ms;
+			mem = 0;
+			continue;
+		}
+		/* Compare left half */
+		for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
+		if (k == mem) return (wchar_t *)h;
+		h += p;
+		mem = mem0;
+	}
+}
+
+wchar_t *wcsstr(const wchar_t *h, const wchar_t *n)
+{
+	/* Return immediately on empty needle or haystack */
+	if (!n[0]) return (wchar_t *)h;
+	if (!h[0]) return 0;
+
+	/* Use faster algorithms for short needles */
+	h = wcschr(h, *n);
+	if (!h || !n[1]) return (wchar_t *)h;
+	if (!h[1]) return 0;
+	if (!n[2] || !n[3] || !n[4]) return naive_wcsstr(h, n);
+
+	return twoway_wcsstr(h, n);
+}
diff --git a/src/string/wcswcs.c b/src/string/wcswcs.c
new file mode 100644
index 00000000..9cfe4ac4
--- /dev/null
+++ b/src/string/wcswcs.c
@@ -0,0 +1,6 @@
+#include <wchar.h>
+
+wchar_t *wcswcs(const wchar_t *haystack, const wchar_t *needle)
+{
+	return wcsstr(haystack, needle);
+}
diff --git a/src/string/wmemchr.c b/src/string/wmemchr.c
new file mode 100644
index 00000000..a3ee0e61
--- /dev/null
+++ b/src/string/wmemchr.c
@@ -0,0 +1,8 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n)
+{
+	for (; n && *s != c; s++);
+	return n ? (wchar_t *)s : 0;
+}
diff --git a/src/string/wmemcmp.c b/src/string/wmemcmp.c
new file mode 100644
index 00000000..6788a383
--- /dev/null
+++ b/src/string/wmemcmp.c
@@ -0,0 +1,8 @@
+#include <string.h>
+#include <wchar.h>
+
+int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)
+{
+	for (; n && *l==*r; n--, l++, r++);
+	return n ? *l-*r : 0;
+}
diff --git a/src/string/wmemcpy.c b/src/string/wmemcpy.c
new file mode 100644
index 00000000..330e37c7
--- /dev/null
+++ b/src/string/wmemcpy.c
@@ -0,0 +1,9 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemcpy(wchar_t *d, const wchar_t *s, size_t n)
+{
+	wchar_t *a = d;
+	while (n--) *d++ = *s++;
+	return a;
+}
diff --git a/src/string/wmemmove.c b/src/string/wmemmove.c
new file mode 100644
index 00000000..49608cae
--- /dev/null
+++ b/src/string/wmemmove.c
@@ -0,0 +1,11 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemmove(wchar_t *d, const wchar_t *s, size_t n)
+{
+	if ((size_t)(d-s) < n) {
+		while (n--) d[n] = s[n];
+		return d;
+	}
+	return wmemcpy(d, s, n);
+}
diff --git a/src/string/wmemset.c b/src/string/wmemset.c
new file mode 100644
index 00000000..1a2a8618
--- /dev/null
+++ b/src/string/wmemset.c
@@ -0,0 +1,9 @@
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n)
+{
+	wchar_t *ret = d;
+	while (n--) *d++ = c;
+	return ret;
+}
diff --git a/src/stub/utmpx.c b/src/stub/utmpx.c
new file mode 100644
index 00000000..32003969
--- /dev/null
+++ b/src/stub/utmpx.c
@@ -0,0 +1,30 @@
+#include <utmpx.h>
+#include <stddef.h>
+
+void endutxent(void)
+{
+}
+
+void setutxent(void)
+{
+}
+
+struct utmpx *getutxent(void)
+{
+	return NULL;
+}
+
+struct utmpx *getutxid(const struct utmpx *ut)
+{
+	return NULL;
+}
+
+struct utmpx *getutxline(const struct utmpx *ut)
+{
+	return NULL;
+}
+
+struct utmpx *pututxline(const struct utmpx *ut)
+{
+	return NULL;
+}
diff --git a/src/temp/mkdtemp.c b/src/temp/mkdtemp.c
new file mode 100644
index 00000000..f8b067ec
--- /dev/null
+++ b/src/temp/mkdtemp.c
@@ -0,0 +1,21 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include "libc.h"
+
+char *mkdtemp(char *template)
+{
+	for (;;) {
+		if (!mktemp(template)) return 0;
+		if (!mkdir(template, 0700)) return template;
+		if (errno != EEXIST) return 0;
+		/* this is safe because mktemp verified
+		 * that we have a valid template string */
+		strcpy(template+strlen(template)-6, "XXXXXX");
+	}
+}
diff --git a/src/temp/mkstemp.c b/src/temp/mkstemp.c
new file mode 100644
index 00000000..b1567191
--- /dev/null
+++ b/src/temp/mkstemp.c
@@ -0,0 +1,26 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include "libc.h"
+
+int mkstemp(char *template)
+{
+	int fd;
+retry:
+	if (!mktemp(template)) return -1;
+	fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
+	if (fd >= 0) return fd;
+	if (errno == EEXIST) {
+		/* this is safe because mktemp verified
+		 * that we have a valid template string */
+		strcpy(template+strlen(template)-6, "XXXXXX");
+		goto retry;
+	}
+	return -1;
+}
+
+LFS64(mkstemp);
diff --git a/src/temp/mktemp.c b/src/temp/mktemp.c
new file mode 100644
index 00000000..8638e087
--- /dev/null
+++ b/src/temp/mktemp.c
@@ -0,0 +1,29 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libc.h"
+
+char *mktemp(char *template)
+{
+	static int lock;
+	static int index;
+	int l = strlen(template);
+
+	if (l < 6 || strcmp(template+l-6, "XXXXXX")) {
+		errno = EINVAL;
+		return NULL;
+	}
+	LOCK(&lock);
+	for (; index < 1000000; index++) {
+		snprintf(template+l-6, 6, "%06d", index);
+		if (access(template, F_OK) != 0) {
+			UNLOCK(&lock);
+			return template;
+		}
+	}
+	UNLOCK(&lock);
+	return NULL;	
+}
diff --git a/src/termios/cfgetospeed.c b/src/termios/cfgetospeed.c
new file mode 100644
index 00000000..0ebc198c
--- /dev/null
+++ b/src/termios/cfgetospeed.c
@@ -0,0 +1,12 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+
+speed_t cfgetospeed(const struct termios *tio)
+{
+	return tio->c_cflag & CBAUD;
+}
+
+speed_t cfgetispeed(const struct termios *tio)
+{
+	return cfgetospeed(tio);
+}
diff --git a/src/termios/cfsetospeed.c b/src/termios/cfsetospeed.c
new file mode 100644
index 00000000..80c790f1
--- /dev/null
+++ b/src/termios/cfsetospeed.c
@@ -0,0 +1,22 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include "libc.h"
+
+int cfsetospeed(struct termios *tio, speed_t speed)
+{
+	if (speed & ~CBAUD) {
+		errno = EINVAL;
+		return -1;
+	}
+	tio->c_cflag &= ~CBAUD;
+	tio->c_cflag |= speed;
+	return 0;
+}
+
+int cfsetispeed(struct termios *tio, speed_t speed)
+{
+	return speed ? cfsetospeed(tio, speed) : 0;
+}
+
+weak_alias(cfsetospeed, cfsetspeed);
diff --git a/src/termios/tcdrain.c b/src/termios/tcdrain.c
new file mode 100644
index 00000000..c51dd401
--- /dev/null
+++ b/src/termios/tcdrain.c
@@ -0,0 +1,7 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+
+int tcdrain(int fd)
+{
+	return ioctl(fd, TCSBRK, 1);
+}
diff --git a/src/termios/tcflow.c b/src/termios/tcflow.c
new file mode 100644
index 00000000..c7fc3fe2
--- /dev/null
+++ b/src/termios/tcflow.c
@@ -0,0 +1,7 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+
+int tcflow(int fd, int action)
+{
+	return ioctl(fd, TCXONC, action);
+}
diff --git a/src/termios/tcflush.c b/src/termios/tcflush.c
new file mode 100644
index 00000000..50222669
--- /dev/null
+++ b/src/termios/tcflush.c
@@ -0,0 +1,7 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+
+int tcflush(int fd, int queue)
+{
+	return ioctl(fd, TCFLSH, queue);
+}
diff --git a/src/termios/tcgetattr.c b/src/termios/tcgetattr.c
new file mode 100644
index 00000000..d9ce786e
--- /dev/null
+++ b/src/termios/tcgetattr.c
@@ -0,0 +1,10 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <string.h>
+
+int tcgetattr(int fd, struct termios *tio)
+{
+	if (ioctl(fd, TCGETS, tio))
+		return -1;
+	return 0;
+}
diff --git a/src/termios/tcgetsid.c b/src/termios/tcgetsid.c
new file mode 100644
index 00000000..1053fd64
--- /dev/null
+++ b/src/termios/tcgetsid.c
@@ -0,0 +1,10 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+
+pid_t tcgetsid(int fd)
+{
+	int sid;
+	if (ioctl(fd, TIOCGSID, &sid) < 0)
+		return -1;
+	return sid;
+}
diff --git a/src/termios/tcsendbreak.c b/src/termios/tcsendbreak.c
new file mode 100644
index 00000000..b6df0a23
--- /dev/null
+++ b/src/termios/tcsendbreak.c
@@ -0,0 +1,8 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+
+int tcsendbreak(int fd, int dur)
+{
+	/* nonzero duration is implementation-defined, so ignore it */
+	return ioctl(fd, TCSBRK, 0);
+}
diff --git a/src/termios/tcsetattr.c b/src/termios/tcsetattr.c
new file mode 100644
index 00000000..e9a168f3
--- /dev/null
+++ b/src/termios/tcsetattr.c
@@ -0,0 +1,13 @@
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <errno.h>
+
+int tcsetattr(int fd, int act, const struct termios *tio)
+{
+	if (act < 0 || act > 2) {
+		errno = EINVAL;
+		return -1;
+	}
+	return ioctl(fd, TCSETS+act, tio);
+}
diff --git a/src/thread/__futex.c b/src/thread/__futex.c
new file mode 100644
index 00000000..93352fa3
--- /dev/null
+++ b/src/thread/__futex.c
@@ -0,0 +1,8 @@
+#include "futex.h"
+#include "syscall.h"
+
+int __futex(volatile int *addr, int op, int val, void *ts)
+{
+	return syscall4(__NR_futex, (long)addr, op, val, (long)ts);
+}
+
diff --git a/src/thread/__lock.c b/src/thread/__lock.c
new file mode 100644
index 00000000..557c6a62
--- /dev/null
+++ b/src/thread/__lock.c
@@ -0,0 +1,12 @@
+#define SYSCALL_RETURN_ERRNO
+#include "pthread_impl.h"
+
+void __lock(volatile int *l)
+{
+	int spins=100000;
+	/* Do not use futexes because we insist that unlocking is a simple
+	 * assignment to optimize non-pathological code with no contention. */
+	while (a_xchg(l, 1))
+		if (spins) spins--, a_spin();
+		else syscall0(__NR_sched_yield);
+}
diff --git a/src/thread/__set_thread_area.c b/src/thread/__set_thread_area.c
new file mode 100644
index 00000000..576d8b40
--- /dev/null
+++ b/src/thread/__set_thread_area.c
@@ -0,0 +1,9 @@
+#include "syscall.h"
+
+int __set_thread_area(unsigned long *desc)
+{
+	if (syscall1(__NR_set_thread_area, (long)desc) < 0)
+		return -1;
+	__asm__ __volatile__ ( "movw %w0,%%gs" : : "r"(desc[0]*8+3) );
+	return 0;
+}
diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
new file mode 100644
index 00000000..354def2c
--- /dev/null
+++ b/src/thread/__timedwait.c
@@ -0,0 +1,21 @@
+#include <time.h>
+#include <errno.h>
+#include "futex.h"
+#define SYSCALL_RETURN_ERRNO
+#include "syscall.h"
+#include <stdio.h>
+int __timedwait(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv)
+{
+	struct timespec to;
+	if (at) {
+		clock_gettime(clk, &to);
+		to.tv_sec = at->tv_sec - to.tv_sec;
+		if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) {
+			to.tv_sec--;
+			to.tv_nsec += 1000000000;
+		}
+		if (to.tv_sec < 0) return ETIMEDOUT;
+	}
+	if (priv) priv = 128; priv=0;
+	return syscall4(__NR_futex, (long)addr, FUTEX_WAIT | priv, val, at ? (long)&to : 0);
+}
diff --git a/src/thread/__unmapself.c b/src/thread/__unmapself.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/thread/__unmapself.c
diff --git a/src/thread/__wait.c b/src/thread/__wait.c
new file mode 100644
index 00000000..8c249cd3
--- /dev/null
+++ b/src/thread/__wait.c
@@ -0,0 +1,16 @@
+#define SYSCALL_RETURN_ERRNO
+#include "pthread_impl.h"
+
+void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
+{
+	int spins=50000;
+	if (priv) priv = 128; priv=0;
+	while (spins--) {
+		if (*addr==val) a_spin();
+		else return;
+	}
+	if (waiters) a_inc(waiters);
+	while (*addr==val)
+		syscall4(__NR_futex, (long)addr, FUTEX_WAIT|priv, val, 0);
+	if (waiters) a_dec(waiters);
+}
diff --git a/src/thread/__wake.c b/src/thread/__wake.c
new file mode 100644
index 00000000..048ddcc0
--- /dev/null
+++ b/src/thread/__wake.c
@@ -0,0 +1,9 @@
+#define SYSCALL_RETURN_ERRNO
+#include "pthread_impl.h"
+
+void __wake(volatile int *addr, int cnt, int priv)
+{
+	if (priv) priv = 128; priv=0;
+	if (cnt<0) cnt = INT_MAX;
+	syscall3(__NR_futex, (long)addr, FUTEX_WAKE | priv, cnt);
+}
diff --git a/src/thread/cancellation.c b/src/thread/cancellation.c
new file mode 100644
index 00000000..e35ba824
--- /dev/null
+++ b/src/thread/cancellation.c
@@ -0,0 +1,22 @@
+#include "pthread_impl.h"
+
+void __pthread_register_cancel(struct __ptcb *cb)
+{
+	struct pthread *self = pthread_self();
+	cb->__next = self->cancelbuf;
+	self->cancelbuf = cb;
+}
+
+#define pthread_self __pthread_self
+
+void __pthread_unregister_cancel(struct __ptcb *cb)
+{
+	struct pthread *self = pthread_self();
+	self->cancelbuf = self->cancelbuf->__next;
+}
+
+void __pthread_unwind_next(struct __ptcb *cb)
+{
+	if (cb->__next) longjmp((void *)cb->__next->__jb, 1);
+	pthread_exit(PTHREAD_CANCELLED);
+}
diff --git a/src/thread/clone.c b/src/thread/clone.c
new file mode 100644
index 00000000..971bfeed
--- /dev/null
+++ b/src/thread/clone.c
@@ -0,0 +1,26 @@
+#if 0
+
+int clone(int (*start)(void *), void *stack, int flags, void *arg,
+	pid_t *ptid, struct user_desc *tls, pid_t *ctid)
+{
+	int ret;
+	__asm__(
+	        "andl $-16,%%ecx     \n\t"
+		"xchgl %%ebx,%2      \n\t"
+		"movl %%ebx,(%%ecx)  \n\t"
+		"int $0x80           \n\t"
+		"testl %%eax,%%eax   \n\t"
+		"jnz 1f              \n\t"
+		"xorl %%ebp,%%ebp    \n\t"
+		"call *%%ebx         \n\t"
+		"\n1:                \n\t"
+		"xchgl %%ebx,%2      \n\t"
+		: "=a" (ret)
+		: "a" (__NR_clone), "m" (flags), "c"(stack), "d"(ptid),
+		  "S" (tls), "D" (ctid)
+		: "memory"
+	);
+	return __syscall_ret(ret);
+}
+
+#endif
diff --git a/src/thread/i386/__unmapself.s b/src/thread/i386/__unmapself.s
new file mode 100644
index 00000000..5c674966
--- /dev/null
+++ b/src/thread/i386/__unmapself.s
@@ -0,0 +1,22 @@
+.text
+.global __unmapself
+.type   __unmapself,%function
+__unmapself:
+	call 1f
+	.long -1
+	.long -1
+1:	popl %ecx
+	xorl %ebx,%ebx
+	xorl %edx,%edx
+	movl $8,%esi
+	movl $175,%eax
+	int $128
+	movl $91,%eax
+	movl 4(%esp),%ebx
+	movl 8(%esp),%ecx
+	int $128
+	xorl %ebx,%ebx
+	movl $1,%eax
+	int $128
+
+.size __unmapself,.-__unmapself
diff --git a/src/thread/i386/clone.s b/src/thread/i386/clone.s
new file mode 100644
index 00000000..4f33366c
--- /dev/null
+++ b/src/thread/i386/clone.s
@@ -0,0 +1,35 @@
+.text
+.global __clone
+.type   __clone,%function
+__clone:
+	movl	8(%esp),%ecx
+	andl	$0xfffffff0, %ecx
+	subl	$28,%ecx
+	movl	16(%esp),%eax
+	movl	%eax,12(%ecx)
+	movl	4(%esp),%eax
+	movl	%eax,8(%ecx)
+	pushl	%ebx
+	pushl	%esi
+	pushl	%edi
+	movl	$120,%eax
+	movl	12+12(%esp),%ebx
+	movl	20+12(%esp),%edx
+	movl	24+12(%esp),%esi
+	movl	28+12(%esp),%edi
+	int	$128
+	popl	%edi
+	popl	%esi
+	popl	%ebx
+	test	%eax,%eax
+	jnz	1f
+	xorl	%ebp,%ebp
+	call	*%ebx
+	movl	%eax, %ebx
+	movl	$1, %eax
+	int	$128
+1:	
+	movl %eax, 4(%esp)
+	ret
+
+.size __clone,.-__clone
diff --git a/src/thread/pthread_attr_destroy.c b/src/thread/pthread_attr_destroy.c
new file mode 100644
index 00000000..b5845dd0
--- /dev/null
+++ b/src/thread/pthread_attr_destroy.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_attr_destroy(pthread_attr_t *a)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_attr_getdetachstate.c b/src/thread/pthread_attr_getdetachstate.c
new file mode 100644
index 00000000..9cd49536
--- /dev/null
+++ b/src/thread/pthread_attr_getdetachstate.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_getdetachstate(pthread_attr_t *a, int *state)
+{
+	*state = a->__detach;
+	return 0;
+}
diff --git a/src/thread/pthread_attr_getguardsize.c b/src/thread/pthread_attr_getguardsize.c
new file mode 100644
index 00000000..3f089c8c
--- /dev/null
+++ b/src/thread/pthread_attr_getguardsize.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_getguardsize(pthread_attr_t *a, size_t *size)
+{
+	*size = a->__guardsize + DEFAULT_GUARD_SIZE;
+	return 0;
+}
diff --git a/src/thread/pthread_attr_getscope.c b/src/thread/pthread_attr_getscope.c
new file mode 100644
index 00000000..0cb224d3
--- /dev/null
+++ b/src/thread/pthread_attr_getscope.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_attr_getscope(pthread_attr_t *a, int *scope)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_attr_getstacksize.c b/src/thread/pthread_attr_getstacksize.c
new file mode 100644
index 00000000..40bbf186
--- /dev/null
+++ b/src/thread/pthread_attr_getstacksize.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_getstacksize(pthread_attr_t *a, size_t *size)
+{
+	*size = a->__stacksize + DEFAULT_STACK_SIZE;
+	return 0;
+}
diff --git a/src/thread/pthread_attr_init.c b/src/thread/pthread_attr_init.c
new file mode 100644
index 00000000..d91bf157
--- /dev/null
+++ b/src/thread/pthread_attr_init.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_init(pthread_attr_t *a)
+{
+	memset(a, 0, sizeof *a);
+	return 0;
+}
diff --git a/src/thread/pthread_attr_setdetachstate.c b/src/thread/pthread_attr_setdetachstate.c
new file mode 100644
index 00000000..d23b4778
--- /dev/null
+++ b/src/thread/pthread_attr_setdetachstate.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_setdetachstate(pthread_attr_t *a, int state)
+{
+	a->__detach = state;
+	return 0;
+}
diff --git a/src/thread/pthread_attr_setguardsize.c b/src/thread/pthread_attr_setguardsize.c
new file mode 100644
index 00000000..e0e8d3fb
--- /dev/null
+++ b/src/thread/pthread_attr_setguardsize.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_attr_setguardsize(pthread_attr_t *a, size_t size)
+{
+	if (size > SIZE_MAX/8) return EINVAL;
+	a->__guardsize = size - DEFAULT_GUARD_SIZE;
+	return 0;
+}
diff --git a/src/thread/pthread_attr_setscope.c b/src/thread/pthread_attr_setscope.c
new file mode 100644
index 00000000..a970a819
--- /dev/null
+++ b/src/thread/pthread_attr_setscope.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_attr_setscope(pthread_attr_t *a, int scope)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_attr_setstacksize.c b/src/thread/pthread_attr_setstacksize.c
new file mode 100644
index 00000000..58f4bb18
--- /dev/null
+++ b/src/thread/pthread_attr_setstacksize.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_attr_setstacksize(pthread_attr_t *a, size_t size)
+{
+	if (size-PAGE_SIZE > SIZE_MAX/4) return EINVAL;
+	a->__stacksize = size - DEFAULT_STACK_SIZE;
+	return 0;
+}
diff --git a/src/thread/pthread_barrier_destroy.c b/src/thread/pthread_barrier_destroy.c
new file mode 100644
index 00000000..2898c41a
--- /dev/null
+++ b/src/thread/pthread_barrier_destroy.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_barrier_destroy(pthread_barrier_t *b)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_barrier_init.c b/src/thread/pthread_barrier_init.c
new file mode 100644
index 00000000..2cc67ed5
--- /dev/null
+++ b/src/thread/pthread_barrier_init.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_barrier_init(pthread_barrier_t *b, const pthread_barrierattr_t *a, unsigned count)
+{
+	if (!count) return EINVAL;
+	*b = (pthread_barrier_t){ .__limit = count-1 };
+	return 0;
+}
diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c
new file mode 100644
index 00000000..02c252ad
--- /dev/null
+++ b/src/thread/pthread_barrier_wait.c
@@ -0,0 +1,31 @@
+#include "pthread_impl.h"
+
+int pthread_barrier_wait(pthread_barrier_t *b)
+{
+	int cur;
+
+	/* Trivial case: count was set at 1 */
+	if (!b->__limit) return PTHREAD_BARRIER_SERIAL_THREAD;
+
+	/* Wait for anyone still suspended at previous use of barrier */
+	while ((cur=b->__left))
+		__wait(&b->__left, &b->__waiters, cur, 0);
+
+	/* If we are the last to reach barrier, reset it and wake others */
+	if (a_fetch_add(&b->__count, 1) == b->__limit) {
+		b->__left = b->__limit;
+		b->__count = 0;
+		__wake(&b->__count, -1, 0);
+		return PTHREAD_BARRIER_SERIAL_THREAD;
+	}
+
+	/* Wait for our peers to reach the barrier */
+	while ((cur=b->__count))
+		__wait(&b->__count, 0, cur, 0);
+
+	/* If we're the last to wake up and barrier is awaiting reuse */
+	if (a_fetch_add(&b->__left, -1) == 1 && b->__waiters)
+		__wake(&b->__left, -1, 0);
+
+	return 0;
+}
diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c
new file mode 100644
index 00000000..9397ffe9
--- /dev/null
+++ b/src/thread/pthread_cancel.c
@@ -0,0 +1,7 @@
+#define SYSCALL_RETURN_ERRNO
+#include "pthread_impl.h"
+
+int pthread_cancel(pthread_t t)
+{
+	return syscall3(__NR_tgkill, t->pid, t->tid, SIGCANCEL);
+}
diff --git a/src/thread/pthread_cond_broadcast.c b/src/thread/pthread_cond_broadcast.c
new file mode 100644
index 00000000..7a023b85
--- /dev/null
+++ b/src/thread/pthread_cond_broadcast.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_cond_broadcast(pthread_cond_t *c)
+{
+	c->__block = 0;
+	__wake(&c->__block, -1, 0);
+	return 0;
+}
diff --git a/src/thread/pthread_cond_destroy.c b/src/thread/pthread_cond_destroy.c
new file mode 100644
index 00000000..1d21a5a8
--- /dev/null
+++ b/src/thread/pthread_cond_destroy.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_cond_destroy(pthread_cond_t *c)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_cond_init.c b/src/thread/pthread_cond_init.c
new file mode 100644
index 00000000..33948606
--- /dev/null
+++ b/src/thread/pthread_cond_init.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
+{
+	memset(c, 0, sizeof *c);
+	return 0;
+}
diff --git a/src/thread/pthread_cond_signal.c b/src/thread/pthread_cond_signal.c
new file mode 100644
index 00000000..0dd9416b
--- /dev/null
+++ b/src/thread/pthread_cond_signal.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_cond_signal(pthread_cond_t *c)
+{
+	c->__block = 0;
+	__wake(&c->__block, 1, 0);
+	return 0;
+}
diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c
new file mode 100644
index 00000000..b67dded4
--- /dev/null
+++ b/src/thread/pthread_cond_timedwait.c
@@ -0,0 +1,26 @@
+#include "pthread_impl.h"
+
+static void relock(void *m)
+{
+	pthread_mutex_lock(m);
+}
+
+int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *ts)
+{
+	int r, e=0;
+	CANCELPT(0);
+
+	pthread_cleanup_push(relock, m);
+	c->__block = 1;
+	if ((r=pthread_mutex_unlock(m))) return r;
+
+	CANCELPT(1);
+	e = __timedwait(&c->__block, 1, CLOCK_REALTIME, ts, 0);
+	CANCELPT(0);
+
+	pthread_cleanup_pop(0);
+	if ((r=pthread_mutex_lock(m))) return r;
+
+	CANCELPT(0);
+	return e;
+}
diff --git a/src/thread/pthread_cond_wait.c b/src/thread/pthread_cond_wait.c
new file mode 100644
index 00000000..eb70e5f7
--- /dev/null
+++ b/src/thread/pthread_cond_wait.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
+{
+	return pthread_cond_timedwait(c, m, 0);
+}
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
new file mode 100644
index 00000000..6fa484c7
--- /dev/null
+++ b/src/thread/pthread_create.c
@@ -0,0 +1,189 @@
+#include "pthread_impl.h"
+
+#define pthread_self __pthread_self
+
+static void docancel(struct pthread *self)
+{
+	struct __ptcb cb = { .__next = self->cancelbuf };
+	__pthread_unwind_next(&cb);
+}
+
+static void cancel_handler(int sig, siginfo_t *si, void *ctx)
+{
+	struct pthread *self = pthread_self();
+	self->cancel = 1;
+	if (self->canceldisable || (!self->cancelasync && !self->cancelpoint))
+		return;
+	docancel(self);
+}
+
+/* "rsyscall" is a mechanism by which a thread can synchronously force all
+ * other threads to perform an arbitrary syscall. It is necessary to work
+ * around the non-conformant implementation of setuid() et al on Linux,
+ * which affect only the calling thread and not the whole process. This
+ * implementation performs some tricks with signal delivery to work around
+ * the fact that it does not keep any list of threads in userspace. */
+
+static struct {
+	volatile int lock, hold, blocks, cnt;
+	unsigned long arg[6];
+	int nr;
+	int err;
+} rs;
+
+static void rsyscall_handler(int sig, siginfo_t *si, void *ctx)
+{
+	if (rs.cnt == libc.threads_minus_1) return;
+
+	if (syscall6(rs.nr, rs.arg[0], rs.arg[1], rs.arg[2],
+		rs.arg[3], rs.arg[4], rs.arg[5]) < 0 && !rs.err) rs.err=errno;
+
+	a_inc(&rs.cnt);
+	__wake(&rs.cnt, 1, 1);
+	while(rs.hold)
+		__wait(&rs.hold, 0, 1, 1);
+	a_dec(&rs.cnt);
+	if (!rs.cnt) __wake(&rs.cnt, 1, 1);
+}
+
+static int rsyscall(int nr, long a, long b, long c, long d, long e, long f)
+{
+	int i, ret;
+	sigset_t set = { 0 };
+	struct pthread *self = pthread_self();
+	sigaddset(&set, SIGSYSCALL);
+
+	LOCK(&rs.lock);
+	while ((i=rs.blocks))
+		__wait(&rs.blocks, 0, i, 1);
+
+	__libc_sigprocmask(SIG_BLOCK, &set, 0);
+
+	rs.nr = nr;
+	rs.arg[0] = a; rs.arg[1] = b;
+	rs.arg[2] = c; rs.arg[3] = d;
+	rs.arg[4] = d; rs.arg[5] = f;
+	rs.hold = 1;
+	rs.err = 0;
+	rs.cnt = 0;
+
+	/* Dispatch signals until all threads respond */
+	for (i=libc.threads_minus_1; i; i--)
+		sigqueue(self->pid, SIGSYSCALL, (union sigval){0});
+	while ((i=rs.cnt) < libc.threads_minus_1) {
+		sigqueue(self->pid, SIGSYSCALL, (union sigval){0});
+		__wait(&rs.cnt, 0, i, 1);
+	}
+
+	/* Handle any lingering signals with no-op */
+	__libc_sigprocmask(SIG_UNBLOCK, &set, 0);
+
+	/* Resume other threads' signal handlers and wait for them */
+	rs.hold = 0;
+	__wake(&rs.hold, -1, 0);
+	while((i=rs.cnt)) __wait(&rs.cnt, 0, i, 1);
+
+	if (rs.err) errno = rs.err, ret = -1;
+	else ret = syscall6(nr, a, b, c, d, e, f);
+
+	UNLOCK(&rs.lock);
+	return ret;
+}
+
+static void cancelpt(int x)
+{
+	struct pthread *self = pthread_self();
+	if (self->canceldisable) return;
+	self->cancelpoint = x;
+	if (self->cancel) docancel(self);
+}
+
+static void init_threads()
+{
+	struct sigaction sa = { .sa_flags = SA_SIGINFO | SA_RESTART };
+	libc.lock = __lock;
+	libc.cancelpt = cancelpt;
+	libc.rsyscall = rsyscall;
+	sa.sa_sigaction = cancel_handler;
+	__libc_sigaction(SIGCANCEL, &sa, 0);
+	sigaddset(&sa.sa_mask, SIGSYSCALL);
+	sigaddset(&sa.sa_mask, SIGCANCEL);
+	sa.sa_sigaction = rsyscall_handler;
+	__libc_sigaction(SIGSYSCALL, &sa, 0);
+	sigprocmask(SIG_UNBLOCK, &sa.sa_mask, 0);
+}
+
+static int start(void *p)
+{
+	struct pthread *self = p;
+	pthread_exit(self->start(self->start_arg));
+	return 0;
+}
+
+#undef pthread_self
+
+#define CLONE_MAGIC 0x7d0f00
+int __clone(int (*)(void *), void *, int, void *, pid_t *, void *, pid_t *);
+
+#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE)
+
+/* pthread_key_create.c overrides this */
+static const size_t dummy = 0;
+weak_alias(dummy, __pthread_tsd_size);
+
+int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(void *), void *arg)
+{
+	static int init;
+	int ret;
+	size_t size, guard;
+	struct pthread *self = pthread_self(), *new;
+	unsigned char *map, *stack, *tsd;
+	static const pthread_attr_t default_attr;
+
+	if (!self) return errno = ENOSYS;
+	if (!init && ++init) init_threads();
+
+	if (!attr) attr = &default_attr;
+	guard = ROUND(attr->__guardsize + DEFAULT_GUARD_SIZE);
+	size = guard + ROUND(attr->__stacksize + DEFAULT_STACK_SIZE);
+	size += __pthread_tsd_size;
+	map = mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
+	if (!map) return EAGAIN;
+	mprotect(map, guard, PROT_NONE);
+
+	tsd = map + size - __pthread_tsd_size;
+	new = (void *)(tsd - sizeof *new - PAGE_SIZE%sizeof *new);
+	new->map_base = map;
+	new->map_size = size;
+	new->pid = self->pid;
+	new->errno_ptr = &new->errno_val;
+	new->start = entry;
+	new->start_arg = arg;
+	new->self = new;
+	new->tsd = (void *)tsd;
+	new->detached = attr->__detach;
+	new->attr = *attr;
+	memcpy(new->tlsdesc, self->tlsdesc, sizeof new->tlsdesc);
+	new->tlsdesc[1] = (uintptr_t)new;
+	stack = (void *)((uintptr_t)new-1 & ~(uintptr_t)15);
+
+	/* We must synchronize new thread creation with rsyscall
+	 * delivery. This looks to be the least expensive way: */
+	a_inc(&rs.blocks);
+	while (rs.lock) __wait(&rs.lock, 0, 1, 1);
+
+	a_inc(&libc.threads_minus_1);
+	ret = __clone(start, stack, CLONE_MAGIC, new,
+		&new->tid, &new->tlsdesc, &new->tid);
+
+	a_dec(&rs.blocks);
+	if (rs.lock) __wake(&rs.blocks, 1, 1);
+
+	if (ret < 0) {
+		a_dec(&libc.threads_minus_1);
+		munmap(map, size);
+		return -ret;
+	}
+	*res = new;
+	return 0;
+}
diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c
new file mode 100644
index 00000000..f0eae3e8
--- /dev/null
+++ b/src/thread/pthread_detach.c
@@ -0,0 +1,11 @@
+#include "pthread_impl.h"
+
+int pthread_detach(pthread_t t)
+{
+	/* Cannot detach a thread that's already exiting */
+	if (a_xchg(&t->exitlock, 1))
+		return pthread_join(t, 0);
+	t->detached = 1;
+	t->exitlock = 0;
+	return 0;
+}
diff --git a/src/thread/pthread_equal.c b/src/thread/pthread_equal.c
new file mode 100644
index 00000000..a55d280c
--- /dev/null
+++ b/src/thread/pthread_equal.c
@@ -0,0 +1,6 @@
+#include <pthread.h>
+
+int pthread_equal(pthread_t a, pthread_t b)
+{
+	return a==b;
+}
diff --git a/src/thread/pthread_exit.c b/src/thread/pthread_exit.c
new file mode 100644
index 00000000..4966e234
--- /dev/null
+++ b/src/thread/pthread_exit.c
@@ -0,0 +1,25 @@
+#include "pthread_impl.h"
+
+#undef pthread_self
+
+void pthread_exit(void *result)
+{
+	int i;
+	struct pthread *self = pthread_self();
+	self->result = result;
+
+	a_dec(&libc.threads_minus_1);
+	if (libc.threads_minus_1 < 0)
+		exit(0);
+
+	LOCK(&self->exitlock);
+
+	if (self->tsd_used) for (i=0; i<PTHREAD_KEYS_MAX; i++)
+		if (self->tsd[i] && libc.tsd_keys[i])
+			libc.tsd_keys[i](self->tsd[i]);
+
+	if (self->detached && self->map_base)
+		__unmapself(self->map_base, self->map_size);
+
+	__syscall_exit(0);
+}
diff --git a/src/thread/pthread_getspecific.c b/src/thread/pthread_getspecific.c
new file mode 100644
index 00000000..a6ca27d0
--- /dev/null
+++ b/src/thread/pthread_getspecific.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+void *pthread_getspecific(pthread_key_t k)
+{
+	struct pthread *self = pthread_self();
+	if (!self->tsd) return 0;
+	return self->tsd[k];
+}
diff --git a/src/thread/pthread_join.c b/src/thread/pthread_join.c
new file mode 100644
index 00000000..5210ed48
--- /dev/null
+++ b/src/thread/pthread_join.c
@@ -0,0 +1,12 @@
+#include "pthread_impl.h"
+
+int pthread_join(pthread_t t, void **res)
+{
+	int tmp = t->tid;
+	CANCELPT_BEGIN;
+	if (tmp) __wait(&t->tid, 0, tmp, 1);
+	CANCELPT_END;
+	if (res) *res = t->result;
+	if (t->map_base) munmap(t->map_base, t->map_size);
+	return 0;
+}
diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c
new file mode 100644
index 00000000..efc38046
--- /dev/null
+++ b/src/thread/pthread_key_create.c
@@ -0,0 +1,25 @@
+#include "pthread_impl.h"
+
+const size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX;
+
+static void nodtor(void *dummy)
+{
+}
+
+int pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
+{
+	static void (*keys[PTHREAD_KEYS_MAX])(void *);
+	int i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX;
+	int j = i;
+
+	libc.tsd_keys = keys;
+	if (!dtor) dtor = nodtor;
+	/* Cheap trick - &k cannot match any destructor pointer */
+	while (a_cas_p(keys+j, 0, &k)
+		&& (j=(j+1)%PTHREAD_KEYS_MAX) != i);
+	if (keys[j] != (void (*)(void *))&k)
+		return EAGAIN;
+	keys[j] = dtor;
+	*k = j;
+	return 0;
+}
diff --git a/src/thread/pthread_key_delete.c b/src/thread/pthread_key_delete.c
new file mode 100644
index 00000000..4914ebb4
--- /dev/null
+++ b/src/thread/pthread_key_delete.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_key_delete(pthread_key_t k)
+{
+	if (libc.tsd_keys) libc.tsd_keys[k] = 0;
+	return 0;
+}
diff --git a/src/thread/pthread_kill.c b/src/thread/pthread_kill.c
new file mode 100644
index 00000000..9d85fa5b
--- /dev/null
+++ b/src/thread/pthread_kill.c
@@ -0,0 +1,7 @@
+#define SYSCALL_RETURN_ERRNO
+#include "pthread_impl.h"
+
+int pthread_kill(pthread_t t, int sig)
+{
+	return syscall3(__NR_tgkill, t->pid, t->tid, sig);
+}
diff --git a/src/thread/pthread_mutex_destroy.c b/src/thread/pthread_mutex_destroy.c
new file mode 100644
index 00000000..6d49e689
--- /dev/null
+++ b/src/thread/pthread_mutex_destroy.c
@@ -0,0 +1,6 @@
+#include <pthread.h>
+
+int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_mutex_init.c b/src/thread/pthread_mutex_init.c
new file mode 100644
index 00000000..d453543d
--- /dev/null
+++ b/src/thread/pthread_mutex_init.c
@@ -0,0 +1,9 @@
+#include "pthread_impl.h"
+
+int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a)
+{
+	memset(m, 0, sizeof *m);
+	if (a) {
+	}
+	return 0;
+}
diff --git a/src/thread/pthread_mutex_lock.c b/src/thread/pthread_mutex_lock.c
new file mode 100644
index 00000000..6696f17a
--- /dev/null
+++ b/src/thread/pthread_mutex_lock.c
@@ -0,0 +1,9 @@
+#include "pthread_impl.h"
+
+int pthread_mutex_lock(pthread_mutex_t *m)
+{
+	int r;
+	while ((r=pthread_mutex_trylock(m)) == EBUSY)
+		__wait(&m->__lock, &m->__waiters, 1, 0);
+	return r;
+}
diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
new file mode 100644
index 00000000..5dfad94f
--- /dev/null
+++ b/src/thread/pthread_mutex_timedlock.c
@@ -0,0 +1,15 @@
+#include "pthread_impl.h"
+
+int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *at)
+{
+	int r, w=0;
+	while ((r=pthread_mutex_trylock(m)) == EBUSY) {
+		if (!w) a_inc(&m->__waiters), w++;
+		if (__timedwait(&m->__lock, 1, CLOCK_REALTIME, at, 0) == ETIMEDOUT) {
+			if (w) a_dec(&m->__waiters);
+			return ETIMEDOUT;
+		}
+	}
+	if (w) a_dec(&m->__waiters);
+	return r;
+}
diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c
new file mode 100644
index 00000000..1e3817bb
--- /dev/null
+++ b/src/thread/pthread_mutex_trylock.c
@@ -0,0 +1,28 @@
+#include "pthread_impl.h"
+
+int pthread_mutex_trylock(pthread_mutex_t *m)
+{
+	if (m->__type == PTHREAD_MUTEX_RECURSIVE) {
+		pthread_t self = pthread_self();
+		if (m->__owner == self) {
+			if ((unsigned)m->__lock >= INT_MAX) return EAGAIN;
+			a_inc(&m->__lock);
+			return 0;
+		}
+		if (a_fetch_add(&m->__lock, 1)) {
+			if (a_fetch_add(&m->__lock, -1)==1 && m->__waiters)
+				__wake(&m->__lock, 1, 0);
+			return EBUSY;
+		}
+		m->__owner = self;
+		return 0;
+	}
+
+	if (a_xchg(&m->__lock, 1))
+		if (m->__type == PTHREAD_MUTEX_ERRORCHECK
+		 && m->__owner == pthread_self()) return EDEADLK;
+		else return EBUSY;
+	if (m->__type == PTHREAD_MUTEX_ERRORCHECK)
+		m->__owner = pthread_self();
+	return 0;
+}
diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c
new file mode 100644
index 00000000..23e64ac8
--- /dev/null
+++ b/src/thread/pthread_mutex_unlock.c
@@ -0,0 +1,19 @@
+#include "pthread_impl.h"
+
+int pthread_mutex_unlock(pthread_mutex_t *m)
+{
+	if (m->__type == PTHREAD_MUTEX_RECURSIVE) {
+		if (a_fetch_add(&m->__lock, -1)==1 && m->__waiters)
+			__wake(&m->__lock, 1, 0);
+		return 0;
+	}
+
+	if (m->__type == PTHREAD_MUTEX_ERRORCHECK
+	 && m->__owner != pthread_self())
+	 	return EPERM;
+
+	m->__owner = 0;
+	m->__lock = 0;
+	if (m->__waiters) __wake(&m->__lock, 1, 0);
+	return 0;
+}
diff --git a/src/thread/pthread_mutexattr_destroy.c b/src/thread/pthread_mutexattr_destroy.c
new file mode 100644
index 00000000..9fd69747
--- /dev/null
+++ b/src/thread/pthread_mutexattr_destroy.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_mutexattr_destroy(pthread_mutexattr_t *a)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_mutexattr_gettype.c b/src/thread/pthread_mutexattr_gettype.c
new file mode 100644
index 00000000..9edb16c6
--- /dev/null
+++ b/src/thread/pthread_mutexattr_gettype.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type)
+{
+	*type = *a & 3;
+	return 0;
+}
diff --git a/src/thread/pthread_mutexattr_init.c b/src/thread/pthread_mutexattr_init.c
new file mode 100644
index 00000000..ea631069
--- /dev/null
+++ b/src/thread/pthread_mutexattr_init.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_mutexattr_init(pthread_mutexattr_t *a)
+{
+	memset(a, 0, sizeof *a);
+	return 0;
+}
diff --git a/src/thread/pthread_mutexattr_settype.c b/src/thread/pthread_mutexattr_settype.c
new file mode 100644
index 00000000..4e85950e
--- /dev/null
+++ b/src/thread/pthread_mutexattr_settype.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type)
+{
+	if ((unsigned)type > 2) return EINVAL;
+	*a = (*a & ~3) | type;
+	return 0;
+}
diff --git a/src/thread/pthread_once.c b/src/thread/pthread_once.c
new file mode 100644
index 00000000..72230054
--- /dev/null
+++ b/src/thread/pthread_once.c
@@ -0,0 +1,38 @@
+#include "pthread_impl.h"
+
+static void undo(void *control)
+{
+	a_store(control, 0);
+	__wake(control, 1, 0);
+}
+
+int pthread_once(pthread_once_t *control, void (*init)(void))
+{
+	static int waiters;
+
+	/* Return immediately if init finished before */
+	if (*control == 2) return 0;
+
+	/* Try to enter initializing state. Three possibilities:
+	 *  0 - we're the first or the other cancelled; run init
+	 *  1 - another thread is running init; wait
+	 *  2 - another thread finished running init; just return */
+
+	for (;;) switch (a_swap(control, 1)) {
+	case 0:
+		break;
+	case 1:
+		__wait(control, &waiters, 1, 0);
+		continue;
+	case 2:
+		a_store(control, 2);
+		return 0;
+	}
+
+	pthread_cleanup_push(undo, control);
+	init();
+	pthread_cleanup_pop(0);
+
+	if (waiters) __wake(control, -1, 0);
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_destroy.c b/src/thread/pthread_rwlock_destroy.c
new file mode 100644
index 00000000..49ecfbd0
--- /dev/null
+++ b/src/thread/pthread_rwlock_destroy.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_destroy(pthread_rwlock_t *rw)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_init.c b/src/thread/pthread_rwlock_init.c
new file mode 100644
index 00000000..f87d566c
--- /dev/null
+++ b/src/thread/pthread_rwlock_init.c
@@ -0,0 +1,9 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_init(pthread_rwlock_t *rw, const pthread_rwlockattr_t *a)
+{
+	memset(rw, 0, sizeof *rw);
+	if (a) {
+	}
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_rdlock.c b/src/thread/pthread_rwlock_rdlock.c
new file mode 100644
index 00000000..6bcdb815
--- /dev/null
+++ b/src/thread/pthread_rwlock_rdlock.c
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_rdlock(pthread_rwlock_t *rw)
+{
+	while (pthread_rwlock_tryrdlock(rw))
+		__wait(&rw->__wrlock, &rw->__waiters, 1, 0);
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_timedrdlock.c b/src/thread/pthread_rwlock_timedrdlock.c
new file mode 100644
index 00000000..290327de
--- /dev/null
+++ b/src/thread/pthread_rwlock_timedrdlock.c
@@ -0,0 +1,15 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_timedrdlock(pthread_rwlock_t *rw, const struct timespec *at)
+{
+	int w=0;
+	while (pthread_rwlock_tryrdlock(rw)) {
+		if (!w) a_inc(&rw->__waiters), w++;
+		if (__timedwait(&rw->__wrlock, 1, CLOCK_REALTIME, at, 0)==ETIMEDOUT) {
+			if (w) a_dec(&rw->__waiters);
+			return ETIMEDOUT;
+		}
+	}
+	if (w) a_dec(&rw->__waiters);
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_timedwrlock.c b/src/thread/pthread_rwlock_timedwrlock.c
new file mode 100644
index 00000000..9f749648
--- /dev/null
+++ b/src/thread/pthread_rwlock_timedwrlock.c
@@ -0,0 +1,17 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_timedwrlock(pthread_rwlock_t *rw, const struct timespec *at)
+{
+	int nr, *p, w=0;
+	while (pthread_rwlock_trywrlock(rw)==EAGAIN) {
+		if (!w) a_inc(&rw->__waiters), w++;
+		if ((nr=rw->__readers)) p = &rw->__readers;
+		else nr=1, p = &rw->__wrlock;
+		if (__timedwait(p, nr, CLOCK_REALTIME, at, 0)==ETIMEDOUT) {
+			if (w) a_dec(&rw->__waiters);
+			return ETIMEDOUT;
+		}
+	}
+	if (w) a_dec(&rw->__waiters);
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_tryrdlock.c b/src/thread/pthread_rwlock_tryrdlock.c
new file mode 100644
index 00000000..f59fbbdd
--- /dev/null
+++ b/src/thread/pthread_rwlock_tryrdlock.c
@@ -0,0 +1,13 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *rw)
+{
+	a_inc(&rw->__readers);
+	if (rw->__wrlock) {
+		a_dec(&rw->__readers);
+		if (rw->__waiters && !rw->__readers)
+			__wake(&rw->__readers, 1, 0);
+		return EAGAIN;
+	}
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_trywrlock.c b/src/thread/pthread_rwlock_trywrlock.c
new file mode 100644
index 00000000..c029b874
--- /dev/null
+++ b/src/thread/pthread_rwlock_trywrlock.c
@@ -0,0 +1,13 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_trywrlock(pthread_rwlock_t *rw)
+{
+	if (a_xchg(&rw->__wrlock, 1))
+		return EAGAIN;
+	if (rw->__readers) {
+		a_store(&rw->__wrlock, 0);
+		return EAGAIN;
+	}
+	rw->__owner = pthread_self()->tid;
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_unlock.c b/src/thread/pthread_rwlock_unlock.c
new file mode 100644
index 00000000..f39117e7
--- /dev/null
+++ b/src/thread/pthread_rwlock_unlock.c
@@ -0,0 +1,17 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_unlock(pthread_rwlock_t *rw)
+{
+	struct pthread *self = pthread_self();
+	if (rw->__owner == self->tid) {
+		rw->__owner = 0;
+		a_store(&rw->__wrlock, 0);
+		if (rw->__waiters)
+			__wake(&rw->__wrlock, -1, 0);
+		return 0;
+	}
+	a_dec(&rw->__readers);
+	if (rw->__waiters && !rw->__readers)
+		__wake(&rw->__readers, 1, 0);
+	return 0;
+}
diff --git a/src/thread/pthread_rwlock_wrlock.c b/src/thread/pthread_rwlock_wrlock.c
new file mode 100644
index 00000000..219e924a
--- /dev/null
+++ b/src/thread/pthread_rwlock_wrlock.c
@@ -0,0 +1,13 @@
+#include "pthread_impl.h"
+
+int pthread_rwlock_wrlock(pthread_rwlock_t *rw)
+{
+	int nr;
+	while (pthread_rwlock_trywrlock(rw)==EAGAIN) {
+		if ((nr=rw->__readers))
+			__wait(&rw->__readers, &rw->__waiters, nr, 0);
+		else
+			__wait(&rw->__wrlock, &rw->__waiters, 1, 0);
+	}
+	return 0;
+}
diff --git a/src/thread/pthread_self.c b/src/thread/pthread_self.c
new file mode 100644
index 00000000..686d73d5
--- /dev/null
+++ b/src/thread/pthread_self.c
@@ -0,0 +1,39 @@
+#include "pthread_impl.h"
+
+static struct pthread main_thread;
+
+#undef errno
+static int *errno_location()
+{
+	return pthread_self()->errno_ptr;
+}
+
+static int init_main_thread()
+{
+	main_thread.tlsdesc[0] = -1;
+	main_thread.tlsdesc[1] = (long)&main_thread;
+	main_thread.tlsdesc[2] = SIZE_MAX/PAGE_SIZE;
+	main_thread.tlsdesc[3] = 0x51;
+	main_thread.self = &main_thread;
+	main_thread.errno_ptr = __errno_location();
+	if (__set_thread_area(main_thread.tlsdesc) < 0)
+		return -1;
+	syscall1(__NR_set_tid_address, (long)&main_thread.tid);
+	libc.errno_location = errno_location;
+	main_thread.tid = main_thread.pid = getpid();
+	return 0;
+}
+
+#undef pthread_self
+
+pthread_t pthread_self()
+{
+	static int init, failed;
+	if (!init) {
+		if (failed) return 0;
+		if (init_main_thread() < 0) failed = 1;
+		if (failed) return 0;
+		init = 1;
+	}
+	return __pthread_self();
+}
diff --git a/src/thread/pthread_setcancelstate.c b/src/thread/pthread_setcancelstate.c
new file mode 100644
index 00000000..23c38851
--- /dev/null
+++ b/src/thread/pthread_setcancelstate.c
@@ -0,0 +1,10 @@
+#include "pthread_impl.h"
+
+int pthread_setcancelstate(int new, int *old)
+{
+	struct pthread *self = pthread_self();
+	if (old) *old = self->canceldisable;
+	if ((unsigned)new > 1) return EINVAL;
+	self->canceldisable = new;
+	return 0;
+}
diff --git a/src/thread/pthread_setcanceltype.c b/src/thread/pthread_setcanceltype.c
new file mode 100644
index 00000000..c73db22f
--- /dev/null
+++ b/src/thread/pthread_setcanceltype.c
@@ -0,0 +1,10 @@
+#include "pthread_impl.h"
+
+int pthread_setcanceltype(int new, int *old)
+{
+	struct pthread *self = pthread_self();
+	if (old) *old = self->cancelasync;
+	if ((unsigned)new > 1) return EINVAL;
+	self->cancelasync = new;
+	return 0;
+}
diff --git a/src/thread/pthread_setspecific.c b/src/thread/pthread_setspecific.c
new file mode 100644
index 00000000..171cef41
--- /dev/null
+++ b/src/thread/pthread_setspecific.c
@@ -0,0 +1,18 @@
+#include "pthread_impl.h"
+
+int pthread_setspecific(pthread_key_t k, const void *x)
+{
+	struct pthread *self = pthread_self();
+	/* Handle the case of the main thread */
+	if (!self->tsd) {
+		if (!x) return 0;
+		if (!(self->tsd = calloc(sizeof(void *), PTHREAD_KEYS_MAX)))
+			return ENOMEM;
+	}
+	/* Avoid unnecessary COW */
+	if (self->tsd[k] != x) {
+		self->tsd[k] = (void *)x;
+		self->tsd_used = 1;
+	}
+	return 0;
+}
diff --git a/src/thread/pthread_spin_destroy.c b/src/thread/pthread_spin_destroy.c
new file mode 100644
index 00000000..e65a820c
--- /dev/null
+++ b/src/thread/pthread_spin_destroy.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_spin_destroy(pthread_spinlock_t *s)
+{
+	return 0;
+}
diff --git a/src/thread/pthread_spin_init.c b/src/thread/pthread_spin_init.c
new file mode 100644
index 00000000..681881cf
--- /dev/null
+++ b/src/thread/pthread_spin_init.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_spin_init(pthread_spinlock_t *s, int shared)
+{
+	return *s = 0;
+}
diff --git a/src/thread/pthread_spin_lock.c b/src/thread/pthread_spin_lock.c
new file mode 100644
index 00000000..59fa6ea8
--- /dev/null
+++ b/src/thread/pthread_spin_lock.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_spin_lock(pthread_spinlock_t *s)
+{
+	while (a_xchg(s, 1));
+	return 0;
+}
diff --git a/src/thread/pthread_spin_trylock.c b/src/thread/pthread_spin_trylock.c
new file mode 100644
index 00000000..c12696b3
--- /dev/null
+++ b/src/thread/pthread_spin_trylock.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_spin_trylock(pthread_spinlock_t *s)
+{
+	return -a_xchg(s, 1) & EBUSY;
+}
diff --git a/src/thread/pthread_spin_unlock.c b/src/thread/pthread_spin_unlock.c
new file mode 100644
index 00000000..a7eab334
--- /dev/null
+++ b/src/thread/pthread_spin_unlock.c
@@ -0,0 +1,6 @@
+#include "pthread_impl.h"
+
+int pthread_spin_unlock(pthread_spinlock_t *s)
+{
+	return *s = 0;
+}
diff --git a/src/thread/pthread_testcancel.c b/src/thread/pthread_testcancel.c
new file mode 100644
index 00000000..774b7068
--- /dev/null
+++ b/src/thread/pthread_testcancel.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+void pthread_testcancel()
+{
+	CANCELPT_BEGIN;
+	CANCELPT_END;
+}
diff --git a/src/time/__asctime.c b/src/time/__asctime.c
new file mode 100644
index 00000000..18535802
--- /dev/null
+++ b/src/time/__asctime.c
@@ -0,0 +1,27 @@
+#include <time.h>
+#include <stdio.h>
+#include <langinfo.h>
+
+const char *__langinfo(nl_item);
+
+char *__asctime(const struct tm *tm, char *buf)
+{
+	/* FIXME: change __langinfo to __C_langinfo once we have locales */
+	if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+		__langinfo(ABDAY_1+tm->tm_wday),
+		__langinfo(ABMON_1+tm->tm_mon),
+		tm->tm_mday, tm->tm_hour,
+		tm->tm_min, tm->tm_sec,
+		1900 + tm->tm_year) >= 26)
+	{
+		/* ISO C requires us to use the above format string,
+		 * even if it will not fit in the buffer. Thus asctime_r
+		 * is _supposed_ to crash if the fields in tm are too large.
+		 * We follow this behavior and crash "gracefully" to warn
+		 * application developers that they may not be so lucky
+		 * on other implementations (e.g. stack smashing..).
+		 */
+		*(int*)0 = 0;
+	}
+	return buf;
+}
diff --git a/src/time/__time.h b/src/time/__time.h
new file mode 100644
index 00000000..967e5180
--- /dev/null
+++ b/src/time/__time.h
@@ -0,0 +1,9 @@
+time_t __tm_to_time(struct tm *);
+struct tm *__time_to_tm(time_t, struct tm *);
+void __tzset(void);
+struct tm *__dst_adjust(struct tm *tm);
+
+extern long __timezone;
+extern int __daylight;
+extern int __dst_offset;
+extern char *__tzname[2];
diff --git a/src/time/__time_to_tm.c b/src/time/__time_to_tm.c
new file mode 100644
index 00000000..a1ebc452
--- /dev/null
+++ b/src/time/__time_to_tm.c
@@ -0,0 +1,81 @@
+#include <time.h>
+
+/* C defines the rounding for division in a nonsensical way */
+#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b)))
+
+#define DAYS_PER_400Y (365*400 + 97)
+#define DAYS_PER_100Y (365*100 + 24)
+#define DAYS_PER_4Y   (365*4   + 1)
+
+/* FIXME: use lldiv once it's fixed to compute quot,rem together */
+struct tm *__time_to_tm(time_t t, struct tm *tm)
+{
+	/* months are march-based */
+	static const int days_thru_month[] = {31,61,92,122,153,184,214,245,275,306,337,366};
+	long long bigday;
+	unsigned int day, year4, year100;
+	int year, year400;
+	int month;
+	int leap;
+	int hour, min, sec;
+	int wday, mday, yday;
+
+	/* start from 2000-03-01 (multiple of 400 years) */
+	t += -946684800 - 86400*(31+29);
+
+	bigday = Q(t, 86400);
+	sec = t-bigday*86400;
+
+	hour = sec/3600;
+	sec -= hour*3600;
+	min = sec/60;
+	sec -= min*60;
+
+	/* 2000-03-01 was a wednesday */
+	wday = (3+bigday)%7;
+	if (wday < 0) wday += 7;
+
+	t = -946684800LL - 86400*(31+29) + 9000000;
+	
+	year400 = Q(bigday, DAYS_PER_400Y);
+	day = bigday-year400*DAYS_PER_400Y;
+
+	year100 = day/DAYS_PER_100Y;
+	if (year100 == 4) year100--;
+	day -= year100*DAYS_PER_100Y;
+
+	year4 = day/DAYS_PER_4Y;
+	if (year4 == 25) year4--;
+	day -= year4*DAYS_PER_4Y;
+
+	year = day/365;
+	if (year == 4) year--;
+	day -= year*365;
+
+	leap = !year && (year4 || !year100);
+	yday = day + 31+28 + leap;
+	if (yday >= 365+leap) yday -= 365+leap;
+
+	year += 4*year4 + 100*year100 + 400*year400 + 2000-1900;
+
+	for (month=0; days_thru_month[month] <= day; month++);
+	if (month) day -= days_thru_month[month-1];
+	month += 2;
+	if (month >= 12) {
+		month -= 12;
+		year++;
+	}
+
+	mday = day+1;
+
+	tm->tm_sec = sec;
+	tm->tm_min = min;
+	tm->tm_hour= hour;
+	tm->tm_mday= mday;
+	tm->tm_mon = month;
+	tm->tm_year= year;
+	tm->tm_wday= wday;
+	tm->tm_yday= yday;
+
+	return tm;
+}
diff --git a/src/time/__tm_to_time.c b/src/time/__tm_to_time.c
new file mode 100644
index 00000000..3fa15fad
--- /dev/null
+++ b/src/time/__tm_to_time.c
@@ -0,0 +1,33 @@
+#include <time.h>
+
+/* C defines the rounding for division in a nonsensical way */
+#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b)))
+
+time_t __tm_to_time(struct tm *tm)
+{
+	time_t year  = tm->tm_year + -100;
+	int    month = tm->tm_mon;
+	int    day   = tm->tm_mday;
+	int z4, z100, z400;
+
+	/* normalize month */
+	if (month >= 12) {
+		year += month/12;
+		month %= 12;
+	} else if (month < 0) {
+		year += month/12;
+		month %= 12;
+		if (month) {
+			month += 12;
+			year--;
+		}
+	}
+	z4 = Q(year - (month < 2), 4);
+	z100 = Q(z4, 25);
+	z400 = Q(z100, 4);
+	day += year*365 + z4 - z100 + z400 +
+		month[(int []){0,31,59,90,120,151,181,212,243,273,304,335}];
+	return (long long)day*86400
+		+ tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec
+		- -946684800; /* the dawn of time :) */
+}
diff --git a/src/time/asctime.c b/src/time/asctime.c
new file mode 100644
index 00000000..3102eb87
--- /dev/null
+++ b/src/time/asctime.c
@@ -0,0 +1,9 @@
+#include <time.h>
+
+char *__asctime(const struct tm *, char *);
+
+char *asctime(const struct tm *tm)
+{
+	static char buf[26];
+	return __asctime(tm, buf);
+}
diff --git a/src/time/asctime_r.c b/src/time/asctime_r.c
new file mode 100644
index 00000000..e51b8804
--- /dev/null
+++ b/src/time/asctime_r.c
@@ -0,0 +1,8 @@
+#include <time.h>
+
+char *__asctime(const struct tm *, char *);
+
+char *asctime_r(const struct tm *tm, char *buf)
+{
+	return __asctime(tm, buf);
+}
diff --git a/src/time/clock.c b/src/time/clock.c
new file mode 100644
index 00000000..2feddb36
--- /dev/null
+++ b/src/time/clock.c
@@ -0,0 +1,9 @@
+#include <time.h>
+#include <sys/times.h>
+
+/* this function assumes 100 hz linux and corrects for it */
+clock_t clock()
+{
+	struct tms tms;
+	return (unsigned long)times(&tms)*10000;
+}
diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c
new file mode 100644
index 00000000..dab09d50
--- /dev/null
+++ b/src/time/clock_gettime.c
@@ -0,0 +1,7 @@
+#include <time.h>
+#include "syscall.h"
+
+int clock_gettime(clockid_t clk, struct timespec *ts)
+{
+	return syscall2(__NR_clock_gettime, clk, (long)ts);
+}
diff --git a/src/time/ctime.c b/src/time/ctime.c
new file mode 100644
index 00000000..185ec554
--- /dev/null
+++ b/src/time/ctime.c
@@ -0,0 +1,6 @@
+#include <time.h>
+
+char *ctime(const time_t *t)
+{
+	return asctime(localtime(t));
+}
diff --git a/src/time/ctime_r.c b/src/time/ctime_r.c
new file mode 100644
index 00000000..d2260a16
--- /dev/null
+++ b/src/time/ctime_r.c
@@ -0,0 +1,8 @@
+#include <time.h>
+
+char *ctime_r(const time_t *t, char *buf)
+{
+	struct tm tm;
+	localtime_r(t, &tm);
+	return asctime_r(&tm, buf);
+}
diff --git a/src/time/difftime.c b/src/time/difftime.c
new file mode 100644
index 00000000..80a18cc0
--- /dev/null
+++ b/src/time/difftime.c
@@ -0,0 +1,6 @@
+#include <time.h>
+
+double difftime(time_t t1, time_t t0)
+{
+	return t1-t0;
+}
diff --git a/src/time/gettimeofday.c b/src/time/gettimeofday.c
new file mode 100644
index 00000000..2b8a287d
--- /dev/null
+++ b/src/time/gettimeofday.c
@@ -0,0 +1,9 @@
+#define SYSCALL_RETURN_ERRNO
+#include <sys/time.h>
+#include "syscall.h"
+
+int gettimeofday(struct timeval *tv, void *tz)
+{
+	syscall2(__NR_gettimeofday, (long)tv, 0);
+	return 0;
+}
diff --git a/src/time/gmtime.c b/src/time/gmtime.c
new file mode 100644
index 00000000..d4d5d1f1
--- /dev/null
+++ b/src/time/gmtime.c
@@ -0,0 +1,11 @@
+#include <time.h>
+
+#include "__time.h"
+
+struct tm *gmtime(const time_t *t)
+{
+	static struct tm tm;
+	__time_to_tm(*t, &tm);
+	tm.tm_isdst = 0;
+	return &tm;
+}
diff --git a/src/time/gmtime_r.c b/src/time/gmtime_r.c
new file mode 100644
index 00000000..5b565a65
--- /dev/null
+++ b/src/time/gmtime_r.c
@@ -0,0 +1,10 @@
+#include <time.h>
+
+#include "__time.h"
+
+struct tm *gmtime_r(const time_t *t, struct tm *result)
+{
+	__time_to_tm(*t, result);
+	result->tm_isdst = 0;
+	return result;
+}
diff --git a/src/time/localtime.c b/src/time/localtime.c
new file mode 100644
index 00000000..abd5e84d
--- /dev/null
+++ b/src/time/localtime.c
@@ -0,0 +1,12 @@
+#include <time.h>
+
+#include "__time.h"
+
+struct tm *localtime(const time_t *t)
+{
+	static struct tm tm;
+	__tzset();
+	__time_to_tm(*t - __timezone, &tm);
+	tm.tm_isdst = -1;
+	return __dst_adjust(&tm);
+}
diff --git a/src/time/localtime_r.c b/src/time/localtime_r.c
new file mode 100644
index 00000000..2bf10378
--- /dev/null
+++ b/src/time/localtime_r.c
@@ -0,0 +1,11 @@
+#include <time.h>
+
+#include "__time.h"
+
+struct tm *localtime_r(const time_t *t, struct tm *result)
+{
+	__tzset();
+	__time_to_tm(*t - __timezone, result);
+	result->tm_isdst = -1;
+	return __dst_adjust(result);
+}
diff --git a/src/time/mktime.c b/src/time/mktime.c
new file mode 100644
index 00000000..858cd50d
--- /dev/null
+++ b/src/time/mktime.c
@@ -0,0 +1,24 @@
+#include <time.h>
+
+#include "__time.h"
+
+time_t mktime(struct tm *tm)
+{
+	int isdst = tm->tm_isdst;
+	time_t t, lt;
+
+	__tzset();
+
+	tm->tm_sec += __timezone;
+	if (isdst > 0) tm->tm_sec += __dst_offset;
+
+	t = __tm_to_time(tm);
+	
+	lt = t - __timezone;
+	if (isdst > 0) lt -= __dst_offset;
+	__time_to_tm(lt, tm);
+
+	__dst_adjust(tm);
+	
+	return t;
+}
diff --git a/src/time/nanosleep.c b/src/time/nanosleep.c
new file mode 100644
index 00000000..5ac4c359
--- /dev/null
+++ b/src/time/nanosleep.c
@@ -0,0 +1,13 @@
+#include <unistd.h>
+#include <time.h>
+#include "syscall.h"
+#include "libc.h"
+
+int nanosleep(const struct timespec *req, struct timespec *rem)
+{
+	int ret;
+	CANCELPT_BEGIN;
+	ret = syscall2(__NR_nanosleep, (long)req, (long)rem);
+	CANCELPT_END;
+	return ret;
+}
diff --git a/src/time/strftime.c b/src/time/strftime.c
new file mode 100644
index 00000000..f1b94631
--- /dev/null
+++ b/src/time/strftime.c
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <langinfo.h>
+#include <time.h>
+#include "__time.h"
+
+// FIXME: integer overflows
+
+const char *__langinfo(nl_item);
+
+size_t strftime(char *s, size_t n, const char *f, const struct tm *tm)
+{
+	nl_item item;
+	int val;
+	const char *fmt;
+	size_t l;
+	for (l=0; *f && l<n; f++) {
+		if (*f == '%') {
+do_fmt:
+		switch (*++f) {
+		case '%':
+			goto literal;
+		case 'E':
+		case 'O':
+			goto do_fmt;
+		case 'a':
+			item = ABDAY_1 + tm->tm_wday;
+			goto nl_strcat;
+		case 'A':
+			item = DAY_1 + tm->tm_wday;
+			goto nl_strcat;
+		case 'h':
+		case 'b':
+			item = ABMON_1 + tm->tm_mon;
+			goto nl_strcat;
+		case 'B':
+			item = MON_1 + tm->tm_mon;
+			goto nl_strcat;
+		case 'c':
+			item = D_T_FMT;
+			goto nl_strftime;
+		case 'C':
+			val = (1900+tm->tm_year) / 100;
+			fmt = "%02d";
+			goto number;
+		case 'd':
+			val = tm->tm_mday;
+			fmt = "%02d";
+			goto number;
+		case 'D':
+			fmt = "%m/%d/%y";
+			goto recu_strftime;
+		case 'e':
+			val = tm->tm_mday;
+			fmt = "%2d";
+			goto number;
+		case 'F':
+			fmt = "%Y-%m-%d";
+			goto recu_strftime;
+		case 'g':
+			// FIXME
+			val = 0; //week_based_year(tm)%100;
+			fmt = "%02d";
+			goto number;
+		case 'G':
+			// FIXME
+			val = 0; //week_based_year(tm);
+			fmt = "%04d";
+			goto number;
+		case 'H':
+			val = tm->tm_hour;
+			fmt = "%02d";
+			goto number;
+		case 'I':
+			val = tm->tm_hour;
+			if (!val) val = 12;
+			else if (val > 12) val -= 12;
+			fmt = "%02d";
+			goto number;
+		case 'j':
+			val = tm->tm_yday+1;
+			fmt = "%03d";
+			goto number;
+		case 'm':
+			val = tm->tm_mon+1;
+			fmt = "%02d";
+			goto number;
+		case 'M':
+			val = tm->tm_min;
+			fmt = "%02d";
+			goto number;
+		case 'n':
+			s[l++] = '\n';
+			continue;
+		case 'p':
+			item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
+			goto nl_strcat;
+		case 'r':
+			item = T_FMT_AMPM;
+			goto nl_strftime;
+		case 'R':
+			fmt = "%H:%M";
+			goto recu_strftime;
+		case 'S':
+			val = tm->tm_sec;
+			fmt = "%02d";
+			goto number;
+		case 't':
+			s[l++] = '\t';
+			continue;
+		case 'T':
+			fmt = "%H:%M:%S";
+			goto recu_strftime;
+		case 'u':
+			val = tm->tm_wday ? tm->tm_wday : 7;
+			fmt = "%d";
+			goto number;
+		case 'U':
+		case 'V':
+		case 'W':
+			// FIXME: week number mess..
+			continue;
+		case 'w':
+			val = tm->tm_wday;
+			fmt = "%d";
+			goto number;
+		case 'x':
+			item = D_FMT;
+			goto nl_strftime;
+		case 'X':
+			item = T_FMT;
+			goto nl_strftime;
+		case 'y':
+			val = tm->tm_year % 100;
+			fmt = "%02d";
+			goto number;
+		case 'Y':
+			val = tm->tm_year + 1900;
+			fmt = "%04d";
+			goto number;
+		case 'z':
+			if (tm->tm_isdst < 0) continue;
+			val = -__timezone - (tm->tm_isdst ? __dst_offset : 0);
+			l += snprintf(s+l, n-l, "%+.2d%.2d", val/3600, abs(val%3600)/60);
+			continue;
+		case 'Z':
+			if (tm->tm_isdst < 0 || !__tzname[0] || !__tzname[0][0])
+				continue;
+			l += snprintf(s+l, n-l, "%s", __tzname[!!tm->tm_isdst]);
+			continue;
+		default:
+			return 0;
+		}
+		}
+literal:
+		s[l++] = *f;
+		continue;
+number:
+		l += snprintf(s+l, n-l, fmt, val);
+		continue;
+nl_strcat:
+		l += snprintf(s+l, n-l, "%s", __langinfo(item));
+		continue;
+nl_strftime:
+		fmt = __langinfo(item);
+recu_strftime:
+		l += strftime(s+l, n-l, fmt, tm);
+	}
+	if (l >= n) return 0;
+	s[l] = 0;
+	return l;
+}
diff --git a/src/time/strptime.c b/src/time/strptime.c
new file mode 100644
index 00000000..db72e610
--- /dev/null
+++ b/src/time/strptime.c
@@ -0,0 +1,178 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <langinfo.h>
+#include <time.h>
+
+const char *__langinfo(nl_item);
+
+char *strptime(const char *s, const char *f, struct tm *tm)
+{
+	return NULL;
+}
+
+#if 0
+
+char *strptime(const char *s, const char *f, struct tm *tm)
+{
+	nl_item item;
+	int *dest;
+	const char *fmt;
+	for (; *f; f++) {
+		if (isspace(*f)) goto whitespace;
+		if (*f == '%') {
+do_fmt:
+		switch (*++f) {
+		case '%':
+			goto literal;
+		case 'E':
+		case 'O':
+			goto do_fmt;
+		case 'a':
+			item = ABDAY_1 + tm->tm_wday;
+			goto nl_strcat;
+		case 'A':
+			item = DAY_1 + tm->tm_wday;
+			goto nl_strcat;
+		case 'h':
+		case 'b':
+			item = ABMON_1 + tm->tm_mon;
+			goto nl_strcat;
+		case 'B':
+			item = MON_1 + tm->tm_mon;
+			goto nl_strcat;
+		case 'c':
+			item = D_T_FMT;
+			goto nl_strftime;
+		case 'C':
+			val = (1900+tm->tm_year) / 100;
+			fmt = "%02d";
+			goto number;
+		case 'd':
+			val = tm->tm_mday;
+			fmt = "%02d";
+			goto number;
+		case 'D':
+			fmt = "%m/%d/%y";
+			goto recu_strftime;
+		case 'e':
+			val = tm->tm_mday;
+			fmt = "%2d";
+			goto number;
+		case 'F':
+			fmt = "%Y-%m-%d";
+			goto recu_strftime;
+		case 'g':
+			// FIXME
+			val = 0; //week_based_year(tm)%100;
+			fmt = "%02d";
+			goto number;
+		case 'G':
+			// FIXME
+			val = 0; //week_based_year(tm);
+			fmt = "%04d";
+			goto number;
+		case 'H':
+			val = tm->tm_hour;
+			fmt = "%02d";
+			goto number;
+		case 'I':
+			val = tm->tm_hour;
+			if (!val) val = 12;
+			else if (val > 12) val -= 12;
+			fmt = "%02d";
+			goto number;
+		case 'j':
+			val = tm->tm_yday+1;
+			fmt = "%03d";
+			goto number;
+		case 'm':
+			val = tm->tm_mon+1;
+			fmt = "%02d";
+			goto number;
+		case 'M':
+			val = tm->tm_min;
+			fmt = "%02d";
+			goto number;
+		case 'n':
+		case 't':
+			goto whitespace;
+		case 'p':
+			item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
+			goto nl_strcat;
+		case 'r':
+			item = T_FMT_AMPM;
+			goto nl_strftime;
+		case 'R':
+			fmt = "%H:%M";
+			goto recu_strftime;
+		case 'S':
+			val = tm->tm_sec;
+			fmt = "%02d";
+			goto number;
+		case 'T':
+			fmt = "%H:%M:%S";
+			goto recu_strftime;
+		case 'u':
+			val = tm->tm_wday ? tm->tm_wday : 7;
+			fmt = "%d";
+			goto number;
+		case 'U':
+		case 'V':
+		case 'W':
+			// FIXME: week number mess..
+			continue;
+		case 'w':
+			val = tm->tm_wday;
+			fmt = "%d";
+			goto number;
+		case 'x':
+			item = D_FMT;
+			goto nl_strftime;
+		case 'X':
+			item = T_FMT;
+			goto nl_strftime;
+		case 'y':
+			val = tm->tm_year % 100;
+			fmt = "%02d";
+			goto number;
+		case 'Y':
+			val = tm->tm_year + 1900;
+			fmt = "%04d";
+			goto number;
+		case 'z':
+			if (tm->tm_isdst < 0) continue;
+			val = timezone + (tm->tm_isdst) ? __dst_offset : 0;
+			l += snprintf(s+l, n-l, "%+02d%02d", val/60, abs(val%60));
+			continue;
+		case 'Z':
+			if (tm->tm_isdst < 0 || !tzname[0] || !tzname[0][0])
+				continue;
+			l += snprintf(s+l, n-l, "%s", tzname[!!tm->tm_isdst]);
+			continue;
+		}
+		default:
+			return NULL;
+		}
+literal:
+		if (*s++ != *f) return NULL;
+		continue;
+whitespace:
+		while(isspace(*s)) s++;
+		continue;
+number:
+		l += snprintf(s+l, n-l, fmt, val);
+		continue;
+nl_strcat:
+		l += snprintf(s+l, n-l, "%s", __langinfo(item));
+		continue;
+nl_strftime:
+		fmt = __langinfo(item);
+recu_strftime:
+		l += strftime(s+l, n-l, fmt, tm);
+	}
+	if (l >= n) return 0;
+	s[l] = 0;
+	return l;
+}
+
+#endif
diff --git a/src/time/time.c b/src/time/time.c
new file mode 100644
index 00000000..3457dade
--- /dev/null
+++ b/src/time/time.c
@@ -0,0 +1,12 @@
+#define SYSCALL_RETURN_ERRNO
+#include <time.h>
+#include <sys/time.h>
+#include "syscall.h"
+
+time_t time(time_t *t)
+{
+	struct timeval tv;
+	syscall2(__NR_gettimeofday, (long)&tv, 0);
+	if (t) *t = tv.tv_sec;
+	return tv.tv_sec;
+}
diff --git a/src/time/times.c b/src/time/times.c
new file mode 100644
index 00000000..e9b5a823
--- /dev/null
+++ b/src/time/times.c
@@ -0,0 +1,7 @@
+#include <sys/times.h>
+#include "syscall.h"
+
+clock_t times(struct tms *tms)
+{
+	return syscall1(__NR_times, (long)&tms);
+}
diff --git a/src/time/timezone.s b/src/time/timezone.s
new file mode 100644
index 00000000..4e167b0b
--- /dev/null
+++ b/src/time/timezone.s
@@ -0,0 +1,27 @@
+.data
+
+.global timezone
+.global __timezone
+.global daylight
+.global __daylight
+.global tzname
+.global __tzname
+
+__timezone:
+timezone:
+	.long 0
+.size timezone,.-timezone
+.size __timezone,.-__timezone
+
+__daylight:
+daylight:
+	.long 0
+.size daylight,.-daylight
+.size __daylight,.-__daylight
+
+__tzname:
+tzname:
+	.long 0
+	.long 0
+.size tzname,.-tzname
+.size __tzname,.-__tzname
diff --git a/src/time/tzset.c b/src/time/tzset.c
new file mode 100644
index 00000000..6d69957e
--- /dev/null
+++ b/src/time/tzset.c
@@ -0,0 +1,173 @@
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libc.h"
+
+#include "__time.h"
+
+long  __timezone = 0;
+int   __daylight = 0;
+char *__tzname[2] = { 0, 0 };
+int   __dst_offset = 0;
+
+weak_alias(__timezone, timezone);
+weak_alias(__daylight, daylight);
+weak_alias(__tzname, tzname);
+weak_alias(__dst_offset, dst_offset);
+
+static char std_name[TZNAME_MAX+1];
+static char dst_name[TZNAME_MAX+1];
+
+/* all elements are zero-based */
+static struct rule {
+	char month;
+	char week;
+	short day;
+	int time;
+} __dst_start, __dst_end;
+
+static void zname(char *d, char **s)
+{
+	int i;
+	for (i=0; i<TZNAME_MAX && isalpha(d[i]=**s); i++, (*s)++);
+	d[i] = 0;
+}
+
+static int hhmmss(char **s)
+{
+	int ofs = strtol(*s, s, 10)*3600;
+	if (ofs >= 0) {
+		if (**s == ':') ofs += strtol(*s+1, s, 10)*60;
+		if (**s == ':') ofs += strtol(*s+1, s, 10);
+	} else {
+		if (**s == ':') ofs -= strtol(*s+1, s, 10)*60;
+		if (**s == ':') ofs -= strtol(*s+1, s, 10);
+	}
+	return ofs;
+}
+
+static int dstrule(struct rule *rule, char **s)
+{
+	if (**s != ',') return -1;
+	switch (*++*s) {
+	case 'J':
+		rule->month = 'J';
+		rule->day = strtol(*s+1, s, 10)-1;
+		break;
+	case 'M':
+		rule->month = strtol(*s+1, s, 10)-1;
+		if (**s != '.' || rule->month < 0 || rule->month > 11)
+			return -1;
+		rule->week = strtol(*s+1, s, 10)-1;
+		if (**s != '.' || rule->week < 0 || rule->week > 4)
+			return -1;
+		rule->day = strtol(*s+1, s, 10);
+		if (rule->day < 0 || rule->day > 6)
+			return -1;
+		break;
+	default:
+		rule->month = 'L';
+		rule->day = strtol(*s+1, s, 10);
+		break;
+	}
+	if (**s == '/') {
+		(*s)++;
+		rule->time = hhmmss(s);
+	} else rule->time = 7200;
+	return 0;
+}
+
+void tzset(void)
+{
+	char *z, *a;
+	
+	strcpy(std_name, "GMT");
+	strcpy(dst_name, "GMT");
+	__tzname[0] = std_name;
+	__tzname[1] = dst_name;
+	__timezone = 0;
+	__daylight = 0;
+	
+	if (!(z = getenv("TZ")) || !isalpha(*z)) return;
+
+	zname(std_name, &z);
+	__timezone = hhmmss(&z);
+
+	zname(dst_name, &z);
+	if (dst_name[0]) __daylight=1;
+	a = z;
+	__dst_offset = hhmmss(&z) - __timezone;
+	if (z==a) __dst_offset = -3600;
+
+	if (dstrule(&__dst_start, &z) || dstrule(&__dst_end, &z))
+		__daylight = 0;
+}
+
+void __tzset(void)
+{
+	static int lock, init;
+	if (init) return;
+	LOCK(&lock);
+	if (!init) tzset();
+	init=1;
+	UNLOCK(&lock);
+}
+
+static int is_leap(int year)
+{
+	year -= 100;
+	return !(year&3) && ((year%100) || !(year%400));
+}
+
+static int cutoff_yday(struct tm *tm, struct rule *rule)
+{
+	static const char days_in_month[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+	static const int first_day[] = {0,31,59,90,120,151,181,212,243,273,304,335};
+	int yday, mday, leap;
+	
+	switch (rule->month) {
+	case 'J':
+		return rule->day + (tm->tm_mon > 1 && is_leap(tm->tm_year));
+	case 'L':
+		return rule->day;
+	default:
+		yday = first_day[rule->month];
+		leap = is_leap(tm->tm_year);
+		if (rule->month > 1 && leap) yday++;
+		mday = (rule->day - (yday + tm->tm_wday - tm->tm_yday) + 1400)%7 + 7*rule->week;
+		if (mday >= days_in_month[rule->month] + (leap && rule->month == 1))
+			mday -= 7;
+		return mday + yday;
+	}
+}
+
+struct tm *__dst_adjust(struct tm *tm)
+{
+	time_t t;
+	int start, end, secs;
+	int after_start, before_end;
+
+	if (tm->tm_isdst >= 0) return tm;
+	if (!__daylight) {
+		tm->tm_isdst = 0;
+		return tm;
+	}
+	
+	secs = tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec;
+	start = cutoff_yday(tm, &__dst_start);
+	end = cutoff_yday(tm, &__dst_end);
+
+	after_start = (tm->tm_yday > start || (tm->tm_yday == start && secs >= __dst_start.time));
+	before_end = (tm->tm_yday < end || (tm->tm_yday == end && secs < __dst_end.time));
+
+	if ((after_start && before_end) || ((end < start) && (after_start || before_end))) {
+		tm->tm_sec -= __dst_offset;
+		tm->tm_isdst = 1;
+		t = __tm_to_time(tm);
+		return __time_to_tm(t, tm);
+	} else tm->tm_isdst = 0;
+
+	return tm;
+}
diff --git a/src/time/utime.c b/src/time/utime.c
new file mode 100644
index 00000000..56e9e13a
--- /dev/null
+++ b/src/time/utime.c
@@ -0,0 +1,12 @@
+#include <utime.h>
+#include "syscall.h"
+
+int utime(const char *path, const struct utimbuf *times)
+{
+	long ktimes[2];
+	if (times) {
+		ktimes[0] = times->actime;
+		ktimes[1] = times->modtime;
+	}
+	return syscall2(__NR_utime, (long)path, times ? (long)ktimes : 0);
+}
diff --git a/src/unistd/_exit.c b/src/unistd/_exit.c
new file mode 100644
index 00000000..d2e84c4c
--- /dev/null
+++ b/src/unistd/_exit.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <stdlib.h>
+
+void _exit(int status)
+{
+	_Exit(status);
+}
diff --git a/src/unistd/access.c b/src/unistd/access.c
new file mode 100644
index 00000000..2c10e58c
--- /dev/null
+++ b/src/unistd/access.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int access(const char *filename, int amode)
+{
+	return syscall2(__NR_access, (long)filename, amode);
+}
diff --git a/src/unistd/alarm.c b/src/unistd/alarm.c
new file mode 100644
index 00000000..bba444d8
--- /dev/null
+++ b/src/unistd/alarm.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+unsigned alarm(unsigned seconds)
+{
+	return syscall1(__NR_alarm, seconds);
+}
diff --git a/src/unistd/chdir.c b/src/unistd/chdir.c
new file mode 100644
index 00000000..c89bda38
--- /dev/null
+++ b/src/unistd/chdir.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int chdir(const char *path)
+{
+	return syscall1(__NR_chdir, (long)path);
+}
diff --git a/src/unistd/chown.c b/src/unistd/chown.c
new file mode 100644
index 00000000..6069a2fe
--- /dev/null
+++ b/src/unistd/chown.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int chown(const char *path, uid_t uid, gid_t gid)
+{
+	return syscall3(__NR_chown32, (long)path, uid, gid);
+}
diff --git a/src/unistd/close.c b/src/unistd/close.c
new file mode 100644
index 00000000..97302f67
--- /dev/null
+++ b/src/unistd/close.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int close(int fd)
+{
+	int ret = __syscall_close(fd);
+	CANCELPT_BEGIN;
+	CANCELPT_END;
+	return ret;
+}
diff --git a/src/unistd/confstr.c b/src/unistd/confstr.c
new file mode 100644
index 00000000..4332f726
--- /dev/null
+++ b/src/unistd/confstr.c
@@ -0,0 +1,17 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+size_t confstr(int name, char *buf, size_t len)
+{
+	const char *s = "";
+	if (!name) {
+		s = "/bin:/usr/bin";
+	} else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>31U) {
+		errno = EINVAL;
+		return 0;
+	}
+	// snprintf is overkill but avoid wasting code size to implement
+	// this completely useless function and its truncation semantics
+	return snprintf(buf, len, "%s", s);
+}
diff --git a/src/unistd/ctermid.c b/src/unistd/ctermid.c
new file mode 100644
index 00000000..21b44ec8
--- /dev/null
+++ b/src/unistd/ctermid.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+
+char *ctermid(char *s)
+{
+	static char *s2;
+	int fd;
+	if (!s) {
+		if (!s2) s2 = malloc(L_ctermid);
+		s = s2;
+	}
+	fd = open("/dev/tty", O_WRONLY | O_NOCTTY);
+	if (fd < 0)
+		return strcpy(s, "");
+	if (ttyname_r(fd, s, L_ctermid))
+		strcpy(s, "");
+	close(fd);
+	return s;
+}
diff --git a/src/unistd/dup.c b/src/unistd/dup.c
new file mode 100644
index 00000000..b11cd715
--- /dev/null
+++ b/src/unistd/dup.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int dup(int fd)
+{
+	return syscall1(__NR_dup, fd);
+}
diff --git a/src/unistd/dup2.c b/src/unistd/dup2.c
new file mode 100644
index 00000000..93325446
--- /dev/null
+++ b/src/unistd/dup2.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int dup2(int old, int new)
+{
+	return __syscall_dup2(old, new);
+}
diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c
new file mode 100644
index 00000000..99a93785
--- /dev/null
+++ b/src/unistd/faccessat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int faccessat(int fd, const char *filename, int amode, int flag)
+{
+	return syscall4(__NR_faccessat, fd, (long)filename, amode, flag);
+}
diff --git a/src/unistd/fchdir.c b/src/unistd/fchdir.c
new file mode 100644
index 00000000..b2acbc29
--- /dev/null
+++ b/src/unistd/fchdir.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int fchdir(int fd)
+{
+	return syscall1(__NR_fchdir, fd);
+}
diff --git a/src/unistd/fchown.c b/src/unistd/fchown.c
new file mode 100644
index 00000000..990f006d
--- /dev/null
+++ b/src/unistd/fchown.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int fchown(int fd, uid_t uid, gid_t gid)
+{
+	return syscall3(__NR_fchown32, fd, uid, gid);
+}
diff --git a/src/unistd/fchownat.c b/src/unistd/fchownat.c
new file mode 100644
index 00000000..70626428
--- /dev/null
+++ b/src/unistd/fchownat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag)
+{
+	return syscall5(__NR_fchownat, fd, (long)path, uid, gid, flag);
+}
diff --git a/src/unistd/fdatasync.c b/src/unistd/fdatasync.c
new file mode 100644
index 00000000..ef7c9a9d
--- /dev/null
+++ b/src/unistd/fdatasync.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int fdatasync(int fd)
+{
+	return 0;
+}
diff --git a/src/unistd/fsync.c b/src/unistd/fsync.c
new file mode 100644
index 00000000..7cfedc98
--- /dev/null
+++ b/src/unistd/fsync.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int fsync(int fd)
+{
+	//return syscall1(__NR_fsync, fd);
+	return 0;
+}
diff --git a/src/unistd/ftruncate.c b/src/unistd/ftruncate.c
new file mode 100644
index 00000000..e0b2f4bb
--- /dev/null
+++ b/src/unistd/ftruncate.c
@@ -0,0 +1,15 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int ftruncate(int fd, off_t length)
+{
+	if (sizeof(long) == 8)
+		return syscall2(__NR_ftruncate, fd, length);
+	else {
+		union { long long ll; long l[2]; } u = { length };
+		return syscall3(__NR_ftruncate64, fd, u.l[0], u.l[1]);
+	}
+}
+
+LFS64(ftruncate);
diff --git a/src/unistd/getcwd.c b/src/unistd/getcwd.c
new file mode 100644
index 00000000..4910f42c
--- /dev/null
+++ b/src/unistd/getcwd.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <errno.h>
+#include "syscall.h"
+
+char *getcwd(char *buf, size_t size)
+{
+	return syscall2(__NR_getcwd, (long)buf, size) < 0 ? NULL : buf;
+}
diff --git a/src/unistd/getegid.c b/src/unistd/getegid.c
new file mode 100644
index 00000000..0e626b75
--- /dev/null
+++ b/src/unistd/getegid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+gid_t getegid(void)
+{
+	return syscall0(__NR_getegid32);
+}
diff --git a/src/unistd/geteuid.c b/src/unistd/geteuid.c
new file mode 100644
index 00000000..39d6ac7b
--- /dev/null
+++ b/src/unistd/geteuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+uid_t geteuid(void)
+{
+	return syscall0(__NR_geteuid32);
+}
diff --git a/src/unistd/getgid.c b/src/unistd/getgid.c
new file mode 100644
index 00000000..186635a2
--- /dev/null
+++ b/src/unistd/getgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+gid_t getgid(void)
+{
+	return syscall0(__NR_getgid32);
+}
diff --git a/src/unistd/getgroups.c b/src/unistd/getgroups.c
new file mode 100644
index 00000000..6f19870e
--- /dev/null
+++ b/src/unistd/getgroups.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int getgroups(int count, gid_t list[])
+{
+	/* this depends on our gid_t being 32bit */
+	return syscall2(__NR_getgroups32, count, (long)list);
+}
diff --git a/src/unistd/gethostname.c b/src/unistd/gethostname.c
new file mode 100644
index 00000000..a406c4eb
--- /dev/null
+++ b/src/unistd/gethostname.c
@@ -0,0 +1,14 @@
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <string.h>
+
+int gethostname(char *name, size_t len)
+{
+	size_t i;
+	struct utsname uts;
+	if (uname(&uts)) return -1;
+	if (len > sizeof uts.nodename) len = sizeof uts.nodename;
+	for (i=0; i<len && (name[i] = uts.nodename[i]); i++);
+	if (i==len) name[i-1] = 0;
+	return 0;
+}
diff --git a/src/unistd/getlogin.c b/src/unistd/getlogin.c
new file mode 100644
index 00000000..06011913
--- /dev/null
+++ b/src/unistd/getlogin.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <stdlib.h>
+
+char *getlogin(void)
+{
+	return getenv("LOGNAME");
+}
diff --git a/src/unistd/getlogin_r.c b/src/unistd/getlogin_r.c
new file mode 100644
index 00000000..f04f71e5
--- /dev/null
+++ b/src/unistd/getlogin_r.c
@@ -0,0 +1,13 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+int getlogin_r(char *name, size_t size)
+{
+	char *logname = getlogin();
+	if (!logname) return ENXIO; /* or...? */
+	if (strlen(name) >= size) return ERANGE;
+	strcpy(name, logname);
+	return 0;
+}
diff --git a/src/unistd/getpgid.c b/src/unistd/getpgid.c
new file mode 100644
index 00000000..50d716b5
--- /dev/null
+++ b/src/unistd/getpgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t getpgid(pid_t pid)
+{
+	return syscall1(__NR_getpgid, pid);
+}
diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c
new file mode 100644
index 00000000..2004630a
--- /dev/null
+++ b/src/unistd/getpgrp.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t getpgrp(void)
+{
+	return syscall0(__NR_getpgrp);
+}
diff --git a/src/unistd/getpid.c b/src/unistd/getpid.c
new file mode 100644
index 00000000..31cbe1cb
--- /dev/null
+++ b/src/unistd/getpid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t getpid(void)
+{
+	return syscall0(__NR_getpid);
+}
diff --git a/src/unistd/getppid.c b/src/unistd/getppid.c
new file mode 100644
index 00000000..a3241829
--- /dev/null
+++ b/src/unistd/getppid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t getppid(void)
+{
+	return syscall0(__NR_getppid);
+}
diff --git a/src/unistd/getsid.c b/src/unistd/getsid.c
new file mode 100644
index 00000000..064229cf
--- /dev/null
+++ b/src/unistd/getsid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t getsid(pid_t pid)
+{
+	return syscall1(__NR_getsid, pid);
+}
diff --git a/src/unistd/getuid.c b/src/unistd/getuid.c
new file mode 100644
index 00000000..9d4e53f5
--- /dev/null
+++ b/src/unistd/getuid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+uid_t getuid(void)
+{
+	return syscall0(__NR_getuid32);
+}
diff --git a/src/unistd/isatty.c b/src/unistd/isatty.c
new file mode 100644
index 00000000..cff6e9fe
--- /dev/null
+++ b/src/unistd/isatty.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <termios.h>
+
+int isatty(int fd)
+{
+	struct termios t;
+	return tcgetattr(fd, &t) == 0;
+}
diff --git a/src/unistd/lchown.c b/src/unistd/lchown.c
new file mode 100644
index 00000000..30e83916
--- /dev/null
+++ b/src/unistd/lchown.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int lchown(const char *path, uid_t uid, gid_t gid)
+{
+	return syscall3(__NR_lchown32, (long)path, uid, gid);
+}
diff --git a/src/unistd/link.c b/src/unistd/link.c
new file mode 100644
index 00000000..f121bb9e
--- /dev/null
+++ b/src/unistd/link.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int link(const char *existing, const char *new)
+{
+	return syscall2(__NR_link, (long)existing, (long)new);
+}
diff --git a/src/unistd/linkat.c b/src/unistd/linkat.c
new file mode 100644
index 00000000..0eb51221
--- /dev/null
+++ b/src/unistd/linkat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int linkat(int fd1, const char *existing, int fd2, const char *new, int flag)
+{
+	return syscall5(__NR_linkat, fd1, (long)existing, fd2, (long)new, flag);
+}
diff --git a/src/unistd/lseek.c b/src/unistd/lseek.c
new file mode 100644
index 00000000..0dab2679
--- /dev/null
+++ b/src/unistd/lseek.c
@@ -0,0 +1,16 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+	/* optimized away at compiletime */
+	if (sizeof(long) == 8)
+		return syscall3(__NR_lseek, fd, offset, whence);
+	else {
+		off_t result;
+		return syscall5(__NR__llseek, fd, offset>>32, offset, (long)&result, whence) ? -1 : result;
+	}
+}
+
+LFS64(lseek);
diff --git a/src/unistd/nice.c b/src/unistd/nice.c
new file mode 100644
index 00000000..4b28ef41
--- /dev/null
+++ b/src/unistd/nice.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int nice(int inc)
+{
+	return syscall1(__NR_nice, inc);
+}
diff --git a/src/unistd/pause.c b/src/unistd/pause.c
new file mode 100644
index 00000000..14720651
--- /dev/null
+++ b/src/unistd/pause.c
@@ -0,0 +1,12 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int pause(void)
+{
+	int r;
+	CANCELPT_BEGIN;
+	r = syscall0(__NR_pause);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/unistd/pipe.c b/src/unistd/pipe.c
new file mode 100644
index 00000000..2dfc9c99
--- /dev/null
+++ b/src/unistd/pipe.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int pipe(int fd[2])
+{
+	return syscall1(__NR_pipe, (long)fd);
+}
diff --git a/src/unistd/pread.c b/src/unistd/pread.c
new file mode 100644
index 00000000..029ba3d1
--- /dev/null
+++ b/src/unistd/pread.c
@@ -0,0 +1,14 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+ssize_t pread(int fd, void *buf, size_t size, off_t ofs)
+{
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall5(__NR_pread64, fd, (long)buf, size, SYSCALL_LL(ofs));
+	CANCELPT_END;
+	return r;
+}
+
+LFS64(pread);
diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c
new file mode 100644
index 00000000..8f23d1b9
--- /dev/null
+++ b/src/unistd/pwrite.c
@@ -0,0 +1,14 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs)
+{
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall5(__NR_pwrite64, fd, (long)buf, size, SYSCALL_LL(ofs));
+	CANCELPT_END;
+	return r;
+}
+
+LFS64(pwrite);
diff --git a/src/unistd/read.c b/src/unistd/read.c
new file mode 100644
index 00000000..87ff1f10
--- /dev/null
+++ b/src/unistd/read.c
@@ -0,0 +1,12 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+ssize_t read(int fd, void *buf, size_t count)
+{
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = __syscall_read(fd, buf, count);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/unistd/readlink.c b/src/unistd/readlink.c
new file mode 100644
index 00000000..f6b1635c
--- /dev/null
+++ b/src/unistd/readlink.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int readlink(const char *path, char *buf, size_t bufsize)
+{
+	return syscall3(__NR_readlink, (long)path, (long)buf, bufsize);
+}
diff --git a/src/unistd/readlinkat.c b/src/unistd/readlinkat.c
new file mode 100644
index 00000000..8171050d
--- /dev/null
+++ b/src/unistd/readlinkat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int readlinkat(int fd, const char *path, char *buf, size_t bufsize)
+{
+	return syscall4(__NR_readlinkat, fd, (long)path, (long)buf, bufsize);
+}
diff --git a/src/unistd/readv.c b/src/unistd/readv.c
new file mode 100644
index 00000000..e311f9de
--- /dev/null
+++ b/src/unistd/readv.c
@@ -0,0 +1,12 @@
+#include <sys/uio.h>
+#include "syscall.h"
+#include "libc.h"
+
+ssize_t readv(int fd, const struct iovec *iov, int count)
+{
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall3(__NR_readv, fd, (long)iov, count);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/unistd/renameat.c b/src/unistd/renameat.c
new file mode 100644
index 00000000..0dae9f11
--- /dev/null
+++ b/src/unistd/renameat.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "syscall.h"
+
+int renameat(int oldfd, const char *old, int newfd, const char *new)
+{
+	return syscall4(__NR_renameat, oldfd, (long)old, newfd, (long)new);
+}
diff --git a/src/unistd/rmdir.c b/src/unistd/rmdir.c
new file mode 100644
index 00000000..8e18c7a8
--- /dev/null
+++ b/src/unistd/rmdir.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int rmdir(const char *path)
+{
+	return syscall1(__NR_rmdir, (long)path);
+}
diff --git a/src/unistd/setegid.c b/src/unistd/setegid.c
new file mode 100644
index 00000000..85348842
--- /dev/null
+++ b/src/unistd/setegid.c
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+int setegid(gid_t egid)
+{
+	return setregid(-1, egid);
+}
diff --git a/src/unistd/seteuid.c b/src/unistd/seteuid.c
new file mode 100644
index 00000000..0aaa86e0
--- /dev/null
+++ b/src/unistd/seteuid.c
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+int seteuid(uid_t euid)
+{
+	return setreuid(-1, euid);
+}
diff --git a/src/unistd/setgid.c b/src/unistd/setgid.c
new file mode 100644
index 00000000..00c7a03a
--- /dev/null
+++ b/src/unistd/setgid.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int setgid(gid_t gid)
+{
+	if (libc.rsyscall) return libc.rsyscall(__NR_setgid32, gid, 0, 0, 0, 0, 0);
+	return syscall1(__NR_setgid32, gid);
+}
diff --git a/src/unistd/setpgid.c b/src/unistd/setpgid.c
new file mode 100644
index 00000000..748d2907
--- /dev/null
+++ b/src/unistd/setpgid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t setpgid(pid_t pid, pid_t pgid)
+{
+	return syscall2(__NR_setpgid, pid, pgid);
+}
diff --git a/src/unistd/setpgrp.c b/src/unistd/setpgrp.c
new file mode 100644
index 00000000..a2a37f65
--- /dev/null
+++ b/src/unistd/setpgrp.c
@@ -0,0 +1,6 @@
+#include <unistd.h>
+
+pid_t setpgrp(void)
+{
+	return setpgid(0, 0);
+}
diff --git a/src/unistd/setregid.c b/src/unistd/setregid.c
new file mode 100644
index 00000000..d25dab76
--- /dev/null
+++ b/src/unistd/setregid.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int setregid(gid_t rgid, gid_t egid)
+{
+	if (libc.rsyscall) return libc.rsyscall(__NR_setregid32, rgid, egid, 0, 0, 0, 0);
+	return syscall2(__NR_setregid32, rgid, egid);
+}
diff --git a/src/unistd/setreuid.c b/src/unistd/setreuid.c
new file mode 100644
index 00000000..0ba2277b
--- /dev/null
+++ b/src/unistd/setreuid.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int setreuid(uid_t ruid, uid_t euid)
+{
+	if (libc.rsyscall) return libc.rsyscall(__NR_setreuid32, ruid, euid, 0, 0, 0, 0);
+	return syscall2(__NR_setreuid32, ruid, euid);
+}
diff --git a/src/unistd/setsid.c b/src/unistd/setsid.c
new file mode 100644
index 00000000..e2c5690c
--- /dev/null
+++ b/src/unistd/setsid.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+pid_t setsid(void)
+{
+	return syscall0(__NR_setsid);
+}
diff --git a/src/unistd/setuid.c b/src/unistd/setuid.c
new file mode 100644
index 00000000..53b74d88
--- /dev/null
+++ b/src/unistd/setuid.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int setuid(uid_t uid)
+{
+	if (libc.rsyscall) return libc.rsyscall(__NR_setuid32, uid, 0, 0, 0, 0, 0);
+	return syscall1(__NR_setuid32, uid);
+}
diff --git a/src/unistd/sleep.c b/src/unistd/sleep.c
new file mode 100644
index 00000000..d6450941
--- /dev/null
+++ b/src/unistd/sleep.c
@@ -0,0 +1,10 @@
+#include <unistd.h>
+#include <time.h>
+
+unsigned sleep(unsigned seconds)
+{
+	struct timespec tv = { .tv_sec = seconds, .tv_nsec = 0 };
+	if (nanosleep(&tv, &tv))
+		return tv.tv_sec;
+	return 0;
+}
diff --git a/src/unistd/symlink.c b/src/unistd/symlink.c
new file mode 100644
index 00000000..8d380d85
--- /dev/null
+++ b/src/unistd/symlink.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int symlink(const char *existing, const char *new)
+{
+	return syscall2(__NR_symlink, (long)existing, (long)new);
+}
diff --git a/src/unistd/symlinkat.c b/src/unistd/symlinkat.c
new file mode 100644
index 00000000..9693b226
--- /dev/null
+++ b/src/unistd/symlinkat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int symlinkat(const char *existing, int fd, const char *new)
+{
+	return syscall3(__NR_symlinkat, (long)existing, fd, (long)new);
+}
diff --git a/src/unistd/sync.c b/src/unistd/sync.c
new file mode 100644
index 00000000..a49808fd
--- /dev/null
+++ b/src/unistd/sync.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+void sync(void)
+{
+	syscall0(__NR_sync);
+}
diff --git a/src/unistd/tcgetpgrp.c b/src/unistd/tcgetpgrp.c
new file mode 100644
index 00000000..50080c7e
--- /dev/null
+++ b/src/unistd/tcgetpgrp.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+pid_t tcgetpgrp(int fd)
+{
+	int pgrp;
+	if (ioctl(fd, TIOCGPGRP, &pgrp) < 0)
+		return -1;
+	return pgrp;
+}
diff --git a/src/unistd/tcsetpgrp.c b/src/unistd/tcsetpgrp.c
new file mode 100644
index 00000000..67c38cb4
--- /dev/null
+++ b/src/unistd/tcsetpgrp.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+int tcsetpgrp(int fd, pid_t pgrp)
+{
+	int pgrp_int = pgrp;
+	return ioctl(fd, TIOCSPGRP, &pgrp_int);
+}
diff --git a/src/unistd/truncate.c b/src/unistd/truncate.c
new file mode 100644
index 00000000..f75e824e
--- /dev/null
+++ b/src/unistd/truncate.c
@@ -0,0 +1,15 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+int truncate(const char *path, off_t length)
+{
+	if (sizeof(long) == 8)
+		return syscall2(__NR_truncate, (long)path, length);
+	else {
+		union { long long ll; long l[2]; } u = { length };
+		return syscall3(__NR_truncate64, (long)path, u.l[0], u.l[1]);
+	}
+}
+
+LFS64(truncate);
diff --git a/src/unistd/ttyname.c b/src/unistd/ttyname.c
new file mode 100644
index 00000000..0f3e1141
--- /dev/null
+++ b/src/unistd/ttyname.c
@@ -0,0 +1,14 @@
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+char *ttyname(int fd)
+{
+	static char buf[TTY_NAME_MAX];
+	int result;
+	if ((result = ttyname_r(fd, buf, sizeof buf))) {
+		errno = result;
+		return NULL;
+	}
+	return buf;
+}
diff --git a/src/unistd/ttyname_r.c b/src/unistd/ttyname_r.c
new file mode 100644
index 00000000..f86fbd9c
--- /dev/null
+++ b/src/unistd/ttyname_r.c
@@ -0,0 +1,19 @@
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+int ttyname_r(int fd, char *name, size_t size)
+{
+	char procname[sizeof "/proc/self/fd/" + 3*sizeof(int) + 2];
+	ssize_t l;
+
+	if (!isatty(fd)) return ENOTTY;
+
+	snprintf(procname, sizeof procname, "/proc/self/fd/%d", fd);
+	l = readlink(procname, name, size);
+
+	if (l < 0) return errno;
+	else if (l == size) return ERANGE;
+	else return 0;
+}
diff --git a/src/unistd/ualarm.c b/src/unistd/ualarm.c
new file mode 100644
index 00000000..be853035
--- /dev/null
+++ b/src/unistd/ualarm.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include "syscall.h"
+
+/* FIXME: ?? */
+useconds_t ualarm(useconds_t useconds, useconds_t interval)
+{
+	return -1;
+}
diff --git a/src/unistd/unlink.c b/src/unistd/unlink.c
new file mode 100644
index 00000000..fb577920
--- /dev/null
+++ b/src/unistd/unlink.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int unlink(const char *path)
+{
+	return __syscall_unlink(path);
+}
diff --git a/src/unistd/unlinkat.c b/src/unistd/unlinkat.c
new file mode 100644
index 00000000..47fccc17
--- /dev/null
+++ b/src/unistd/unlinkat.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int unlinkat(int fd, const char *path, int flag)
+{
+	return syscall3(__NR_unlinkat, fd, (long)path, flag);
+}
diff --git a/src/unistd/usleep.c b/src/unistd/usleep.c
new file mode 100644
index 00000000..e3869017
--- /dev/null
+++ b/src/unistd/usleep.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <time.h>
+
+int usleep(useconds_t useconds)
+{
+	struct timespec tv = {
+		.tv_sec = useconds/1000000,
+		.tv_nsec = (useconds%1000000)*1000
+	};
+	return nanosleep(&tv, &tv);
+}
diff --git a/src/unistd/write.c b/src/unistd/write.c
new file mode 100644
index 00000000..426cfc5b
--- /dev/null
+++ b/src/unistd/write.c
@@ -0,0 +1,12 @@
+#include <unistd.h>
+#include "syscall.h"
+#include "libc.h"
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+	int r;
+	CANCELPT_BEGIN;
+	r = __syscall_write(fd, buf, count);
+	CANCELPT_END;
+	return r;
+}
diff --git a/src/unistd/writev.c b/src/unistd/writev.c
new file mode 100644
index 00000000..a6a118af
--- /dev/null
+++ b/src/unistd/writev.c
@@ -0,0 +1,12 @@
+#include <sys/uio.h>
+#include "syscall.h"
+#include "libc.h"
+
+ssize_t writev(int fd, const struct iovec *iov, int count)
+{
+	ssize_t r;
+	CANCELPT_BEGIN;
+	r = syscall3(__NR_writev, fd, (long)iov, count);
+	CANCELPT_END;
+	return r;
+}