summaryrefslogtreecommitdiff
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
initial check-in, version 0.5.0v0.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;
+}