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.
+ *