summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/ap
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/ape/lib/ap
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/ape/lib/ap')
-rwxr-xr-xsys/src/ape/lib/ap/386/cycles.s8
-rwxr-xr-xsys/src/ape/lib/ap/386/lock.c26
-rwxr-xr-xsys/src/ape/lib/ap/386/main9.s13
-rwxr-xr-xsys/src/ape/lib/ap/386/main9p.s46
-rwxr-xr-xsys/src/ape/lib/ap/386/memchr.s23
-rwxr-xr-xsys/src/ape/lib/ap/386/memcmp.s47
-rwxr-xr-xsys/src/ape/lib/ap/386/memcpy.s57
-rwxr-xr-xsys/src/ape/lib/ap/386/memmove.s57
-rwxr-xr-xsys/src/ape/lib/ap/386/memset.s35
-rwxr-xr-xsys/src/ape/lib/ap/386/mkfile27
-rwxr-xr-xsys/src/ape/lib/ap/386/notetramp.c72
-rwxr-xr-xsys/src/ape/lib/ap/386/setjmp.s29
-rwxr-xr-xsys/src/ape/lib/ap/386/strcat.s43
-rwxr-xr-xsys/src/ape/lib/ap/386/strchr.s38
-rwxr-xr-xsys/src/ape/lib/ap/386/strcpy.s35
-rwxr-xr-xsys/src/ape/lib/ap/386/strlen.s16
-rwxr-xr-xsys/src/ape/lib/ap/386/tas.s6
-rwxr-xr-xsys/src/ape/lib/ap/386/vlop.s44
-rwxr-xr-xsys/src/ape/lib/ap/386/vlrt.c695
-rwxr-xr-xsys/src/ape/lib/ap/68020/cycles.c5
-rwxr-xr-xsys/src/ape/lib/ap/68020/lock.c26
-rwxr-xr-xsys/src/ape/lib/ap/68020/main9.s9
-rwxr-xr-xsys/src/ape/lib/ap/68020/main9p.s43
-rwxr-xr-xsys/src/ape/lib/ap/68020/memchr.s15
-rwxr-xr-xsys/src/ape/lib/ap/68020/memcmp.s18
-rwxr-xr-xsys/src/ape/lib/ap/68020/memcpy.s98
-rwxr-xr-xsys/src/ape/lib/ap/68020/memmove.s99
-rwxr-xr-xsys/src/ape/lib/ap/68020/memset.s47
-rwxr-xr-xsys/src/ape/lib/ap/68020/mkfile28
-rwxr-xr-xsys/src/ape/lib/ap/68020/notetramp.c72
-rwxr-xr-xsys/src/ape/lib/ap/68020/setjmp.s26
-rwxr-xr-xsys/src/ape/lib/ap/68020/strcat.s15
-rwxr-xr-xsys/src/ape/lib/ap/68020/strchr.s27
-rwxr-xr-xsys/src/ape/lib/ap/68020/strcmp.s20
-rwxr-xr-xsys/src/ape/lib/ap/68020/strcpy.s10
-rwxr-xr-xsys/src/ape/lib/ap/68020/strlen.s18
-rwxr-xr-xsys/src/ape/lib/ap/68020/tas.s9
-rwxr-xr-xsys/src/ape/lib/ap/68020/vlop.s23
-rwxr-xr-xsys/src/ape/lib/ap/68020/vlrt.c730
-rwxr-xr-xsys/src/ape/lib/ap/alpha/_seek.c12
-rwxr-xr-xsys/src/ape/lib/ap/alpha/cycles.c5
-rwxr-xr-xsys/src/ape/lib/ap/alpha/divl.s189
-rwxr-xr-xsys/src/ape/lib/ap/alpha/divq.s191
-rwxr-xr-xsys/src/ape/lib/ap/alpha/getfcr.s33
-rwxr-xr-xsys/src/ape/lib/ap/alpha/lock.c26
-rwxr-xr-xsys/src/ape/lib/ap/alpha/main9.s15
-rwxr-xr-xsys/src/ape/lib/ap/alpha/main9p.s48
-rwxr-xr-xsys/src/ape/lib/ap/alpha/memcpy.c7
-rwxr-xr-xsys/src/ape/lib/ap/alpha/memmove.s197
-rwxr-xr-xsys/src/ape/lib/ap/alpha/memset.s61
-rwxr-xr-xsys/src/ape/lib/ap/alpha/mkfile23
-rwxr-xr-xsys/src/ape/lib/ap/alpha/notetramp.c72
-rwxr-xr-xsys/src/ape/lib/ap/alpha/setjmp.s24
-rwxr-xr-xsys/src/ape/lib/ap/alpha/tas.s10
-rwxr-xr-xsys/src/ape/lib/ap/arm/cycles.c5
-rwxr-xr-xsys/src/ape/lib/ap/arm/div.s118
-rwxr-xr-xsys/src/ape/lib/ap/arm/getfcr.s16
-rwxr-xr-xsys/src/ape/lib/ap/arm/lock.c26
-rwxr-xr-xsys/src/ape/lib/ap/arm/main9.s17
-rwxr-xr-xsys/src/ape/lib/ap/arm/main9p.s52
-rwxr-xr-xsys/src/ape/lib/ap/arm/memmove.s212
-rwxr-xr-xsys/src/ape/lib/ap/arm/memset.s60
-rwxr-xr-xsys/src/ape/lib/ap/arm/mkfile25
-rwxr-xr-xsys/src/ape/lib/ap/arm/notetramp.c72
-rwxr-xr-xsys/src/ape/lib/ap/arm/setjmp.s29
-rwxr-xr-xsys/src/ape/lib/ap/arm/strchr.s56
-rwxr-xr-xsys/src/ape/lib/ap/arm/strcmp.s67
-rwxr-xr-xsys/src/ape/lib/ap/arm/strcpy.s46
-rwxr-xr-xsys/src/ape/lib/ap/arm/tas.s5
-rwxr-xr-xsys/src/ape/lib/ap/arm/vlop.s13
-rwxr-xr-xsys/src/ape/lib/ap/arm/vlrt.c708
-rwxr-xr-xsys/src/ape/lib/ap/extraobjs37
-rwxr-xr-xsys/src/ape/lib/ap/gen/_assert.c18
-rwxr-xr-xsys/src/ape/lib/ap/gen/abort.c9
-rwxr-xr-xsys/src/ape/lib/ap/gen/abs.c17
-rwxr-xr-xsys/src/ape/lib/ap/gen/atof.c7
-rwxr-xr-xsys/src/ape/lib/ap/gen/atoi.c7
-rwxr-xr-xsys/src/ape/lib/ap/gen/atol.c7
-rwxr-xr-xsys/src/ape/lib/ap/gen/atoll.c7
-rwxr-xr-xsys/src/ape/lib/ap/gen/bsearch.c24
-rwxr-xr-xsys/src/ape/lib/ap/gen/calloc.c13
-rwxr-xr-xsys/src/ape/lib/ap/gen/clock.c12
-rwxr-xr-xsys/src/ape/lib/ap/gen/ctype.c56
-rwxr-xr-xsys/src/ape/lib/ap/gen/difftime.c9
-rwxr-xr-xsys/src/ape/lib/ap/gen/div.c9
-rwxr-xr-xsys/src/ape/lib/ap/gen/getenv.c18
-rwxr-xr-xsys/src/ape/lib/ap/gen/isalnum.c24
-rwxr-xr-xsys/src/ape/lib/ap/gen/itoa.c7
-rwxr-xr-xsys/src/ape/lib/ap/gen/itol.c7
-rwxr-xr-xsys/src/ape/lib/ap/gen/ldiv.c9
-rwxr-xr-xsys/src/ape/lib/ap/gen/mbwc.c165
-rwxr-xr-xsys/src/ape/lib/ap/gen/memccpy.c17
-rwxr-xr-xsys/src/ape/lib/ap/gen/memchr.c16
-rwxr-xr-xsys/src/ape/lib/ap/gen/memcmp.c22
-rwxr-xr-xsys/src/ape/lib/ap/gen/memmove.c35
-rwxr-xr-xsys/src/ape/lib/ap/gen/memset.c14
-rwxr-xr-xsys/src/ape/lib/ap/gen/mkfile63
-rwxr-xr-xsys/src/ape/lib/ap/gen/mktime.c122
-rwxr-xr-xsys/src/ape/lib/ap/gen/qsort.c90
-rwxr-xr-xsys/src/ape/lib/ap/gen/raise.c11
-rwxr-xr-xsys/src/ape/lib/ap/gen/rand.c75
-rwxr-xr-xsys/src/ape/lib/ap/gen/reduce16
-rwxr-xr-xsys/src/ape/lib/ap/gen/strcat.c9
-rwxr-xr-xsys/src/ape/lib/ap/gen/strchr.c18
-rwxr-xr-xsys/src/ape/lib/ap/gen/strcmp.c19
-rwxr-xr-xsys/src/ape/lib/ap/gen/strcoll.c8
-rwxr-xr-xsys/src/ape/lib/ap/gen/strcpy.c30
-rwxr-xr-xsys/src/ape/lib/ap/gen/strcspn.c20
-rwxr-xr-xsys/src/ape/lib/ap/gen/strftime.c202
-rwxr-xr-xsys/src/ape/lib/ap/gen/strlen.c8
-rwxr-xr-xsys/src/ape/lib/ap/gen/strncat.c20
-rwxr-xr-xsys/src/ape/lib/ap/gen/strncmp.c23
-rwxr-xr-xsys/src/ape/lib/ap/gen/strncpy.c17
-rwxr-xr-xsys/src/ape/lib/ap/gen/strpbrk.c20
-rwxr-xr-xsys/src/ape/lib/ap/gen/strrchr.c14
-rwxr-xr-xsys/src/ape/lib/ap/gen/strspn.c17
-rwxr-xr-xsys/src/ape/lib/ap/gen/strstr.c27
-rwxr-xr-xsys/src/ape/lib/ap/gen/strtod.c91
-rwxr-xr-xsys/src/ape/lib/ap/gen/strtok.c36
-rwxr-xr-xsys/src/ape/lib/ap/gen/strtol.c94
-rwxr-xr-xsys/src/ape/lib/ap/gen/strtoll.c103
-rwxr-xr-xsys/src/ape/lib/ap/gen/strtoul.c92
-rwxr-xr-xsys/src/ape/lib/ap/gen/strtoull.c100
-rwxr-xr-xsys/src/ape/lib/ap/gen/strxfrm.c17
-rwxr-xr-xsys/src/ape/lib/ap/gen/toupper.c17
-rwxr-xr-xsys/src/ape/lib/ap/math/asin.c47
-rwxr-xr-xsys/src/ape/lib/ap/math/atan.c86
-rwxr-xr-xsys/src/ape/lib/ap/math/atan2.c30
-rwxr-xr-xsys/src/ape/lib/ap/math/erf.c116
-rwxr-xr-xsys/src/ape/lib/ap/math/exp.c44
-rwxr-xr-xsys/src/ape/lib/ap/math/fabs.c10
-rwxr-xr-xsys/src/ape/lib/ap/math/floor.c26
-rwxr-xr-xsys/src/ape/lib/ap/math/fmod.c27
-rwxr-xr-xsys/src/ape/lib/ap/math/gamma.c116
-rwxr-xr-xsys/src/ape/lib/ap/math/hypot.c29
-rwxr-xr-xsys/src/ape/lib/ap/math/j0.c188
-rwxr-xr-xsys/src/ape/lib/ap/math/j1.c195
-rwxr-xr-xsys/src/ape/lib/ap/math/jn.c116
-rwxr-xr-xsys/src/ape/lib/ap/math/log.c62
-rwxr-xr-xsys/src/ape/lib/ap/math/mkfile27
-rwxr-xr-xsys/src/ape/lib/ap/math/modf.c53
-rwxr-xr-xsys/src/ape/lib/ap/math/pow.c76
-rwxr-xr-xsys/src/ape/lib/ap/math/sin.c68
-rwxr-xr-xsys/src/ape/lib/ap/math/sinh.c71
-rwxr-xr-xsys/src/ape/lib/ap/math/tan.c70
-rwxr-xr-xsys/src/ape/lib/ap/math/tanh.c24
-rwxr-xr-xsys/src/ape/lib/ap/mips/cycles.c5
-rwxr-xr-xsys/src/ape/lib/ap/mips/getfcr.s15
-rwxr-xr-xsys/src/ape/lib/ap/mips/lock.c172
-rwxr-xr-xsys/src/ape/lib/ap/mips/main9.s12
-rwxr-xr-xsys/src/ape/lib/ap/mips/main9p.s54
-rwxr-xr-xsys/src/ape/lib/ap/mips/memchr.s39
-rwxr-xr-xsys/src/ape/lib/ap/mips/memcmp.s114
-rwxr-xr-xsys/src/ape/lib/ap/mips/memmove.s161
-rwxr-xr-xsys/src/ape/lib/ap/mips/memset.s88
-rwxr-xr-xsys/src/ape/lib/ap/mips/mkfile26
-rwxr-xr-xsys/src/ape/lib/ap/mips/notetramp.c72
-rwxr-xr-xsys/src/ape/lib/ap/mips/setjmp.s24
-rwxr-xr-xsys/src/ape/lib/ap/mips/strchr.s63
-rwxr-xr-xsys/src/ape/lib/ap/mips/strcmp.s21
-rwxr-xr-xsys/src/ape/lib/ap/mips/strcpy.s96
-rwxr-xr-xsys/src/ape/lib/ap/mips/tas.s33
-rwxr-xr-xsys/src/ape/lib/ap/mips/vlop.s17
-rwxr-xr-xsys/src/ape/lib/ap/mips/vlrt.c719
-rwxr-xr-xsys/src/ape/lib/ap/mkfile24
-rwxr-xr-xsys/src/ape/lib/ap/plan9/9errstr.c4
-rwxr-xr-xsys/src/ape/lib/ap/plan9/9iounit.c65
-rwxr-xr-xsys/src/ape/lib/ap/plan9/9mallocz.c14
-rwxr-xr-xsys/src/ape/lib/ap/plan9/9read.c11
-rwxr-xr-xsys/src/ape/lib/ap/plan9/9readn.c21
-rwxr-xr-xsys/src/ape/lib/ap/plan9/9wait.c93
-rwxr-xr-xsys/src/ape/lib/ap/plan9/9write.c11
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_buf.c472
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_dirconv.c65
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_envsetup.c123
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_errno.c124
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_exit.c58
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_fcall.c422
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_fdinfo.c169
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_getpw.c174
-rwxr-xr-xsys/src/ape/lib/ap/plan9/_nap.c20
-rwxr-xr-xsys/src/ape/lib/ap/plan9/access.c62
-rwxr-xr-xsys/src/ape/lib/ap/plan9/acid.c31
-rwxr-xr-xsys/src/ape/lib/ap/plan9/acidlib706
-rwxr-xr-xsys/src/ape/lib/ap/plan9/alarm.c9
-rwxr-xr-xsys/src/ape/lib/ap/plan9/brk.c36
-rwxr-xr-xsys/src/ape/lib/ap/plan9/buf.prom360
-rwxr-xr-xsys/src/ape/lib/ap/plan9/cfgetospeed.c26
-rwxr-xr-xsys/src/ape/lib/ap/plan9/chdir.c14
-rwxr-xr-xsys/src/ape/lib/ap/plan9/chmod.c33
-rwxr-xr-xsys/src/ape/lib/ap/plan9/chown.c39
-rwxr-xr-xsys/src/ape/lib/ap/plan9/close.c34
-rwxr-xr-xsys/src/ape/lib/ap/plan9/convD2M.c93
-rwxr-xr-xsys/src/ape/lib/ap/plan9/convM2D.c74
-rwxr-xr-xsys/src/ape/lib/ap/plan9/creat.c13
-rwxr-xr-xsys/src/ape/lib/ap/plan9/ctermid.c20
-rwxr-xr-xsys/src/ape/lib/ap/plan9/ctime.c321
-rwxr-xr-xsys/src/ape/lib/ap/plan9/cuserid.c21
-rwxr-xr-xsys/src/ape/lib/ap/plan9/dir.h80
-rwxr-xr-xsys/src/ape/lib/ap/plan9/dirread.c119
-rwxr-xr-xsys/src/ape/lib/ap/plan9/dirstat.c107
-rwxr-xr-xsys/src/ape/lib/ap/plan9/dirtostat.c52
-rwxr-xr-xsys/src/ape/lib/ap/plan9/dup.c24
-rwxr-xr-xsys/src/ape/lib/ap/plan9/execl.c9
-rwxr-xr-xsys/src/ape/lib/ap/plan9/execle.c11
-rwxr-xr-xsys/src/ape/lib/ap/plan9/execlp.c24
-rwxr-xr-xsys/src/ape/lib/ap/plan9/execv.c9
-rwxr-xr-xsys/src/ape/lib/ap/plan9/execve.c103
-rwxr-xr-xsys/src/ape/lib/ap/plan9/execvp.c24
-rwxr-xr-xsys/src/ape/lib/ap/plan9/fcall.h118
-rwxr-xr-xsys/src/ape/lib/ap/plan9/fcntl.c81
-rwxr-xr-xsys/src/ape/lib/ap/plan9/fork.c19
-rwxr-xr-xsys/src/ape/lib/ap/plan9/frexp.c89
-rwxr-xr-xsys/src/ape/lib/ap/plan9/fstat.c20
-rwxr-xr-xsys/src/ape/lib/ap/plan9/fsync.c10
-rwxr-xr-xsys/src/ape/lib/ap/plan9/ftruncate.c23
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getcwd.c32
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getgid.c21
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getgrgid.c25
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getgrnam.c25
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getgroups.c10
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getlogin.c27
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getpgrp.c27
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getpid.c22
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getppid.c23
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getpwnam.c29
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getpwuid.c30
-rwxr-xr-xsys/src/ape/lib/ap/plan9/getuid.c17
-rwxr-xr-xsys/src/ape/lib/ap/plan9/isatty.c29
-rwxr-xr-xsys/src/ape/lib/ap/plan9/kill.c60
-rwxr-xr-xsys/src/ape/lib/ap/plan9/lib.h72
-rwxr-xr-xsys/src/ape/lib/ap/plan9/link.c12
-rwxr-xr-xsys/src/ape/lib/ap/plan9/lseek.c24
-rwxr-xr-xsys/src/ape/lib/ap/plan9/malloc.c142
-rwxr-xr-xsys/src/ape/lib/ap/plan9/mkdir.c27
-rwxr-xr-xsys/src/ape/lib/ap/plan9/mkfile110
-rwxr-xr-xsys/src/ape/lib/ap/plan9/nan.c54
-rwxr-xr-xsys/src/ape/lib/ap/plan9/open.c62
-rwxr-xr-xsys/src/ape/lib/ap/plan9/opendir.c121
-rwxr-xr-xsys/src/ape/lib/ap/plan9/pause.c11
-rwxr-xr-xsys/src/ape/lib/ap/plan9/pipe.c31
-rwxr-xr-xsys/src/ape/lib/ap/plan9/profile.c324
-rwxr-xr-xsys/src/ape/lib/ap/plan9/qlock.c365
-rwxr-xr-xsys/src/ape/lib/ap/plan9/read.c46
-rwxr-xr-xsys/src/ape/lib/ap/plan9/rename.c76
-rwxr-xr-xsys/src/ape/lib/ap/plan9/rmdir.c17
-rwxr-xr-xsys/src/ape/lib/ap/plan9/setgid.c14
-rwxr-xr-xsys/src/ape/lib/ap/plan9/setpgid.c31
-rwxr-xr-xsys/src/ape/lib/ap/plan9/setsid.c14
-rwxr-xr-xsys/src/ape/lib/ap/plan9/setuid.c14
-rwxr-xr-xsys/src/ape/lib/ap/plan9/signal.c136
-rwxr-xr-xsys/src/ape/lib/ap/plan9/sigpending.c11
-rwxr-xr-xsys/src/ape/lib/ap/plan9/sigprocmask.c23
-rwxr-xr-xsys/src/ape/lib/ap/plan9/sigsuspend.c13
-rwxr-xr-xsys/src/ape/lib/ap/plan9/sleep.c17
-rwxr-xr-xsys/src/ape/lib/ap/plan9/sqrt.c56
-rwxr-xr-xsys/src/ape/lib/ap/plan9/stat.c21
-rwxr-xr-xsys/src/ape/lib/ap/plan9/sys9.h121
-rwxr-xr-xsys/src/ape/lib/ap/plan9/system.c40
-rwxr-xr-xsys/src/ape/lib/ap/plan9/tcgetattr.c201
-rwxr-xr-xsys/src/ape/lib/ap/plan9/time.c27
-rwxr-xr-xsys/src/ape/lib/ap/plan9/times.c51
-rwxr-xr-xsys/src/ape/lib/ap/plan9/tmpfile.c44
-rwxr-xr-xsys/src/ape/lib/ap/plan9/ttyname.c11
-rwxr-xr-xsys/src/ape/lib/ap/plan9/umask.c13
-rwxr-xr-xsys/src/ape/lib/ap/plan9/uname.c25
-rwxr-xr-xsys/src/ape/lib/ap/plan9/unlink.c75
-rwxr-xr-xsys/src/ape/lib/ap/plan9/utime.c30
-rwxr-xr-xsys/src/ape/lib/ap/plan9/wait.c150
-rwxr-xr-xsys/src/ape/lib/ap/plan9/write.c21
-rwxr-xr-xsys/src/ape/lib/ap/posix/getgrent.c62
-rwxr-xr-xsys/src/ape/lib/ap/posix/getpwent.c69
-rwxr-xr-xsys/src/ape/lib/ap/posix/locale.c62
-rwxr-xr-xsys/src/ape/lib/ap/posix/mkfifo.c12
-rwxr-xr-xsys/src/ape/lib/ap/posix/mkfile16
-rwxr-xr-xsys/src/ape/lib/ap/posix/pathconf.c55
-rwxr-xr-xsys/src/ape/lib/ap/posix/sigset.c67
-rwxr-xr-xsys/src/ape/lib/ap/posix/sysconf.c42
-rwxr-xr-xsys/src/ape/lib/ap/posix/tzset.c141
-rwxr-xr-xsys/src/ape/lib/ap/power/cycles.s17
-rwxr-xr-xsys/src/ape/lib/ap/power/getfcr.s28
-rwxr-xr-xsys/src/ape/lib/ap/power/lock.c45
-rwxr-xr-xsys/src/ape/lib/ap/power/main9.s14
-rwxr-xr-xsys/src/ape/lib/ap/power/main9p.s46
-rwxr-xr-xsys/src/ape/lib/ap/power/memcmp.s110
-rwxr-xr-xsys/src/ape/lib/ap/power/memmove.s170
-rwxr-xr-xsys/src/ape/lib/ap/power/memset.s73
-rwxr-xr-xsys/src/ape/lib/ap/power/mkfile23
-rwxr-xr-xsys/src/ape/lib/ap/power/notetramp.c72
-rwxr-xr-xsys/src/ape/lib/ap/power/setjmp.s37
-rwxr-xr-xsys/src/ape/lib/ap/power/strcmp.s21
-rwxr-xr-xsys/src/ape/lib/ap/power/tas.s16
-rwxr-xr-xsys/src/ape/lib/ap/power/vlop.s132
-rwxr-xr-xsys/src/ape/lib/ap/power/vlrt.c254
-rwxr-xr-xsys/src/ape/lib/ap/sparc/cycles.c5
-rwxr-xr-xsys/src/ape/lib/ap/sparc/lock.c26
-rwxr-xr-xsys/src/ape/lib/ap/sparc/main9.s14
-rwxr-xr-xsys/src/ape/lib/ap/sparc/main9p.s53
-rwxr-xr-xsys/src/ape/lib/ap/sparc/memchr.s26
-rwxr-xr-xsys/src/ape/lib/ap/sparc/memcmp.s122
-rwxr-xr-xsys/src/ape/lib/ap/sparc/memmove.s169
-rwxr-xr-xsys/src/ape/lib/ap/sparc/memset.s88
-rwxr-xr-xsys/src/ape/lib/ap/sparc/mkfile26
-rwxr-xr-xsys/src/ape/lib/ap/sparc/muldiv.s310
-rwxr-xr-xsys/src/ape/lib/ap/sparc/notetramp.c81
-rwxr-xr-xsys/src/ape/lib/ap/sparc/setjmp.s36
-rwxr-xr-xsys/src/ape/lib/ap/sparc/strchr.s73
-rwxr-xr-xsys/src/ape/lib/ap/sparc/strcmp.s27
-rwxr-xr-xsys/src/ape/lib/ap/sparc/strcpy.s84
-rwxr-xr-xsys/src/ape/lib/ap/sparc/tas.s7
-rwxr-xr-xsys/src/ape/lib/ap/sparc/vlop.s112
-rwxr-xr-xsys/src/ape/lib/ap/sparc/vlrt.c718
-rwxr-xr-xsys/src/ape/lib/ap/stdio/_IO_getc.c30
-rwxr-xr-xsys/src/ape/lib/ap/stdio/_IO_putc.c106
-rwxr-xr-xsys/src/ape/lib/ap/stdio/_dtoa.c744
-rwxr-xr-xsys/src/ape/lib/ap/stdio/_fconv.c593
-rwxr-xr-xsys/src/ape/lib/ap/stdio/atexit.c15
-rwxr-xr-xsys/src/ape/lib/ap/stdio/clearerr.c14
-rwxr-xr-xsys/src/ape/lib/ap/stdio/exit.c17
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fclose.c15
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fconv.h236
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fdopen.c33
-rwxr-xr-xsys/src/ape/lib/ap/stdio/feof.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/ferror.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fflush.c31
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fgetc.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fgetpos.c8
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fgets.c17
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fileno.c10
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fopen.c11
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fprintf.c12
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fputc.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fputs.c8
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fread.c45
-rwxr-xr-xsys/src/ape/lib/ap/stdio/freopen.c66
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fscanf.c12
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fseek.c24
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fseeko.c24
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fsetpos.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/ftell.c16
-rwxr-xr-xsys/src/ape/lib/ap/stdio/ftello.c16
-rwxr-xr-xsys/src/ape/lib/ap/stdio/ftoa.c41
-rwxr-xr-xsys/src/ape/lib/ap/stdio/fwrite.c55
-rwxr-xr-xsys/src/ape/lib/ap/stdio/getc.c8
-rwxr-xr-xsys/src/ape/lib/ap/stdio/getchar.c8
-rwxr-xr-xsys/src/ape/lib/ap/stdio/gets.c17
-rwxr-xr-xsys/src/ape/lib/ap/stdio/iolib.h44
-rwxr-xr-xsys/src/ape/lib/ap/stdio/mkfile68
-rwxr-xr-xsys/src/ape/lib/ap/stdio/perror.c11
-rwxr-xr-xsys/src/ape/lib/ap/stdio/pow10.c30
-rwxr-xr-xsys/src/ape/lib/ap/stdio/printf.c12
-rwxr-xr-xsys/src/ape/lib/ap/stdio/putc.c8
-rwxr-xr-xsys/src/ape/lib/ap/stdio/putchar.c8
-rwxr-xr-xsys/src/ape/lib/ap/stdio/puts.c9
-rwxr-xr-xsys/src/ape/lib/ap/stdio/rdline.c65
-rwxr-xr-xsys/src/ape/lib/ap/stdio/remove.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/rename.c12
-rwxr-xr-xsys/src/ape/lib/ap/stdio/rewind.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/scanf.c12
-rwxr-xr-xsys/src/ape/lib/ap/stdio/sclose.c37
-rwxr-xr-xsys/src/ape/lib/ap/stdio/setbuf.c17
-rwxr-xr-xsys/src/ape/lib/ap/stdio/setvbuf.c39
-rwxr-xr-xsys/src/ape/lib/ap/stdio/snprintf.c20
-rwxr-xr-xsys/src/ape/lib/ap/stdio/sopenr.c18
-rwxr-xr-xsys/src/ape/lib/ap/stdio/sopenw.c15
-rwxr-xr-xsys/src/ape/lib/ap/stdio/sprintf.c17
-rwxr-xr-xsys/src/ape/lib/ap/stdio/sscanf.c14
-rwxr-xr-xsys/src/ape/lib/ap/stdio/stdio.c10
-rwxr-xr-xsys/src/ape/lib/ap/stdio/strerror.c106
-rwxr-xr-xsys/src/ape/lib/ap/stdio/strtod.c731
-rwxr-xr-xsys/src/ape/lib/ap/stdio/tmpfile.c32
-rwxr-xr-xsys/src/ape/lib/ap/stdio/tmpnam.c33
-rwxr-xr-xsys/src/ape/lib/ap/stdio/ungetc.c33
-rwxr-xr-xsys/src/ape/lib/ap/stdio/vfprintf.c566
-rwxr-xr-xsys/src/ape/lib/ap/stdio/vfscanf.c367
-rwxr-xr-xsys/src/ape/lib/ap/stdio/vprintf.c7
-rwxr-xr-xsys/src/ape/lib/ap/stdio/vsnprintf.c17
-rwxr-xr-xsys/src/ape/lib/ap/stdio/vsprintf.c14
-rwxr-xr-xsys/src/ape/lib/ap/syscall/genall16
-rwxr-xr-xsys/src/ape/lib/ap/syscall/mkfile25
380 files changed, 26221 insertions, 0 deletions
diff --git a/sys/src/ape/lib/ap/386/cycles.s b/sys/src/ape/lib/ap/386/cycles.s
new file mode 100755
index 000000000..d1acbd2fc
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/cycles.s
@@ -0,0 +1,8 @@
+#define RDTSC BYTE $0x0F; BYTE $0x31
+
+TEXT _cycles(SB),1,$0 /* time stamp counter; cycles since power up */
+ RDTSC
+ MOVL vlong+0(FP), CX /* &vlong */
+ MOVL AX, 0(CX) /* lo */
+ MOVL DX, 4(CX) /* hi */
+ RET
diff --git a/sys/src/ape/lib/ap/386/lock.c b/sys/src/ape/lib/ap/386/lock.c
new file mode 100755
index 000000000..91c0ba233
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/lock.c
@@ -0,0 +1,26 @@
+#define _LOCK_EXTENSION
+#include "../plan9/sys9.h"
+#include <lock.h>
+
+int tas(int*);
+
+void
+lock(Lock *lk)
+{
+ while(tas(&lk->val))
+ _SLEEP(0);
+}
+
+int
+canlock(Lock *lk)
+{
+ if(tas(&lk->val))
+ return 0;
+ return 1;
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
diff --git a/sys/src/ape/lib/ap/386/main9.s b/sys/src/ape/lib/ap/386/main9.s
new file mode 100755
index 000000000..aef0777a4
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/main9.s
@@ -0,0 +1,13 @@
+ TEXT _main(SB), 1, $12
+
+ CALL _envsetup(SB)
+ MOVL inargc-4(FP), AX
+ MOVL AX, 0(SP)
+ LEAL inargv+0(FP), AX
+ MOVL AX, 4(SP)
+ MOVL environ(SB), AX
+ MOVL AX, 8(SP)
+ CALL main(SB)
+ MOVL AX, 0(SP)
+ CALL exit(SB)
+ RET
diff --git a/sys/src/ape/lib/ap/386/main9p.s b/sys/src/ape/lib/ap/386/main9p.s
new file mode 100755
index 000000000..0ca3004a4
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/main9p.s
@@ -0,0 +1,46 @@
+#define NPRIVATES 16
+
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
+
+TEXT _mainp(SB), 1, $(3*4+NPRIVATES*4)
+
+ /* _tos = arg */
+ MOVL AX, _tos(SB)
+ LEAL 8(SP), AX
+ MOVL AX, _privates(SB)
+ MOVL $NPRIVATES, _nprivates(SB)
+
+ /* _profmain(); */
+ CALL _profmain(SB)
+
+ /* _tos->prof.pp = _tos->prof.next; */
+ MOVL _tos+0(SB),DX
+ MOVL 4(DX),CX
+ MOVL CX,(DX)
+
+ CALL _envsetup(SB)
+
+ /* main(argc, argv, environ); */
+ MOVL inargc-4(FP), AX
+ MOVL AX, 0(SP)
+ LEAL inargv+0(FP), AX
+ MOVL AX, 4(SP)
+ MOVL environ(SB), AX
+ MOVL AX, 8(SP)
+ CALL main(SB)
+loop:
+ MOVL AX, 0(SP)
+ CALL exit(SB)
+ MOVL $_profin(SB), AX /* force loading of profile */
+ MOVL $0, AX
+ JMP loop
+
+TEXT _savearg(SB), 1, $0
+ RET
+
+TEXT _callpc(SB), 1, $0
+ MOVL argp+0(FP), AX
+ MOVL 4(AX), AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/memchr.s b/sys/src/ape/lib/ap/386/memchr.s
new file mode 100755
index 000000000..23a1982a3
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/memchr.s
@@ -0,0 +1,23 @@
+ TEXT memchr(SB),$0
+
+ MOVL n+8(FP), CX
+ CMPL CX, $0
+ JEQ none
+ MOVL p+0(FP), DI
+ MOVBLZX c+4(FP), AX
+ CLD
+/*
+ * SCASB is memchr instruction
+ */
+
+ REPN; SCASB
+ JEQ found
+
+none:
+ MOVL $0, AX
+ RET
+
+found:
+ MOVL DI, AX
+ SUBL $1, AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/memcmp.s b/sys/src/ape/lib/ap/386/memcmp.s
new file mode 100755
index 000000000..4e9d090cf
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/memcmp.s
@@ -0,0 +1,47 @@
+ TEXT memcmp(SB),$0
+
+ MOVL n+8(FP), BX
+ CMPL BX, $0
+ JEQ none
+ MOVL p1+0(FP), DI
+ MOVL p2+4(FP), SI
+ CLD
+/*
+ * first by longs
+ */
+
+ MOVL BX, CX
+ SHRL $2, CX
+
+ REP; CMPSL
+ JNE found
+
+/*
+ * then by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; CMPSB
+ JNE found1
+
+none:
+ MOVL $0, AX
+ RET
+
+/*
+ * if long found,
+ * back up and look by bytes
+ */
+found:
+ MOVL $4, CX
+ SUBL CX, DI
+ SUBL CX, SI
+ REP; CMPSB
+
+found1:
+ JLS lt
+ MOVL $-1, AX
+ RET
+lt:
+ MOVL $1, AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/memcpy.s b/sys/src/ape/lib/ap/386/memcpy.s
new file mode 100755
index 000000000..bb9cfe40c
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/memcpy.s
@@ -0,0 +1,57 @@
+ TEXT memcpy(SB), $0
+
+ MOVL p1+0(FP), DI
+ MOVL p2+4(FP), SI
+ MOVL n+8(FP), BX
+ CMPL BX, $0
+ JGE ok
+ MOVL $0, SI
+ok:
+ CLD
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+back:
+ ADDL BX, DI
+ ADDL BX, SI
+ SUBL $4, DI
+ SUBL $4, SI
+ STD
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ADDL $3, DI
+ ADDL $3, SI
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/memmove.s b/sys/src/ape/lib/ap/386/memmove.s
new file mode 100755
index 000000000..45a72225f
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/memmove.s
@@ -0,0 +1,57 @@
+ TEXT memmove(SB), $0
+
+ MOVL p1+0(FP), DI
+ MOVL p2+4(FP), SI
+ MOVL n+8(FP), BX
+ CMPL BX, $0
+ JGE ok
+ MOVL $0, SI
+ok:
+ CLD
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+back:
+ ADDL BX, DI
+ ADDL BX, SI
+ SUBL $4, DI
+ SUBL $4, SI
+ STD
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ADDL $3, DI
+ ADDL $3, SI
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/memset.s b/sys/src/ape/lib/ap/386/memset.s
new file mode 100755
index 000000000..dacb2f5fb
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/memset.s
@@ -0,0 +1,35 @@
+ TEXT memset(SB),$0
+
+ CLD
+ MOVL p+0(FP), DI
+ MOVBLZX c+4(FP), AX
+ MOVL n+8(FP), BX
+/*
+ * if not enough bytes, just copy
+ */
+ CMPL BX, $9
+ JLS c3
+/*
+ * build word in AX
+ */
+ MOVB AL, AH
+ MOVL AX, CX
+ SHLL $16, CX
+ ORL CX, AX
+/*
+ * copy whole longs
+ */
+c1:
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; STOSL
+/*
+ * copy the rest, by bytes
+ */
+c3:
+ MOVL BX, CX
+ REP; STOSB
+ret:
+ MOVL p+0(FP),AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/mkfile b/sys/src/ape/lib/ap/386/mkfile
new file mode 100755
index 000000000..e19a4b852
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/mkfile
@@ -0,0 +1,27 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ cycles.$O\
+ lock.$O\
+ main9.$O\
+ main9p.$O\
+ memchr.$O\
+ memcmp.$O\
+ memcpy.$O\
+ memmove.$O\
+ memset.$O\
+ notetramp.$O\
+ setjmp.$O\
+ strcat.$O\
+ strchr.$O\
+ strcpy.$O\
+ strlen.$O\
+ tas.$O\
+ vlop.$O\
+ vlrt.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE
+
diff --git a/sys/src/ape/lib/ap/386/notetramp.c b/sys/src/ape/lib/ap/386/notetramp.c
new file mode 100755
index 000000000..19a6395f4
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/notetramp.c
@@ -0,0 +1,72 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#include <signal.h>
+#include <setjmp.h>
+
+/* A stack to hold pcs when signals nest */
+#define MAXSIGSTACK 20
+typedef struct Pcstack Pcstack;
+static struct Pcstack {
+ int sig;
+ void (*hdlr)(int, char*, Ureg*);
+ unsigned long restorepc;
+ Ureg *u;
+} pcstack[MAXSIGSTACK];
+static int nstack = 0;
+
+static void notecont(Ureg*, char*);
+
+void
+_notetramp(int sig, void (*hdlr)(int, char*, Ureg*), Ureg *u)
+{
+ Pcstack *p;
+
+ if(nstack >= MAXSIGSTACK)
+ _NOTED(1); /* nesting too deep; just do system default */
+ p = &pcstack[nstack];
+ p->restorepc = u->pc;
+ p->sig = sig;
+ p->hdlr = hdlr;
+ p->u = u;
+ nstack++;
+ u->pc = (unsigned long) notecont;
+ _NOTED(2); /* NSAVE: clear note but hold state */
+}
+
+static void
+notecont(Ureg *u, char *s)
+{
+ Pcstack *p;
+ void(*f)(int, char*, Ureg*);
+
+ p = &pcstack[nstack-1];
+ f = p->hdlr;
+ u->pc = p->restorepc;
+ nstack--;
+ (*f)(p->sig, s, u);
+ _NOTED(3); /* NRSTR */
+}
+
+#define JMPBUFPC 1
+#define JMPBUFSP 0
+
+extern sigset_t _psigblocked;
+
+void
+siglongjmp(sigjmp_buf j, int ret)
+{
+ struct Ureg *u;
+
+ if(j[0])
+ _psigblocked = j[1];
+ if(nstack == 0 || pcstack[nstack-1].u->sp > j[2+JMPBUFSP])
+ longjmp(j+2, ret);
+ u = pcstack[nstack-1].u;
+ nstack--;
+ u->ax = ret;
+ if(ret == 0)
+ u->ax = 1;
+ u->pc = j[2+JMPBUFPC];
+ u->sp = j[2+JMPBUFSP] + 4;
+ _NOTED(3); /* NRSTR */
+}
diff --git a/sys/src/ape/lib/ap/386/setjmp.s b/sys/src/ape/lib/ap/386/setjmp.s
new file mode 100755
index 000000000..008a43f07
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/setjmp.s
@@ -0,0 +1,29 @@
+TEXT longjmp(SB), $0
+ MOVL r+4(FP), AX
+ CMPL AX, $0
+ JNE ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVL $1, AX /* bless their pointed heads */
+ok: MOVL l+0(FP), BX
+ MOVL 0(BX), SP /* restore sp */
+ MOVL 4(BX), BX /* put return pc on the stack */
+ MOVL BX, 0(SP)
+ RET
+
+TEXT setjmp(SB), $0
+ MOVL l+0(FP), AX
+ MOVL SP, 0(AX) /* store sp */
+ MOVL 0(SP), BX /* store return pc */
+ MOVL BX, 4(AX)
+ MOVL $0, AX /* return 0 */
+ RET
+
+TEXT sigsetjmp(SB), $0
+ MOVL buf+0(FP), AX
+ MOVL savemask+4(FP),BX
+ MOVL BX,0(AX)
+ MOVL $_psigblocked(SB),4(AX)
+ MOVL SP, 8(AX) /* store sp */
+ MOVL 0(SP), BX /* store return pc */
+ MOVL BX, 12(AX)
+ MOVL $0, AX /* return 0 */
+ RET
diff --git a/sys/src/ape/lib/ap/386/strcat.s b/sys/src/ape/lib/ap/386/strcat.s
new file mode 100755
index 000000000..3f41fefa5
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/strcat.s
@@ -0,0 +1,43 @@
+ TEXT strcat(SB),$0
+
+ MOVL $0, AX
+ MOVL $-1, CX
+ CLD
+
+/*
+ * find length of second string
+ */
+
+ MOVL p2+4(FP), DI
+ REPN; SCASB
+
+ MOVL DI, BX
+ SUBL p2+4(FP), BX
+
+/*
+ * find end of first string
+ */
+
+ MOVL p1+0(FP), DI
+ REPN; SCASB
+
+/*
+ * copy the memory
+ */
+ SUBL $1, DI
+ MOVL p2+4(FP), SI
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p1+0(FP), AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/strchr.s b/sys/src/ape/lib/ap/386/strchr.s
new file mode 100755
index 000000000..873bdcf12
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/strchr.s
@@ -0,0 +1,38 @@
+ TEXT strchr(SB), $0
+
+ MOVL s+0(FP), DI
+ MOVB c+4(FP), AX
+ CMPB AX, $0
+ JEQ l2 /**/
+
+/*
+ * char is not null
+ */
+l1:
+ MOVB (DI), BX
+ CMPB BX, $0
+ JEQ ret0
+ ADDL $1, DI
+ CMPB AX, BX
+ JNE l1
+
+ MOVL DI, AX
+ SUBL $1, AX
+ RET
+
+/*
+ * char is null
+ */
+l2:
+ MOVL $-1, CX
+ CLD
+
+ REPN; SCASB
+
+ MOVL DI, AX
+ SUBL $1, AX
+ RET
+
+ret0:
+ MOVL $0, AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/strcpy.s b/sys/src/ape/lib/ap/386/strcpy.s
new file mode 100755
index 000000000..83482e8a2
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/strcpy.s
@@ -0,0 +1,35 @@
+ TEXT strcpy(SB),$0
+
+ MOVL $0, AX
+ MOVL $-1, CX
+ CLD
+/*
+ * find end of second string
+ */
+
+ MOVL p2+4(FP), DI
+ REPN; SCASB
+
+ MOVL DI, BX
+ SUBL p2+4(FP), BX
+
+/*
+ * copy the memory
+ */
+ MOVL p1+0(FP), DI
+ MOVL p2+4(FP), SI
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p1+0(FP), AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/strlen.s b/sys/src/ape/lib/ap/386/strlen.s
new file mode 100755
index 000000000..e0330ffcc
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/strlen.s
@@ -0,0 +1,16 @@
+ TEXT strlen(SB),$0
+
+ MOVL $0, AX
+ MOVL $-1, CX
+ CLD
+/*
+ * look for end of string
+ */
+
+ MOVL p+0(FP), DI
+ REPN; SCASB
+
+ MOVL DI, AX
+ SUBL p+0(FP), AX
+ SUBL $1, AX
+ RET
diff --git a/sys/src/ape/lib/ap/386/tas.s b/sys/src/ape/lib/ap/386/tas.s
new file mode 100755
index 000000000..d756102db
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/tas.s
@@ -0,0 +1,6 @@
+TEXT tas(SB),$0
+
+ MOVL $0xdeadead,AX
+ MOVL l+0(FP),BX
+ XCHGL AX,(BX)
+ RET
diff --git a/sys/src/ape/lib/ap/386/vlop.s b/sys/src/ape/lib/ap/386/vlop.s
new file mode 100755
index 000000000..42e8a70df
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/vlop.s
@@ -0,0 +1,44 @@
+TEXT _mulv(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+4(FP), AX
+ MULL b+16(FP)
+ ADDL AX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _mul64by32(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _div64by32(SB), $0
+ MOVL r+12(FP), CX
+ MOVL a+0(FP), AX
+ MOVL a+4(FP), DX
+ DIVL b+8(FP)
+ MOVL DX, 0(CX)
+ RET
+
+TEXT _addv(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MOVL a+8(FP), BX
+ ADDL b+12(FP), AX
+ ADCL b+16(FP), BX
+ MOVL AX, 0(CX)
+ MOVL BX, 4(CX)
+ RET
diff --git a/sys/src/ape/lib/ap/386/vlrt.c b/sys/src/ape/lib/ap/386/vlrt.c
new file mode 100755
index 000000000..f0b100ef5
--- /dev/null
+++ b/sys/src/ape/lib/ap/386/vlrt.c
@@ -0,0 +1,695 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ struct
+ {
+ ushort lols;
+ ushort loms;
+ ushort hils;
+ ushort hims;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+ulong _div64by32(Vlong, ulong, ulong*);
+void _mul64by32(Vlong*, Vlong, ulong);
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong n;
+ Vlong x, q, r;
+
+ if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+ if(qp) {
+ qp->hi = 0;
+ qp->lo = 0;
+ }
+ if(rp) {
+ rp->hi = num.hi;
+ rp->lo = num.lo;
+ }
+ return;
+ }
+
+ if(den.hi != 0){
+ q.hi = 0;
+ n = num.hi/den.hi;
+ _mul64by32(&x, den, n);
+ if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)){
+ n--;
+ _mul64by32(&x, den, n);
+ }
+ q.lo = n;
+ _subv(&r, num, x);
+ } else {
+ if(num.hi >= den.lo){
+ q.hi = n = num.hi/den.lo;
+ num.hi -= den.lo*n;
+ } else {
+ q.hi = 0;
+ }
+ q.lo = _div64by32(num, den.lo, &r.lo);
+ r.hi = 0;
+ }
+ if(qp) {
+ qp->lo = q.lo;
+ qp->hi = q.hi;
+ }
+ if(rp) {
+ rp->lo = r.lo;
+ rp->hi = r.hi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/sys/src/ape/lib/ap/68020/cycles.c b/sys/src/ape/lib/ap/68020/cycles.c
new file mode 100755
index 000000000..1c32bc732
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/cycles.c
@@ -0,0 +1,5 @@
+void
+_cycles(unsigned long long *u)
+{
+ *u = 0;
+}
diff --git a/sys/src/ape/lib/ap/68020/lock.c b/sys/src/ape/lib/ap/68020/lock.c
new file mode 100755
index 000000000..91c0ba233
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/lock.c
@@ -0,0 +1,26 @@
+#define _LOCK_EXTENSION
+#include "../plan9/sys9.h"
+#include <lock.h>
+
+int tas(int*);
+
+void
+lock(Lock *lk)
+{
+ while(tas(&lk->val))
+ _SLEEP(0);
+}
+
+int
+canlock(Lock *lk)
+{
+ if(tas(&lk->val))
+ return 0;
+ return 1;
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
diff --git a/sys/src/ape/lib/ap/68020/main9.s b/sys/src/ape/lib/ap/68020/main9.s
new file mode 100755
index 000000000..04e40c5e6
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/main9.s
@@ -0,0 +1,9 @@
+TEXT _main(SB), 1, $16
+ MOVL $a6base(SB), A6
+ PEA inargv+0(FP)
+ MOVL inargc-4(FP), TOS
+ BSR _envsetup(SB)
+ BSR main(SB)
+ MOVL R0,TOS
+ BSR exit(SB)
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/main9p.s b/sys/src/ape/lib/ap/68020/main9p.s
new file mode 100755
index 000000000..171355c5f
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/main9p.s
@@ -0,0 +1,43 @@
+#define NPRIVATES 16
+
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
+
+TEXT _mainp(SB), 1, $(3*4+NPRIVATES*4)
+ MOVL $a6base(SB), A6
+
+ /* _tos = arg */
+ MOVL R0, _tos(SB) /* return value of sys exec!! */
+ LEA private+8(SP), _privates(SB)
+ MOVL $NPRIVATES, _nprivates(SB)
+
+ /* _profmain(); */
+ BSR _profmain(SB)
+
+ /* _tos->prof.pp = _tos->prof.next; */
+ MOVL _tos+0(SB),A1
+ MOVL 4(A1),(A1)
+
+ BSR _envsetup(SB)
+
+ /* main(argc, argv, environ); */
+ MOVL environ(SB), TOS
+ PEA inargv+0(FP)
+ MOVL inargc-4(FP), TOS
+ BSR main(SB)
+
+loop:
+ MOVL R0,TOS
+ BSR exit(SB)
+ LEA _profin(SB), A0 /* force loading of profile */
+ BRA loop
+
+
+TEXT _savearg(SB), 1, $0
+ RTS
+
+TEXT _callpc(SB), 1, $0
+ MOVL argp+0(FP), A0
+ MOVL 4(A0), R0
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/memchr.s b/sys/src/ape/lib/ap/68020/memchr.s
new file mode 100755
index 000000000..ea2584df8
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/memchr.s
@@ -0,0 +1,15 @@
+ TEXT memchr(SB),$0
+ MOVL n+8(FP),R0
+ BEQ ret
+ MOVL s1+0(FP),A1
+ MOVL c+4(FP),R1
+
+l1: CMPB R1,(A1)+
+ BEQ eq
+ SUBL $1,R0
+ BNE l1
+ RTS
+
+eq: MOVL A1,R0
+ SUBL $1,R0
+ret: RTS
diff --git a/sys/src/ape/lib/ap/68020/memcmp.s b/sys/src/ape/lib/ap/68020/memcmp.s
new file mode 100755
index 000000000..97d208e3b
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/memcmp.s
@@ -0,0 +1,18 @@
+ TEXT memcmp(SB),$0
+ MOVL n+8(FP),R0
+ BEQ ret
+ MOVL s1+0(FP),A2
+ MOVL s2+4(FP),A1
+
+l1: CMPB (A1)+,(A2)+
+ BNE neq
+ SUBL $1,R0
+ BNE l1
+ RTS
+
+neq: BCS gtr
+ MOVL $-1,R0
+ RTS
+
+gtr: MOVL $1,R0
+ret: RTS
diff --git a/sys/src/ape/lib/ap/68020/memcpy.s b/sys/src/ape/lib/ap/68020/memcpy.s
new file mode 100755
index 000000000..2a37573da
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/memcpy.s
@@ -0,0 +1,98 @@
+ TEXT memcpy(SB), $0
+
+ MOVL n+8(FP),R0
+ BEQ return
+ BGT ok
+ MOVL 0, R0
+ok:
+ MOVL s1+0(FP),A2
+ MOVL s2+4(FP),A1
+
+ CMPL A2,A1
+ BHI back
+
+/*
+ * speed depends on source allignment
+ * destination allignment is secondary
+ * byte-at-a-time foreward copy to
+ * get source (A1) alligned.
+ */
+f1:
+ MOVL A1, R1
+ ANDL $3, R1
+ BEQ f2
+ SUBL $1, R0
+ BLT return
+ MOVB (A1)+, (A2)+
+ BRA f1
+/*
+ * quad-long-at-a-time forward copy
+ */
+f2:
+ SUBL $16, R0
+ BLT f3
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ BRA f2
+
+/*
+ * cleanup byte-at-a-time
+ */
+f3:
+ ADDL $15, R0
+ BLT return
+f4:
+ MOVB (A1)+, (A2)+
+ SUBL $1, R0
+ BGE f4
+ BRA return
+
+return:
+ MOVL s1+0(FP),R0
+ RTS
+
+/*
+ * everything the same, but
+ * copy backwards
+ */
+back:
+ ADDL R0, A1
+ ADDL R0, A2
+
+/*
+ * byte-at-a-time backward copy to
+ * get source (A1) alligned.
+ */
+b1:
+ MOVL A1, R1
+ ANDL $3, R1
+ BEQ b2
+ SUBL $1, R0
+ BLT return
+ MOVB -(A1), -(A2)
+ BRA b1
+/*
+ * quad-long-at-a-time backward copy
+ */
+b2:
+ SUBL $16, R0
+ BLT b3
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ BRA b2
+
+/*
+ * cleanup byte-at-a-time backward
+ */
+b3:
+ ADDL $15, R0
+ BLT return
+b4:
+ MOVB -(A1), -(A2)
+ SUBL $1, R0
+ BGE b4
+ BRA return
diff --git a/sys/src/ape/lib/ap/68020/memmove.s b/sys/src/ape/lib/ap/68020/memmove.s
new file mode 100755
index 000000000..482b3d690
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/memmove.s
@@ -0,0 +1,99 @@
+ TEXT memmove(SB), $0
+move:
+
+ MOVL n+8(FP),R0
+ BEQ return
+ BGT ok
+ MOVL 0, R0
+ok:
+ MOVL s1+0(FP),A2
+ MOVL s2+4(FP),A1
+
+ CMPL A2,A1
+ BHI back
+
+/*
+ * speed depends on source allignment
+ * destination allignment is secondary
+ * byte-at-a-time foreward copy to
+ * get source (A1) alligned.
+ */
+f1:
+ MOVL A1, R1
+ ANDL $3, R1
+ BEQ f2
+ SUBL $1, R0
+ BLT return
+ MOVB (A1)+, (A2)+
+ BRA f1
+/*
+ * quad-long-at-a-time forward copy
+ */
+f2:
+ SUBL $16, R0
+ BLT f3
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ BRA f2
+
+/*
+ * cleanup byte-at-a-time
+ */
+f3:
+ ADDL $15, R0
+ BLT return
+f4:
+ MOVB (A1)+, (A2)+
+ SUBL $1, R0
+ BGE f4
+ BRA return
+
+return:
+ MOVL s1+0(FP),R0
+ RTS
+
+/*
+ * everything the same, but
+ * copy backwards
+ */
+back:
+ ADDL R0, A1
+ ADDL R0, A2
+
+/*
+ * byte-at-a-time backward copy to
+ * get source (A1) alligned.
+ */
+b1:
+ MOVL A1, R1
+ ANDL $3, R1
+ BEQ b2
+ SUBL $1, R0
+ BLT return
+ MOVB -(A1), -(A2)
+ BRA b1
+/*
+ * quad-long-at-a-time backward copy
+ */
+b2:
+ SUBL $16, R0
+ BLT b3
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ BRA b2
+
+/*
+ * cleanup byte-at-a-time backward
+ */
+b3:
+ ADDL $15, R0
+ BLT return
+b4:
+ MOVB -(A1), -(A2)
+ SUBL $1, R0
+ BGE b4
+ BRA return
diff --git a/sys/src/ape/lib/ap/68020/memset.s b/sys/src/ape/lib/ap/68020/memset.s
new file mode 100755
index 000000000..d4b773416
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/memset.s
@@ -0,0 +1,47 @@
+ TEXT memset(SB), $0
+ MOVL n+8(FP), R0
+ BLE return
+ MOVL s1+0(FP), A1
+ CLRL R1
+ MOVB c+7(FP), R1
+ BEQ l1
+
+/*
+ * create 4 replicated copies
+ * of the byte in R1
+ */
+ MOVL R1, R2
+ ASLL $8, R2
+ ORL R2, R1
+ MOVL R1, R2
+ SWAP R2
+ ORL R2, R1
+
+/*
+ * quad-long-at-a-time set
+ * destination allignment is not
+ * very important.
+ */
+l1:
+ SUBL $16, R0
+ BLT l2
+ MOVL R1, (A1)+
+ MOVL R1, (A1)+
+ MOVL R1, (A1)+
+ MOVL R1, (A1)+
+ BRA l1
+
+/*
+ * cleanup byte-at-a-time
+ */
+l2:
+ ADDL $15, R0
+ BLT return
+l3:
+ MOVB R1, (A1)+
+ SUBL $1, R0
+ BGE l3
+
+return:
+ MOVL s1+0(FP),R0
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/mkfile b/sys/src/ape/lib/ap/68020/mkfile
new file mode 100755
index 000000000..f71b3cef2
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/mkfile
@@ -0,0 +1,28 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ cycles.$O\
+ lock.$O\
+ main9.$O\
+ main9p.$O\
+ memchr.$O\
+ memcmp.$O\
+ memcpy.$O\
+ memmove.$O\
+ memset.$O\
+ notetramp.$O\
+ setjmp.$O\
+ strcat.$O\
+ strchr.$O\
+ strcmp.$O\
+ strcpy.$O\
+ strlen.$O\
+ tas.$O\
+ vlop.$O\
+ vlrt.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE
+
diff --git a/sys/src/ape/lib/ap/68020/notetramp.c b/sys/src/ape/lib/ap/68020/notetramp.c
new file mode 100755
index 000000000..7803a35c7
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/notetramp.c
@@ -0,0 +1,72 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#include <signal.h>
+#include <setjmp.h>
+
+/* A stack to hold pcs when signals nest */
+#define MAXSIGSTACK 20
+typedef struct Pcstack Pcstack;
+static struct Pcstack {
+ int sig;
+ void (*hdlr)(int, char*, Ureg*);
+ unsigned long restorepc;
+ Ureg *u;
+} pcstack[MAXSIGSTACK];
+static int nstack = 0;
+
+static void notecont(Ureg*, char*);
+
+void
+_notetramp(int sig, void (*hdlr)(int, char*, Ureg*), Ureg *u)
+{
+ Pcstack *p;
+
+ if(nstack >= MAXSIGSTACK)
+ _NOTED(1); /* nesting too deep; just do system default */
+ p = &pcstack[nstack];
+ p->restorepc = u->pc;
+ p->sig = sig;
+ p->hdlr = hdlr;
+ p->u = u;
+ nstack++;
+ u->pc = (unsigned long) notecont;
+ _NOTED(2); /* NSAVE: clear note but hold state */
+}
+
+static void
+notecont(Ureg *u, char *s)
+{
+ Pcstack *p;
+ void(*f)(int, char*, Ureg*);
+
+ p = &pcstack[nstack-1];
+ f = p->hdlr;
+ u->pc = p->restorepc;
+ nstack--;
+ (*f)(p->sig, s, u);
+ _NOTED(3); /* NRSTR */
+}
+
+#define JMPBUFPC 1
+#define JMPBUFSP 0
+
+extern sigset_t _psigblocked;
+
+void
+siglongjmp(sigjmp_buf j, int ret)
+{
+ struct Ureg *u;
+
+ if(j[0])
+ _psigblocked = j[1];
+ if(nstack == 0 || pcstack[nstack-1].u->sp > j[2+JMPBUFSP])
+ longjmp(j+2, ret);
+ u = pcstack[nstack-1].u;
+ nstack--;
+ u->r0 = ret;
+ if(ret == 0)
+ u->r0 = 1;
+ u->pc = j[2+JMPBUFPC];
+ u->sp = j[2+JMPBUFSP] + 4;
+ _NOTED(3); /* NRSTR */
+}
diff --git a/sys/src/ape/lib/ap/68020/setjmp.s b/sys/src/ape/lib/ap/68020/setjmp.s
new file mode 100755
index 000000000..c827376c2
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/setjmp.s
@@ -0,0 +1,26 @@
+TEXT setjmp(SB), 1, $0
+ MOVL b+0(FP), A0
+ MOVL A7, (A0)+
+ MOVL (A7), (A0)
+ CLRL R0
+ RTS
+
+TEXT sigsetjmp(SB), 1, $0
+ MOVL b+0(FP), A0
+ MOVW savemask+4(FP), R1
+ MOVW R1, (A0)+
+ MOVW $_psigblocked(SB), R1
+ MOVW R1, (A0)+
+ MOVL A7, (A0)+
+ MOVL (A7), (A0)
+ CLRL R0
+ RTS
+
+TEXT longjmp(SB), 1, $0
+ MOVL b+0(FP), A0
+ MOVL r+4(FP), R0
+ BNE ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVL $1, R0 /* bless their pointed heads */
+ok: MOVL (A0)+, A7
+ MOVL (A0), (A7)
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/strcat.s b/sys/src/ape/lib/ap/68020/strcat.s
new file mode 100755
index 000000000..95821408b
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/strcat.s
@@ -0,0 +1,15 @@
+ TEXT strcat(SB), $0
+ MOVL s1+0(FP), A2
+ MOVL s2+4(FP), A1
+
+l1: TSTB (A2)+
+ BNE l1
+
+ MOVB (A1)+, -1(A2)
+ BEQ done
+
+l2: MOVB (A1)+, (A2)+
+ BNE l2
+
+done: MOVL s1+0(FP), R0
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/strchr.s b/sys/src/ape/lib/ap/68020/strchr.s
new file mode 100755
index 000000000..a5d4be2c6
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/strchr.s
@@ -0,0 +1,27 @@
+ TEXT strchr(SB), $0
+
+ MOVL s+0(FP), A0
+ MOVB c+7(FP), R2
+ BEQ null
+
+l:
+ MOVB (A0)+, R1
+ BEQ out
+ CMPB R1, R2
+ BNE l
+
+ MOVL A0, R0
+ ADDL $-1, R0
+ RTS
+
+out:
+ CLRL R0
+ RTS
+
+null:
+ TSTB (A0)+
+ BNE null
+
+ MOVL A0, R0
+ ADDL $-1, R0
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/strcmp.s b/sys/src/ape/lib/ap/68020/strcmp.s
new file mode 100755
index 000000000..c6072efd7
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/strcmp.s
@@ -0,0 +1,20 @@
+ TEXT strcmp(SB), $0
+ MOVL s1+0(FP), A2
+ MOVL s2+4(FP), A1
+
+l1: MOVB (A1)+, R0
+ BEQ end
+ CMPB R0, (A2)+
+ BEQ l1
+
+ BCS gtr
+ MOVL $-1, R0
+ RTS
+
+gtr: MOVL $1, R0
+ RTS
+
+end: TSTB (A2)
+ BNE gtr
+ CLRL R0
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/strcpy.s b/sys/src/ape/lib/ap/68020/strcpy.s
new file mode 100755
index 000000000..ce5c30bdb
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/strcpy.s
@@ -0,0 +1,10 @@
+ TEXT strcpy(SB), $0
+
+ MOVL s1+0(FP), A2
+ MOVL s2+4(FP), A1
+
+l1: MOVB (A1)+, (A2)+
+ BNE l1
+
+ MOVL s1+0(FP), R0
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/strlen.s b/sys/src/ape/lib/ap/68020/strlen.s
new file mode 100755
index 000000000..4d787c704
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/strlen.s
@@ -0,0 +1,18 @@
+ TEXT strlen(SB), $0
+ MOVL s+0(FP), A1
+
+ TSTB (A1)+
+ BEQ null
+ MOVL A1, A2
+
+l1:
+ TSTB (A1)+
+ BNE l1
+
+ SUBL A2, A1
+ MOVL A1, R0
+ RTS
+
+null:
+ MOVL $0, R0
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/tas.s b/sys/src/ape/lib/ap/68020/tas.s
new file mode 100755
index 000000000..ad5e7a9c9
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/tas.s
@@ -0,0 +1,9 @@
+TEXT tas(SB), $0
+
+ MOVL $0, R0
+ MOVL a+0(FP), A0
+ TAS (A0)
+ BEQ tas_1
+ MOVL $1, R0
+tas_1:
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/vlop.s b/sys/src/ape/lib/ap/68020/vlop.s
new file mode 100755
index 000000000..2f34fd645
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/vlop.s
@@ -0,0 +1,23 @@
+TEXT _mulv(SB), $0
+ MOVL r+0(FP), A0
+ MOVL a+8(FP), R0
+
+ WORD $0x4c2f
+ WORD $0x0401
+ WORD $0x0014
+/*
+ * MULUL b+16(FP), R0:R1
+ * philw made me do it!
+ */
+
+ MOVL a+4(FP), R2
+ MULUL b+16(FP), R2
+ ADDL R2, R1
+
+ MOVL a+8(FP), R2
+ MULUL b+12(FP), R2
+ ADDL R2, R1
+
+ MOVL R1, (A0)+
+ MOVL R0, (A0)
+ RTS
diff --git a/sys/src/ape/lib/ap/68020/vlrt.c b/sys/src/ape/lib/ap/68020/vlrt.c
new file mode 100755
index 000000000..cfad2afc0
--- /dev/null
+++ b/sys/src/ape/lib/ap/68020/vlrt.c
@@ -0,0 +1,730 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_negv(Vlong *r, Vlong a)
+{
+ if(a.lo == 0) {
+ r->hi = -a.hi;
+ r->lo = 0;
+ return;
+ }
+ r->hi = ~a.hi;
+ r->lo = -a.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/sys/src/ape/lib/ap/alpha/_seek.c b/sys/src/ape/lib/ap/alpha/_seek.c
new file mode 100755
index 000000000..7bccc0661
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/_seek.c
@@ -0,0 +1,12 @@
+extern long __SEEK(long long*, int, long long, int);
+
+long long
+_SEEK(int fd, long long o, int p)
+{
+ long long l;
+
+ if(__SEEK(&l, fd, o, p) < 0)
+ l = -1;
+ return l;
+}
+
diff --git a/sys/src/ape/lib/ap/alpha/cycles.c b/sys/src/ape/lib/ap/alpha/cycles.c
new file mode 100755
index 000000000..1c32bc732
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/cycles.c
@@ -0,0 +1,5 @@
+void
+_cycles(unsigned long long *u)
+{
+ *u = 0;
+}
diff --git a/sys/src/ape/lib/ap/alpha/divl.s b/sys/src/ape/lib/ap/alpha/divl.s
new file mode 100755
index 000000000..bce568a8e
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/divl.s
@@ -0,0 +1,189 @@
+/*
+ * ulong
+ * _udiv(ulong num, ulong den)
+ * {
+ * int i;
+ * ulong quo;
+ *
+ * if(den == 0)
+ * *(ulong*)-1 = 0;
+ * quo = num;
+ * if(quo > 1<<(32-1))
+ * quo = 1<<(32-1);
+ * for(i=0; den<quo; i++)
+ * den <<= 1;
+ * quo = 0;
+ * for(; i>=0; i--) {
+ * quo <<= 1;
+ * if(num >= den) {
+ * num -= den;
+ * quo |= 1;
+ * }
+ * den >>= 1;
+ * }
+ * return quo::num;
+ * }
+ */
+
+#define NOPROF 1
+
+/*
+ * calling sequence:
+ * num: 8(R30)
+ * den: 12(R30)
+ * returns
+ * quo: 8(R30)
+ * rem: 12(R30)
+ */
+TEXT _udivmodl(SB), NOPROF, $-8
+
+ MOVQ $-1, R11
+ SLLQ $31, R11 /* (1<<31) in canonical form */
+ MOVL 8(R30), R23 /* numerator */
+ MOVL 12(R30), R10 /* denominator */
+ BNE R10, udm20
+ MOVQ R31, -1(R31) /* fault -- divide by zero; todo: use gentrap? */
+udm20:
+ MOVQ R23, R12
+ BGE R12, udm34
+ MOVQ R11, R12
+udm34:
+ MOVQ R31, R11
+udm38:
+ CMPUGE R10, R12, R24
+ BNE R24, udm54
+ SLLL $1, R10
+ ADDQ $1, R11
+ JMP udm38
+udm54:
+ MOVQ R31, R12
+udm58:
+ BLT R11, udm8c
+ SLLL $1, R12
+ CMPUGE R23, R10, R24
+ BEQ R24, udm7c
+ SUBL R10, R23
+ OR $1, R12
+udm7c:
+ SRLL $1, R10
+ SUBQ $1, R11
+ JMP udm58
+udm8c:
+ MOVL R12, 8(R30) /* quotient */
+ MOVL R23, 12(R30) /* remainder */
+ RET
+
+/*
+ * save working registers
+ * and bring in num/den parameters
+ */
+TEXT _unsargl(SB), NOPROF, $-8
+ MOVQ R10, 24(R30)
+ MOVQ R11, 32(R30)
+ MOVQ R12, 40(R30)
+ MOVQ R23, 48(R30)
+ MOVQ R24, 56(R30)
+
+ MOVL R27, 8(R30)
+ MOVL 72(R30), R27
+ MOVL R27, 12(R30)
+
+ RET
+
+/*
+ * save working registers
+ * and bring in absolute value
+ * of num/den parameters
+ */
+TEXT _absargl(SB), NOPROF, $-8
+ MOVQ R10, 24(R30)
+ MOVQ R11, 32(R30)
+ MOVQ R12, 40(R30)
+ MOVQ R23, 48(R30)
+ MOVQ R24, 56(R30)
+
+ MOVL R27, 64(R30)
+ BGE R27, ab1
+ SUBL R27, R31, R27
+ab1:
+ MOVL R27, 8(R30) /* numerator */
+
+ MOVL 72(R30), R27
+ BGE R27, ab2
+ SUBL R27, R31, R27
+ab2:
+ MOVL R27, 12(R30) /* denominator */
+ RET
+
+/*
+ * restore registers and
+ * return to original caller
+ * answer is in R27
+ */
+TEXT _retargl(SB), NOPROF, $-8
+ MOVQ 24(R30), R10
+ MOVQ 32(R30), R11
+ MOVQ 40(R30), R12
+ MOVQ 48(R30), R23
+ MOVQ 56(R30), R24
+ MOVL 0(R30), R26
+
+ ADDQ $64, R30
+ RET /* back to main sequence */
+
+TEXT _divl(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVL R26, 0(R30)
+
+ JSR _absargl(SB)
+ JSR _udivmodl(SB)
+ MOVL 8(R30), R27
+
+ MOVL 64(R30), R10 /* clean up the sign */
+ MOVL 72(R30), R11
+ XOR R11, R10
+ BGE R10, div1
+ SUBL R27, R31, R27
+div1:
+
+ JSR _retargl(SB)
+ RET /* not executed */
+
+TEXT _divlu(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVL R26, 0(R30)
+
+ JSR _unsargl(SB)
+ JSR _udivmodl(SB)
+ MOVL 8(R30), R27
+
+ JSR _retargl(SB)
+ RET /* not executed */
+
+TEXT _modl(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVL R26, 0(R30)
+
+ JSR _absargl(SB)
+ JSR _udivmodl(SB)
+ MOVL 12(R30), R27
+
+ MOVL 64(R30), R10 /* clean up the sign */
+ BGE R10, div2
+ SUBL R27, R31, R27
+div2:
+
+ JSR _retargl(SB)
+ RET /* not executed */
+
+TEXT _modlu(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVL R26, 0(R30)
+
+ JSR _unsargl(SB)
+ JSR _udivmodl(SB)
+ MOVL 12(R30), R27
+
+ JSR _retargl(SB)
+ RET /* not executed */
+
diff --git a/sys/src/ape/lib/ap/alpha/divq.s b/sys/src/ape/lib/ap/alpha/divq.s
new file mode 100755
index 000000000..98a58e4a8
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/divq.s
@@ -0,0 +1,191 @@
+/*
+ * uvlong
+ * _udiv(uvlong num, uvlong den)
+ * {
+ * int i;
+ * uvlong quo;
+ *
+ * if(den == 0)
+ * *(ulong*)-1 = 0;
+ * quo = num;
+ * if(quo > 1<<(64-1))
+ * quo = 1<<(64-1);
+ * for(i=0; den<quo; i++)
+ * den <<= 1;
+ * quo = 0;
+ * for(; i>=0; i--) {
+ * quo <<= 1;
+ * if(num >= den) {
+ * num -= den;
+ * quo |= 1;
+ * }
+ * den >>= 1;
+ * }
+ * return quo::num;
+ * }
+ */
+
+#define NOPROF 1
+
+/*
+ * calling sequence:
+ * num: 8(R30)
+ * den: 16(R30)
+ * returns
+ * quo: 8(R30)
+ * rem: 16(R30)
+ */
+TEXT _udivmodq(SB), NOPROF, $-8
+
+ MOVQ $1, R11
+ SLLQ $63, R11
+ MOVQ 8(R30), R23 /* numerator */
+ MOVQ 16(R30), R10 /* denominator */
+ BNE R10, udm20
+ MOVQ R31, -1(R31) /* fault -- divide by zero; todo: use gentrap? */
+udm20:
+ MOVQ R23, R12
+ BGE R12, udm34
+ MOVQ R11, R12
+udm34:
+ MOVQ R31, R11
+udm38:
+ CMPUGE R10, R12, R24
+ BNE R24, udm54
+ SLLQ $1, R10
+ ADDQ $1, R11
+ JMP udm38
+udm54:
+ MOVQ R31, R12
+udm58:
+ BLT R11, udm8c
+ SLLQ $1, R12
+ CMPUGE R23, R10, R24
+ BEQ R24, udm7c
+ SUBQ R10, R23
+ OR $1, R12
+udm7c:
+ SRLQ $1, R10
+ SUBQ $1, R11
+ JMP udm58
+udm8c:
+ MOVQ R12, 8(R30) /* quotient */
+ MOVQ R23, 16(R30) /* remainder */
+ RET
+
+/*
+ * save working registers
+ * and bring in num/den parameters
+ */
+TEXT _unsargq(SB), NOPROF, $-8
+ MOVQ R10, 24(R30)
+ MOVQ R11, 32(R30)
+ MOVQ R12, 40(R30)
+ MOVQ R23, 48(R30)
+ MOVQ R24, 56(R30)
+
+ MOVQ R27, 8(R30)
+ MOVQ 72(R30), R27
+ MOVQ R27, 16(R30)
+
+MOVQ (R30), R10 /* debug */
+ RET
+
+/*
+ * save working registers
+ * and bring in absolute value
+ * of num/den parameters
+ */
+TEXT _absargq(SB), NOPROF, $-8
+ MOVQ R10, 24(R30)
+ MOVQ R11, 32(R30)
+ MOVQ R12, 40(R30)
+ MOVQ R23, 48(R30)
+ MOVQ R24, 56(R30)
+
+ MOVQ R27, 64(R30)
+ BGE R27, ab1
+ SUBQ R27, R31, R27
+ab1:
+ MOVQ R27, 8(R30) /* numerator */
+
+ MOVQ 72(R30), R27
+ BGE R27, ab2
+ SUBQ R27, R31, R27
+ab2:
+ MOVQ R27, 16(R30) /* denominator */
+MOVQ (R30), R10 /* debug */
+ RET
+
+/*
+ * restore registers and
+ * return to original caller
+ * answer is in R27
+ */
+TEXT _retargq(SB), NOPROF, $-8
+ MOVQ 24(R30), R10
+ MOVQ 32(R30), R11
+ MOVQ 40(R30), R12
+ MOVQ 48(R30), R23
+ MOVQ 56(R30), R24
+ MOVL 0(R30), R26
+
+ ADDQ $64, R30
+ RET /* back to main sequence */
+
+TEXT _divq(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVQ R26, 0(R30)
+
+ JSR _absargq(SB)
+ JSR _udivmodq(SB)
+ MOVQ 8(R30), R27
+
+ MOVQ 64(R30), R10 /* clean up the sign */
+ MOVQ 72(R30), R11
+ XOR R11, R10
+ BGE R10, div1
+ SUBQ R27, R31, R27
+div1:
+
+ JSR _retargq(SB)
+ RET /* not executed */
+
+TEXT _divqu(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVQ R26, 0(R30)
+
+ JSR _unsargq(SB)
+ JSR _udivmodq(SB)
+ MOVQ 8(R30), R27
+
+ JSR _retargq(SB)
+ RET /* not executed */
+
+TEXT _modq(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVQ R26, 0(R30)
+
+ JSR _absargq(SB)
+ JSR _udivmodq(SB)
+ MOVQ 16(R30), R27
+
+ MOVQ 64(R30), R10 /* clean up the sign */
+ BGE R10, div2
+ SUBQ R27, R31, R27
+div2:
+
+ JSR _retargq(SB)
+ RET /* not executed */
+
+TEXT _modqu(SB), NOPROF, $-8
+ SUBQ $64, R30 /* 5 reg save, 2 parameters, link */
+ MOVQ R26, 0(R30)
+
+ JSR _unsargq(SB)
+ JSR _udivmodq(SB)
+ MOVQ 16(R30), R27
+
+ JSR _retargq(SB)
+ RET /* not executed */
+
diff --git a/sys/src/ape/lib/ap/alpha/getfcr.s b/sys/src/ape/lib/ap/alpha/getfcr.s
new file mode 100755
index 000000000..e3c9f02d8
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/getfcr.s
@@ -0,0 +1,33 @@
+TEXT getfsr(SB), $8
+ TRAPB
+ MOVT FPCR, F0
+ TRAPB
+ MOVT F0, tmp-8(SP)
+ MOVL tmp-4(SP), R0
+ RET
+
+TEXT setfsr(SB), $8
+ SLLQ $32, R0
+ MOVQ R0, tmp-8(SP)
+ MOVT tmp-8(SP), F0
+ TRAPB
+ MOVT F0, FPCR
+ TRAPB
+ RET
+
+TEXT getfcr(SB), $8
+ TRAPB
+ MOVT FPCR, F0
+ TRAPB
+ MOVT F0, tmp-8(SP)
+ MOVL tmp-4(SP), R0
+ RET
+
+TEXT setfcr(SB), $8
+ SLLQ $32, R0
+ MOVQ R0, tmp-8(SP)
+ MOVT tmp-8(SP), F0
+ TRAPB
+ MOVT F0, FPCR
+ TRAPB
+ RET
diff --git a/sys/src/ape/lib/ap/alpha/lock.c b/sys/src/ape/lib/ap/alpha/lock.c
new file mode 100755
index 000000000..91c0ba233
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/lock.c
@@ -0,0 +1,26 @@
+#define _LOCK_EXTENSION
+#include "../plan9/sys9.h"
+#include <lock.h>
+
+int tas(int*);
+
+void
+lock(Lock *lk)
+{
+ while(tas(&lk->val))
+ _SLEEP(0);
+}
+
+int
+canlock(Lock *lk)
+{
+ if(tas(&lk->val))
+ return 0;
+ return 1;
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
diff --git a/sys/src/ape/lib/ap/alpha/main9.s b/sys/src/ape/lib/ap/alpha/main9.s
new file mode 100755
index 000000000..43bdd7bd6
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/main9.s
@@ -0,0 +1,15 @@
+TEXT _main(SB), 1, $16
+
+ MOVQ $setSB(SB), R29
+ JSR _envsetup(SB)
+ MOVL inargc-8(FP), R0
+ MOVL $inargv-4(FP), R1
+ MOVL R0, 8(R30)
+ MOVL R1, 12(R30)
+ JSR main(SB)
+loop:
+ MOVL R0, 8(R30)
+ JSR exit(SB)
+ MOVQ $_divq(SB), R31 /* force loading of divq */
+ MOVQ $_divl(SB), R31 /* force loading of divl */
+ JMP loop
diff --git a/sys/src/ape/lib/ap/alpha/main9p.s b/sys/src/ape/lib/ap/alpha/main9p.s
new file mode 100755
index 000000000..3312100cd
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/main9p.s
@@ -0,0 +1,48 @@
+#define NPRIVATES 16
+
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
+
+TEXT _mainp(SB), 1, $(3*4+NPRIVATES*4)
+ MOVQ $setSB(SB), R29
+
+ /* _tos = arg */
+ MOVL R0, _tos(SB)
+ MOVQ $8(SP), R1
+ MOVL R1, _privates(SB)
+ MOVQ $NPRIVATES, R1
+ MOVL R1, _nprivates(SB)
+
+ /* _profmain(); */
+ JSR _profmain(SB)
+
+ /* _tos->prof.pp = _tos->prof.next; */
+ MOVL _tos+0(SB), R1
+ MOVL 4(R1), R2
+ MOVL R2, 0(R1)
+
+ JSR _envsetup(SB)
+
+ /* main(argc, argv, environ); */
+ MOVL inargc-4(FP), R0
+ MOVL $inargv+0(FP), R1
+ MOVL environ(SB), R2
+ MOVL R0, 8(R30)
+ MOVL R1, 12(R30)
+ MOVL R2, 16(R30)
+ JSR main(SB)
+loop:
+ MOVL R0, 8(R30)
+ JSR exit(SB)
+ MOVQ $_divq(SB), R31 /* force loading of divq */
+ MOVQ $_divl(SB), R31 /* force loading of divl */
+ MOVQ $_profin(SB), R31 /* force loading of profile */
+ JMP loop
+
+TEXT _savearg(SB), 1, $0
+ RET
+
+TEXT _callpc(SB), 1, $0
+ MOVL argp-8(FP), R0
+ RET
diff --git a/sys/src/ape/lib/ap/alpha/memcpy.c b/sys/src/ape/lib/ap/alpha/memcpy.c
new file mode 100755
index 000000000..7bbb55c6e
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/memcpy.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+void*
+memcpy(void *a1, const void *a2, size_t n)
+{
+ return memmove(a1, a2, n);
+}
diff --git a/sys/src/ape/lib/ap/alpha/memmove.s b/sys/src/ape/lib/ap/alpha/memmove.s
new file mode 100755
index 000000000..0fafb752d
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/memmove.s
@@ -0,0 +1,197 @@
+#define QUAD 8
+#define ALIGN 64
+#define BLOCK 64
+
+TEXT memmove(SB), $0
+ MOVL from+4(FP), R7
+ MOVL n+8(FP), R10
+ MOVQ R0, R6
+
+ CMPUGE R7, R0, R5
+ BNE R5, _forward
+
+ MOVQ R6, R8 /* end to address */
+ ADDL R10, R6, R6 /* to+n */
+ ADDL R10, R7, R7 /* from+n */
+
+ CMPUGE $ALIGN, R10, R1 /* need at least ALIGN bytes */
+ BNE R1, _b1tail
+
+_balign:
+ AND $(ALIGN-1), R6, R1
+ BEQ R1, _baligned
+
+ MOVBU -1(R7), R2
+ ADDL $-1, R6, R6
+ MOVB R2, (R6)
+ ADDL $-1, R7, R7
+ JMP _balign
+
+_baligned:
+ AND $(QUAD-1), R7, R1 /* is the source quad-aligned */
+ BNE R1, _bunaligned
+
+ ADDL $(BLOCK-1), R8, R9
+_bblock:
+ CMPUGE R9, R6, R1
+ BNE R1, _b8tail
+
+ MOVQ -64(R7), R22
+ MOVQ -56(R7), R23
+ MOVQ -48(R7), R24
+ MOVQ -40(R7), R25
+ MOVQ -32(R7), R2
+ MOVQ -24(R7), R3
+ MOVQ -16(R7), R4
+ MOVQ -8(R7), R5
+
+ SUBL $64, R6, R6
+ SUBL $64, R7, R7
+
+ MOVQ R22, (R6)
+ MOVQ R23, 8(R6)
+ MOVQ R24, 16(R6)
+ MOVQ R25, 24(R6)
+ MOVQ R2, 32(R6)
+ MOVQ R3, 40(R6)
+ MOVQ R4, 48(R6)
+ MOVQ R5, 56(R6)
+ JMP _bblock
+
+_b8tail:
+ ADDL $(QUAD-1), R8, R9
+_b8block:
+ CMPUGE R9, R6, R1
+ BNE R1, _b1tail
+
+ MOVQ -8(R7), R2
+ SUBL $8, R6
+ MOVQ R2, (R6)
+ SUBL $8, R7
+ JMP _b8block
+
+_b1tail:
+ CMPUGE R8, R6, R1
+ BNE R1, _ret
+
+ MOVBU -1(R7), R2
+ SUBL $1, R6, R6
+ MOVB R2, (R6)
+ SUBL $1, R7, R7
+ JMP _b1tail
+_ret:
+ RET
+
+_bunaligned:
+ ADDL $(16-1), R8, R9
+
+_bu8block:
+ CMPUGE R9, R6, R1
+ BNE R1, _b1tail
+
+ MOVQU -16(R7), R4
+ MOVQU -8(R7), R3
+ MOVQU (R7), R2
+ SUBL $16, R6
+ EXTQH R7, R2, R2
+ EXTQL R7, R3, R5
+ OR R5, R2, R11
+ EXTQH R7, R3, R3
+ EXTQL R7, R4, R4
+ OR R3, R4, R13
+ MOVQ R11, 8(R6)
+ MOVQ R13, (R6)
+ SUBL $16, R7
+ JMP _bu8block
+
+_forward:
+ ADDL R10, R6, R8 /* end to address */
+
+ CMPUGE $ALIGN, R10, R1 /* need at least ALIGN bytes */
+ BNE R1, _f1tail
+
+_falign:
+ AND $(ALIGN-1), R6, R1
+ BEQ R1, _faligned
+
+ MOVBU (R7), R2
+ ADDL $1, R6, R6
+ ADDL $1, R7, R7
+ MOVB R2, -1(R6)
+ JMP _falign
+
+_faligned:
+ AND $(QUAD-1), R7, R1 /* is the source quad-aligned */
+ BNE R1, _funaligned
+
+ SUBL $(BLOCK-1), R8, R9
+_fblock:
+ CMPUGT R9, R6, R1
+ BEQ R1, _f8tail
+
+ MOVQ (R7), R2
+ MOVQ 8(R7), R3
+ MOVQ 16(R7), R4
+ MOVQ 24(R7), R5
+ MOVQ 32(R7), R22
+ MOVQ 40(R7), R23
+ MOVQ 48(R7), R24
+ MOVQ 56(R7), R25
+
+ ADDL $64, R6, R6
+ ADDL $64, R7, R7
+
+ MOVQ R2, -64(R6)
+ MOVQ R3, -56(R6)
+ MOVQ R4, -48(R6)
+ MOVQ R5, -40(R6)
+ MOVQ R22, -32(R6)
+ MOVQ R23, -24(R6)
+ MOVQ R24, -16(R6)
+ MOVQ R25, -8(R6)
+ JMP _fblock
+
+_f8tail:
+ SUBL $(QUAD-1), R8, R9
+_f8block:
+ CMPUGT R9, R6, R1
+ BEQ R1, _f1tail
+
+ MOVQ (R7), R2
+ ADDL $8, R6
+ ADDL $8, R7
+ MOVQ R2, -8(R6)
+ JMP _f8block
+
+_f1tail:
+ CMPUGT R8, R6, R1
+ BEQ R1, _fret
+ MOVBU (R7), R2
+ ADDL $1, R6, R6
+ ADDL $1, R7, R7
+ MOVB R2, -1(R6)
+ JMP _f1tail
+
+_fret:
+ RET
+
+_funaligned:
+ SUBL $(16-1), R8, R9
+_fu8block:
+ CMPUGT R9, R6, R1
+ BEQ R1, _f1tail
+
+ MOVQU (R7), R2
+ MOVQU 8(R7), R3
+ MOVQU 16(R7), R4
+ EXTQL R7, R2, R2
+ EXTQH R7, R3, R5
+ OR R5, R2, R11
+ EXTQL R7, R3, R3
+ MOVQ R11, (R6)
+ EXTQH R7, R4, R4
+ OR R3, R4, R11
+ MOVQ R11, 8(R6)
+ ADDL $16, R6
+ ADDL $16, R7
+ JMP _fu8block
diff --git a/sys/src/ape/lib/ap/alpha/memset.s b/sys/src/ape/lib/ap/alpha/memset.s
new file mode 100755
index 000000000..e3cfd468b
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/memset.s
@@ -0,0 +1,61 @@
+TEXT memset(SB), $0
+ MOVL R0, R6
+ MOVBU data+4(FP), R2
+ MOVL n+8(FP), R10
+
+ ADDL R10, R0, R8
+
+ CMPUGE $8, R10, R1 /* need at least 8 bytes */
+ BNE R1, _1loop
+
+ SLLQ $8, R2, R1 /* replicate the byte */
+ OR R1, R2
+ SLLQ $16, R2, R1
+ OR R1, R2
+ SLLQ $32, R2, R1
+ OR R1, R2
+
+_align:
+ AND $(8-1), R6, R1
+ BEQ R1, _aligned
+
+ MOVB R2, (R6)
+ ADDL $1, R6, R6
+ JMP _align
+
+_aligned:
+ SUBL $(64-1), R8, R9 /* end pointer minus slop */
+_64loop:
+ CMPUGT R9, R6, R1
+ BEQ R1, _8tail
+
+ MOVQ R2, (R6)
+ MOVQ R2, 8(R6)
+ MOVQ R2, 16(R6)
+ MOVQ R2, 24(R6)
+ MOVQ R2, 32(R6)
+ MOVQ R2, 40(R6)
+ MOVQ R2, 48(R6)
+ MOVQ R2, 56(R6)
+ ADDL $64, R6, R6
+ JMP _64loop
+
+_8tail:
+ SUBL $(8-1), R8, R9
+_8loop:
+ CMPUGT R9, R6, R1
+ BEQ R1, _1loop
+
+ MOVQ R2, (R6)
+ ADDL $8, R6
+ JMP _8loop
+
+_1loop:
+ CMPUGT R8, R6, R1
+ BEQ R1, _ret
+ MOVB R2, (R6)
+ ADDL $1, R6
+ JMP _1loop
+
+_ret:
+ RET
diff --git a/sys/src/ape/lib/ap/alpha/mkfile b/sys/src/ape/lib/ap/alpha/mkfile
new file mode 100755
index 000000000..6a1c3ca60
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/mkfile
@@ -0,0 +1,23 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ _seek.$O\
+ cycles.$O\
+ divl.$O\
+ divq.$O\
+ getfcr.$O\
+ lock.$O\
+ main9.$O\
+ main9p.$O\
+ memcpy.$O\
+ memmove.$O\
+ memset.$O\
+ notetramp.$O\
+ setjmp.$O\
+ tas.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE
+
diff --git a/sys/src/ape/lib/ap/alpha/notetramp.c b/sys/src/ape/lib/ap/alpha/notetramp.c
new file mode 100755
index 000000000..6b1be6641
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/notetramp.c
@@ -0,0 +1,72 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#include <signal.h>
+#include <setjmp.h>
+
+/* A stack to hold pcs when signals nest */
+#define MAXSIGSTACK 20
+typedef struct Pcstack Pcstack;
+static struct Pcstack {
+ int sig;
+ void (*hdlr)(int, char*, Ureg*);
+ unsigned long restorepc;
+ Ureg *u;
+} pcstack[MAXSIGSTACK];
+static int nstack = 0;
+
+static void notecont(Ureg*, char*);
+
+void
+_notetramp(int sig, void (*hdlr)(int, char*, Ureg*), Ureg *u)
+{
+ Pcstack *p;
+
+ if(nstack >= MAXSIGSTACK)
+ _NOTED(1); /* nesting too deep; just do system default */
+ p = &pcstack[nstack];
+ p->restorepc = u->pc;
+ p->sig = sig;
+ p->hdlr = hdlr;
+ p->u = u;
+ nstack++;
+ u->pc = (unsigned long) notecont;
+ _NOTED(2); /* NSAVE: clear note but hold state */
+}
+
+static void
+notecont(Ureg *u, char *s)
+{
+ Pcstack *p;
+ void(*f)(int, char*, Ureg*);
+
+ p = &pcstack[nstack-1];
+ f = p->hdlr;
+ u->pc = p->restorepc;
+ nstack--;
+ (*f)(p->sig, s, u);
+ _NOTED(3); /* NRSTR */
+}
+
+#define JMPBUFPC 1
+#define JMPBUFSP 0
+
+extern sigset_t _psigblocked;
+
+void
+siglongjmp(sigjmp_buf j, int ret)
+{
+ struct Ureg *u;
+
+ if(j[0])
+ _psigblocked = j[1];
+ if(nstack == 0 || pcstack[nstack-1].u->sp > j[2+JMPBUFSP])
+ longjmp(j+2, ret);
+ u = pcstack[nstack-1].u;
+ nstack--;
+ u->r0 = ret;
+ if(ret == 0)
+ u->r0 = 1;
+ u->pc = j[2+JMPBUFPC];
+ u->sp = j[2+JMPBUFSP];
+ _NOTED(3); /* NRSTR */
+}
diff --git a/sys/src/ape/lib/ap/alpha/setjmp.s b/sys/src/ape/lib/ap/alpha/setjmp.s
new file mode 100755
index 000000000..3289029a7
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/setjmp.s
@@ -0,0 +1,24 @@
+TEXT setjmp(SB), 1, $-8
+ MOVL R30, (R0)
+ MOVL R26, 4(R0)
+ MOVQ $0, R0
+ RET
+
+TEXT sigsetjmp(SB), 1, $-8
+ MOVL savemask+4(FP), R3
+ MOVL R3, 0(R0)
+ MOVL $_psigblocked(SB), R3
+ MOVL R3, 4(R0)
+ MOVL R30, 8(R0)
+ MOVL R26, 12(R0)
+ MOVQ $0, R0
+ RET
+
+TEXT longjmp(SB), 1, $-8
+ MOVL r+4(FP), R3
+ BNE R3, ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVQ $1, R3 /* bless their pointed heads */
+ok: MOVL (R0), R30
+ MOVL 4(R0), R26
+ MOVL R3, R0
+ RET
diff --git a/sys/src/ape/lib/ap/alpha/tas.s b/sys/src/ape/lib/ap/alpha/tas.s
new file mode 100755
index 000000000..8b3164c3a
--- /dev/null
+++ b/sys/src/ape/lib/ap/alpha/tas.s
@@ -0,0 +1,10 @@
+TEXT tas(SB), $-8
+ MOVQ R0, R1 /* l */
+tas1:
+ MOVLL (R1), R0 /* l->key */
+ BNE R0, tas2
+ MOVQ $1, R2
+ MOVLC R2, (R1) /* l->key = 1 */
+ BEQ R2, tas1 /* write failed, try again? */
+tas2:
+ RET
diff --git a/sys/src/ape/lib/ap/arm/cycles.c b/sys/src/ape/lib/ap/arm/cycles.c
new file mode 100755
index 000000000..1c32bc732
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/cycles.c
@@ -0,0 +1,5 @@
+void
+_cycles(unsigned long long *u)
+{
+ *u = 0;
+}
diff --git a/sys/src/ape/lib/ap/arm/div.s b/sys/src/ape/lib/ap/arm/div.s
new file mode 100755
index 000000000..2f7699c50
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/div.s
@@ -0,0 +1,118 @@
+Q = 0
+N = 1
+D = 2
+CC = 3
+TMP = 11
+
+TEXT save<>(SB), 1, $0
+ MOVW R(Q), 0(FP)
+ MOVW R(N), 4(FP)
+ MOVW R(D), 8(FP)
+ MOVW R(CC), 12(FP)
+
+ MOVW R(TMP), R(Q) /* numerator */
+ MOVW 20(FP), R(D) /* denominator */
+ CMP $0, R(D)
+ BNE s1
+ MOVW -1(R(D)), R(TMP) /* divide by zero fault */
+s1: RET
+
+TEXT rest<>(SB), 1, $0
+ MOVW 0(FP), R(Q)
+ MOVW 4(FP), R(N)
+ MOVW 8(FP), R(D)
+ MOVW 12(FP), R(CC)
+/*
+ * return to caller
+ * of rest<>
+ */
+ MOVW 0(R13), R14
+ ADD $20, R13
+ B (R14)
+
+TEXT div<>(SB), 1, $0
+ MOVW $32, R(CC)
+/*
+ * skip zeros 8-at-a-time
+ */
+e1:
+ AND.S $(0xff<<24),R(Q), R(N)
+ BNE e2
+ SLL $8, R(Q)
+ SUB.S $8, R(CC)
+ BNE e1
+ RET
+e2:
+ MOVW $0, R(N)
+
+loop:
+/*
+ * shift R(N||Q) left one
+ */
+ SLL $1, R(N)
+ CMP $0, R(Q)
+ ORR.LT $1, R(N)
+ SLL $1, R(Q)
+
+/*
+ * compare numerator to denominator
+ * if less, subtract and set quotent bit
+ */
+ CMP R(D), R(N)
+ ORR.HS $1, R(Q)
+ SUB.HS R(D), R(N)
+ SUB.S $1, R(CC)
+ BNE loop
+ RET
+
+TEXT _div(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(Q)
+ BGE d1
+ RSB $0, R(Q), R(Q)
+ CMP $0, R(D)
+ BGE d2
+ RSB $0, R(D), R(D)
+d0:
+ BL div<>(SB) /* none/both neg */
+ MOVW R(Q), R(TMP)
+ B out
+d1:
+ CMP $0, R(D)
+ BGE d0
+ RSB $0, R(D), R(D)
+d2:
+ BL div<>(SB) /* one neg */
+ RSB $0, R(Q), R(TMP)
+ B out
+
+TEXT _mod(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(D)
+ RSB.LT $0, R(D), R(D)
+ CMP $0, R(Q)
+ BGE m1
+ RSB $0, R(Q), R(Q)
+ BL div<>(SB) /* neg numerator */
+ RSB $0, R(N), R(TMP)
+ B out
+m1:
+ BL div<>(SB) /* pos numerator */
+ MOVW R(N), R(TMP)
+ B out
+
+TEXT _divu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(Q), R(TMP)
+ B out
+
+TEXT _modu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(N), R(TMP)
+ B out
+
+out:
+ BL rest<>(SB)
+ B out
diff --git a/sys/src/ape/lib/ap/arm/getfcr.s b/sys/src/ape/lib/ap/arm/getfcr.s
new file mode 100755
index 000000000..b27c7f082
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/getfcr.s
@@ -0,0 +1,16 @@
+
+TEXT setfcr(SB), $4
+ MOVW R0, FPCR
+ RET
+
+TEXT getfcr(SB), $4
+ MOVW FPCR, R0
+ RET
+
+TEXT getfsr(SB), $0
+ MOVW FPSR, R0
+ RET
+
+TEXT setfsr(SB), $0
+ MOVW R0, FPSR
+ RET
diff --git a/sys/src/ape/lib/ap/arm/lock.c b/sys/src/ape/lib/ap/arm/lock.c
new file mode 100755
index 000000000..91c0ba233
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/lock.c
@@ -0,0 +1,26 @@
+#define _LOCK_EXTENSION
+#include "../plan9/sys9.h"
+#include <lock.h>
+
+int tas(int*);
+
+void
+lock(Lock *lk)
+{
+ while(tas(&lk->val))
+ _SLEEP(0);
+}
+
+int
+canlock(Lock *lk)
+{
+ if(tas(&lk->val))
+ return 0;
+ return 1;
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
diff --git a/sys/src/ape/lib/ap/arm/main9.s b/sys/src/ape/lib/ap/arm/main9.s
new file mode 100755
index 000000000..cd04bea17
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/main9.s
@@ -0,0 +1,17 @@
+arg=0
+sp=13
+sb=12
+
+TEXT _main(SB), 1, $16
+ MOVW $setR12(SB), R(sb)
+ BL _envsetup(SB)
+ MOVW $inargv+0(FP), R(arg)
+ MOVW R(arg), 8(R(sp))
+ MOVW inargc-4(FP), R(arg)
+ MOVW R(arg), 4(R(sp))
+ BL main(SB)
+loop:
+ MOVW R(arg), 4(R(sp))
+ BL exit(SB)
+ BL _div(SB)
+ B loop
diff --git a/sys/src/ape/lib/ap/arm/main9p.s b/sys/src/ape/lib/ap/arm/main9p.s
new file mode 100755
index 000000000..f5dc65344
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/main9p.s
@@ -0,0 +1,52 @@
+arg=0
+sp=13
+sb=12
+
+#define NPRIVATES 16
+
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
+
+TEXT _mainp(SB), 1, $(3*4+NPRIVATES*4)
+
+ MOVW $setR12(SB), R(sb)
+
+ /* _tos = arg */
+ MOVW R(arg), _tos(SB)
+ MOVW $private+8(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ /* _profmain(); */
+ BL _profmain(SB)
+
+ /* _tos->prof.pp = _tos->prof.next; */
+ MOVW _tos+0(SB),R1
+ MOVW 4(R1), R2
+ MOVW R2, 0(R1)
+
+ BL _envsetup(SB)
+
+ /* main(argc, argv, environ); */
+ MOVW $inargv+0(FP), R(arg)
+ MOVW R(arg), 8(R(sp))
+ MOVW inargc-4(FP), R(arg)
+ MOVW R(arg), 4(R(sp))
+ MOVW environ(SB), R(arg)
+ MOVW R(arg), 8(R(sp))
+ BL main(SB)
+loop:
+ MOVW R(arg), 4(R(sp))
+ BL exit(SB)
+ MOVW $_div(SB), R(arg) /* force loading of div */
+ MOVW $_profin(SB), R(arg) /* force loading of profile */
+ B loop
+
+TEXT _savearg(SB), 1, $0
+ RET
+
+TEXT _callpc(SB), 1, $0
+ MOVW argp-4(FP), R(arg)
+ RET
diff --git a/sys/src/ape/lib/ap/arm/memmove.s b/sys/src/ape/lib/ap/arm/memmove.s
new file mode 100755
index 000000000..346a23d72
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/memmove.s
@@ -0,0 +1,212 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT memcpy(SB), $-4
+ B _memmove
+TEXT memmove(SB), $-4
+_memmove:
+ MOVW R(TS), to+0(FP) /* need to save for return value */
+ MOVW from+4(FP), R(FROM)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TS), R(TE) /* to end pointer */
+
+ CMP R(FROM), R(TS)
+ BLS _forward
+
+_back:
+ ADD R(N), R(FROM) /* from end pointer */
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _b1tail
+
+_b4align: /* align destination on 4 */
+ AND.S $3, R(TE), R(TMP)
+ BEQ _b4aligned
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b4align
+
+_b4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _bunaligned
+
+ ADD $31, R(TS), R(TMP) /* do 32-byte chunks if possible */
+_b32loop:
+ CMP R(TMP), R(TE)
+ BLS _b4tail
+
+ MOVM.DB.W (R(FROM)), [R4-R7]
+ MOVM.DB.W [R4-R7], (R(TE))
+ MOVM.DB.W (R(FROM)), [R4-R7]
+ MOVM.DB.W [R4-R7], (R(TE))
+ B _b32loop
+
+_b4tail: /* do remaining words if possible */
+ ADD $3, R(TS), R(TMP)
+_b4loop:
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ MOVW.W -4(R(FROM)), R(TMP1) /* pre-indexed */
+ MOVW.W R(TMP1), -4(R(TE)) /* pre-indexed */
+ B _b4loop
+
+_b1tail: /* remaining bytes */
+ CMP R(TE), R(TS)
+ BEQ _return
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b1tail
+
+_forward:
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _f1tail
+
+_f4align: /* align destination on 4 */
+ AND.S $3, R(TS), R(TMP)
+ BEQ _f4aligned
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f4align
+
+_f4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _funaligned
+
+ SUB $31, R(TE), R(TMP) /* do 32-byte chunks if possible */
+_f32loop:
+ CMP R(TMP), R(TS)
+ BHS _f4tail
+
+ MOVM.IA.W (R(FROM)), [R4-R7]
+ MOVM.IA.W [R4-R7], (R(TS))
+ MOVM.IA.W (R(FROM)), [R4-R7]
+ MOVM.IA.W [R4-R7], (R(TS))
+ B _f32loop
+
+_f4tail:
+ SUB $3, R(TE), R(TMP) /* do remaining words if possible */
+_f4loop:
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ MOVW.P 4(R(FROM)), R(TMP1) /* implicit write back */
+ MOVW.P R4, 4(R(TS)) /* implicit write back */
+ B _f4loop
+
+_f1tail:
+ CMP R(TS), R(TE)
+ BEQ _return
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f1tail
+
+_return:
+ MOVW to+0(FP), R0
+ RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 11
+
+BR0 = 6
+BW0 = 7
+BR1 = 7
+BW1 = 8
+
+_bunaligned:
+ CMP $2, R(TMP) /* is R(TMP) < 2 ? */
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n)<<24)|(R(n-1)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $1, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n)<<16)|(R(n-1)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n)<<8)|(R(n-1)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $3, R(OFFSET)
+
+ ADD $8, R(TS), R(TMP) /* do 8-byte chunks if possible */
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ BIC $3, R(FROM) /* align source */
+ MOVW (R(FROM)), R(BR0) /* prime first block register */
+
+_bu8loop:
+ CMP R(TMP), R(TE)
+ BLS _bu1tail
+
+ MOVW R(BR0)<<R(LSHIFT), R(BW1)
+ MOVM.DB.W (R(FROM)), [R(BR0)-R(BR1)]
+ ORR R(BR1)>>R(RSHIFT), R(BW1)
+
+ MOVW R(BR1)<<R(LSHIFT), R(BW0)
+ ORR R(BR0)>>R(RSHIFT), R(BW0)
+
+ MOVM.DB.W [R(BW0)-R(BW1)], (R(TE))
+ B _bu8loop
+
+_bu1tail:
+ ADD R(OFFSET), R(FROM)
+ B _b1tail
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 11
+
+FW0 = 6
+FR0 = 7
+FW1 = 7
+FR1 = 8
+
+_funaligned:
+ CMP $2, R(TMP)
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n+1)<<24)|(R(n)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $3, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n+1)<<16)|(R(n)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n+1)<<8)|(R(n)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $1, R(OFFSET)
+
+ SUB $8, R(TE), R(TMP) /* do 8-byte chunks if possible */
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ BIC $3, R(FROM) /* align source */
+ MOVW.P 4(R(FROM)), R(FR1) /* prime last block register, implicit write back */
+
+_fu8loop:
+ CMP R(TMP), R(TS)
+ BHS _fu1tail
+
+ MOVW R(FR1)>>R(RSHIFT), R(FW0)
+ MOVM.IA.W (R(FROM)), [R(FR0)-R(FR1)]
+ ORR R(FR0)<<R(LSHIFT), R(FW0)
+
+ MOVW R(FR0)>>R(RSHIFT), R(FW1)
+ ORR R(FR1)<<R(LSHIFT), R(FW1)
+
+ MOVM.IA.W [R(FW0)-R(FW1)], (R(TS))
+ B _fu8loop
+
+_fu1tail:
+ SUB R(OFFSET), R(FROM)
+ B _f1tail
diff --git a/sys/src/ape/lib/ap/arm/memset.s b/sys/src/ape/lib/ap/arm/memset.s
new file mode 100755
index 000000000..7ebbb44c3
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/memset.s
@@ -0,0 +1,60 @@
+TO = 1
+TOE = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+
+TEXT memset(SB), $0
+ MOVW R0, R(TO)
+ MOVW data+4(FP), R(4)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TO), R(TOE) /* to end pointer */
+
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _1tail
+
+ AND $0xFF, R(4)
+ ORR R(4)<<8, R(4)
+ ORR R(4)<<16, R(4) /* replicate to word */
+
+_4align: /* align on 4 */
+ AND.S $3, R(TO), R(TMP)
+ BEQ _4aligned
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _4align
+
+_4aligned:
+ SUB $15, R(TOE), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVW R4, R5 /* replicate */
+ MOVW R4, R6
+ MOVW R4, R7
+
+_f16loop:
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVM.IA.W [R4-R7], (R(TO))
+ B _f16loop
+
+_4tail:
+ SUB $3, R(TOE), R(TMP) /* do remaining words if possible */
+_4loop:
+ CMP R(TMP), R(TO)
+ BHS _1tail
+
+ MOVW.P R(4), 4(R(TO)) /* implicit write back */
+ B _4loop
+
+_1tail:
+ CMP R(TO), R(TOE)
+ BEQ _return
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _1tail
+
+_return:
+ RET
diff --git a/sys/src/ape/lib/ap/arm/mkfile b/sys/src/ape/lib/ap/arm/mkfile
new file mode 100755
index 000000000..f65e34395
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/mkfile
@@ -0,0 +1,25 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ cycles.$O\
+ div.$O\
+ getfcr.$O\
+ lock.$O\
+ main9.$O\
+ main9p.$O\
+ memmove.$O\
+ memset.$O\
+ notetramp.$O\
+ setjmp.$O\
+ strchr.$O\
+ strcmp.$O\
+ strcpy.$O\
+ tas.$O\
+ vlop.$O\
+ vlrt.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE
+
diff --git a/sys/src/ape/lib/ap/arm/notetramp.c b/sys/src/ape/lib/ap/arm/notetramp.c
new file mode 100755
index 000000000..6b1be6641
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/notetramp.c
@@ -0,0 +1,72 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#include <signal.h>
+#include <setjmp.h>
+
+/* A stack to hold pcs when signals nest */
+#define MAXSIGSTACK 20
+typedef struct Pcstack Pcstack;
+static struct Pcstack {
+ int sig;
+ void (*hdlr)(int, char*, Ureg*);
+ unsigned long restorepc;
+ Ureg *u;
+} pcstack[MAXSIGSTACK];
+static int nstack = 0;
+
+static void notecont(Ureg*, char*);
+
+void
+_notetramp(int sig, void (*hdlr)(int, char*, Ureg*), Ureg *u)
+{
+ Pcstack *p;
+
+ if(nstack >= MAXSIGSTACK)
+ _NOTED(1); /* nesting too deep; just do system default */
+ p = &pcstack[nstack];
+ p->restorepc = u->pc;
+ p->sig = sig;
+ p->hdlr = hdlr;
+ p->u = u;
+ nstack++;
+ u->pc = (unsigned long) notecont;
+ _NOTED(2); /* NSAVE: clear note but hold state */
+}
+
+static void
+notecont(Ureg *u, char *s)
+{
+ Pcstack *p;
+ void(*f)(int, char*, Ureg*);
+
+ p = &pcstack[nstack-1];
+ f = p->hdlr;
+ u->pc = p->restorepc;
+ nstack--;
+ (*f)(p->sig, s, u);
+ _NOTED(3); /* NRSTR */
+}
+
+#define JMPBUFPC 1
+#define JMPBUFSP 0
+
+extern sigset_t _psigblocked;
+
+void
+siglongjmp(sigjmp_buf j, int ret)
+{
+ struct Ureg *u;
+
+ if(j[0])
+ _psigblocked = j[1];
+ if(nstack == 0 || pcstack[nstack-1].u->sp > j[2+JMPBUFSP])
+ longjmp(j+2, ret);
+ u = pcstack[nstack-1].u;
+ nstack--;
+ u->r0 = ret;
+ if(ret == 0)
+ u->r0 = 1;
+ u->pc = j[2+JMPBUFPC];
+ u->sp = j[2+JMPBUFSP];
+ _NOTED(3); /* NRSTR */
+}
diff --git a/sys/src/ape/lib/ap/arm/setjmp.s b/sys/src/ape/lib/ap/arm/setjmp.s
new file mode 100755
index 000000000..62a06245c
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/setjmp.s
@@ -0,0 +1,29 @@
+arg=0
+link=14
+sp=13
+
+TEXT setjmp(SB), 1, $-4
+ MOVW R(sp), (R(arg+0))
+ MOVW R(link), 4(R(arg+0))
+ MOVW $0, R0
+ RET
+
+TEXT sigsetjmp(SB), 1, $-4
+ MOVW savemask+4(FP), R(arg+2)
+ MOVW R(arg+2), 0(R(arg+0))
+ MOVW $_psigblocked(SB), R(arg+2)
+ MOVW R2, 4(R(arg+0))
+ MOVW R(sp), 8(R(arg+0))
+ MOVW R(link), 12(R(arg+0))
+ MOVW $0, R(arg+0)
+ RET
+
+TEXT longjmp(SB), 1, $-4
+ MOVW r+4(FP), R(arg+2)
+ CMP $0, R(arg+2)
+ BNE ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVW $1, R(arg+2) /* bless their pointed heads */
+ok: MOVW (R(arg+0)), R(sp)
+ MOVW 4(R(arg+0)), R(link)
+ MOVW R(arg+2), R(arg+0)
+ RET
diff --git a/sys/src/ape/lib/ap/arm/strchr.s b/sys/src/ape/lib/ap/arm/strchr.s
new file mode 100755
index 000000000..349b5a49f
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/strchr.s
@@ -0,0 +1,56 @@
+TEXT strchr(SB), $-4
+ MOVBU c+4(FP), R1
+ CMP $0, R1
+ BEQ _null
+
+_strchr: /* not looking for a null, byte at a time */
+ MOVBU.P 1(R0), R2
+ CMP R1, R2
+ BEQ _sub1
+
+ CMP $0, R2
+ BNE _strchr
+
+_return0: /* character not found in string, return 0 */
+ MOVW $0, R0
+ RET
+
+_null: /* looking for null, align */
+ AND.S $3, R0, R2
+ BEQ _aligned
+
+ MOVBU.P 1(R0), R4
+ CMP $0, R4
+ BEQ _sub1
+ B _null
+
+_aligned:
+ MOVW $0xFF, R3 /* mask */
+
+_loop:
+ MOVW.P 4(R0), R4 /* 4 at a time */
+ TST R4, R3 /* AND.S R2, R3, Rx */
+ TST.NE R4>>8, R3
+ TST.NE R4>>16, R3
+ TST.NE R4>>24, R3
+ BNE _loop
+
+ TST R4, R3 /* its somewhere, find it and correct */
+ BEQ _sub4
+ TST R4>>8, R3
+ BEQ _sub3
+ TST R4>>16, R3
+ BEQ _sub2
+
+_sub1: /* compensate for pointer increment */
+ SUB $1, R0
+ RET
+_sub2:
+ SUB $2, R0
+ RET
+_sub3:
+ SUB $3, R0
+ RET
+_sub4:
+ SUB $4, R0
+ RET
diff --git a/sys/src/ape/lib/ap/arm/strcmp.s b/sys/src/ape/lib/ap/arm/strcmp.s
new file mode 100755
index 000000000..015e51596
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/strcmp.s
@@ -0,0 +1,67 @@
+TEXT strcmp(SB), $-4
+ MOVW R0, R1
+ MOVW s2+4(FP), R2
+
+ MOVW $0xFF, R3 /* mask */
+
+_align: /* align s1 on 4 */
+ TST $3, R1
+ BEQ _aligned
+
+ MOVBU.P 1(R1), R4 /* implicit write back */
+ MOVBU.P 1(R2), R8 /* implicit write back */
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+ B _align
+
+_aligned: /* is s2 now aligned? */
+ TST $3, R2
+ BNE _unaligned
+
+_aloop:
+ MOVW.P 4(R1), R5 /* 4 at a time */
+ MOVW.P 4(R2), R7
+
+ AND R5, R3, R4
+ AND R7, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ AND R5>>8, R3, R4
+ AND R7>>8, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ AND R5>>16, R3, R4
+ AND R7>>16, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ AND R5>>24, R3, R4
+ AND R7>>24, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ B _aloop
+
+_return:
+ RET
+
+_unaligned:
+ MOVBU.P 1(R1), R4 /* implicit write back */
+ MOVBU.P 1(R2), R8 /* implicit write back */
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+ B _unaligned
diff --git a/sys/src/ape/lib/ap/arm/strcpy.s b/sys/src/ape/lib/ap/arm/strcpy.s
new file mode 100755
index 000000000..3e69fdc7d
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/strcpy.s
@@ -0,0 +1,46 @@
+TEXT strcpy(SB), $-4
+ MOVW R0, to+0(FP) /* need to save for return value */
+ MOVW from+4(FP), R1
+ MOVW $0xFF, R2 /* mask */
+
+salign: /* align source on 4 */
+ AND.S $3, R1, R3
+ BEQ dalign
+ MOVBU.P 1(R1), R3 /* implicit write back */
+ TST R3, R2
+ MOVBU.P R3, 1(R0) /* implicit write back */
+ BNE salign
+ B return
+
+dalign: /* is destination now aligned? */
+ AND.S $3, R0, R3
+ BNE uloop
+
+aloop:
+ MOVW.P 4(R1), R4 /* read 4, write 4 */
+ TST R4, R2 /* AND.S R3, R2, Rx */
+ TST.NE R4>>8, R2
+ TST.NE R4>>16, R2
+ TST.NE R4>>24, R2
+ BEQ tail
+ MOVW.P R4, 4(R0)
+ B aloop
+
+uloop:
+ MOVW.P 4(R1), R4 /* read 4, write 1,1,1,1 */
+
+tail:
+ AND.S R4, R2, R3
+ MOVBU.NE.P R3, 1(R0)
+ AND.NE.S R4>>8, R2, R3
+ MOVBU.NE.P R3, 1(R0)
+ AND.NE.S R4>>16, R2, R3
+ MOVBU.NE.P R3, 1(R0)
+ AND.NE.S R4>>24, R2, R3
+ MOVBU.P R3, 1(R0)
+ BNE uloop
+ B return
+
+return:
+ MOVW to+0(FP), R0
+ RET
diff --git a/sys/src/ape/lib/ap/arm/tas.s b/sys/src/ape/lib/ap/arm/tas.s
new file mode 100755
index 000000000..f1269209e
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/tas.s
@@ -0,0 +1,5 @@
+TEXT tas(SB), $-4
+ MOVW R0,R1
+ MOVW $1,R0
+ SWPW R0,(R1)
+ RET
diff --git a/sys/src/ape/lib/ap/arm/vlop.s b/sys/src/ape/lib/ap/arm/vlop.s
new file mode 100755
index 000000000..3a5375541
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/vlop.s
@@ -0,0 +1,13 @@
+TEXT _mulv(SB), $0
+ MOVW 4(FP),R8 /* l0 */
+ MOVW 8(FP),R11 /* h0 */
+ MOVW 12(FP),R4 /* l1 */
+ MOVW 16(FP),R5 /* h1 */
+ MULLU R8,R4,(R6, R7) /* l0*l1 */
+ MUL R8,R5,R5 /* l0*h1 */
+ MUL R11,R4,R4 /* h0*l1 */
+ ADD R4,R6
+ ADD R5,R6
+ MOVW R6,4(R0)
+ MOVW R7,0(R0)
+ RET
diff --git a/sys/src/ape/lib/ap/arm/vlrt.c b/sys/src/ape/lib/ap/arm/vlrt.c
new file mode 100755
index 000000000..5e9524d34
--- /dev/null
+++ b/sys/src/ape/lib/ap/arm/vlrt.c
@@ -0,0 +1,708 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ ulong lo;
+ ulong hi;
+};
+
+void abort(void);
+
+/* needed by profiler; can't be profiled */
+#pragma profile off
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+#pragma profile on
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/sys/src/ape/lib/ap/extraobjs b/sys/src/ape/lib/ap/extraobjs
new file mode 100755
index 000000000..66974b2cf
--- /dev/null
+++ b/sys/src/ape/lib/ap/extraobjs
@@ -0,0 +1,37 @@
+#!/bin/rc
+switch($objtype){
+case mips
+ echo G_strcat.$O 9_strchr.$O 9_strcmp.$O 9_strcpy.$O G_strlen.$O\
+ G_strncmp.$O G_strrchr.$O 9_memchr.$O 9_memcmp.$O 9_memmove.$O\
+ 9_memset.$O 9_getfcr.$O 9_vlop.$O 9_vlrt.$O
+
+case 68020
+ echo 9_strcat.$O 9_strchr.$O 9_strcmp.$O 9_strcpy.$O 9_strlen.$O\
+ G_strncmp.$O G_strrchr.$O 9_memchr.$O 9_memcmp.$O 9_memcpy.$O\
+ 9_memmove.$O 9_memset.$O 9_vlop.$O 9_vlrt.$O
+
+case 386
+ echo 9_strcat.$O 9_strchr.$O G_strcmp.$O 9_strcpy.$O 9_strlen.$O\
+ G_strncmp.$O G_strrchr.$O 9_memchr.$O 9_memcmp.$O 9_memcpy.$O\
+ 9_memmove.$O 9_memset.$O 9_vlop.$O 9_vlrt.$O
+
+case arm
+ echo 9_strcat.$O 9_strchr.$O G_strcmp.$O 9_strcpy.$O 9_strlen.$O\
+ G_strncmp.$O G_strrchr.$O 9_memchr.$O 9_memcmp.$O\
+ 9_memmove.$O 9_memset.$O 9_vlop.$O 9_vlrt.$O 9_div.$O
+
+case sparc
+ echo G_strcat.$O 9_strchr.$O 9_strcmp.$O 9_strcpy.$O G_strlen.$O\
+ G_strncmp.$O G_strrchr.$O 9_memchr.$O 9_memcmp.$O 9_memmove.$O\
+ 9_memset.$O 9_muldiv.$O 9_vlop.$O 9_vlrt.$O
+
+case alpha
+ echo G_strcat.$O G_strchr.$O G_strcmp.$O G_strcpy.$O G_strlen.$O\
+ G_strncmp.$O G_strrchr.$O G_memchr.$O G_memcmp.$O 9_memmove.$O\
+ 9_memset.$O 9_memcpy.$O 9_getfcr.$O 9_divl.$O 9_divq.$O
+
+case power
+ echo G_strcat.$O G_strchr.$O G_strcmp.$O G_strcpy.$O G_strlen.$O\
+ G_strncmp.$O G_strrchr.$O G_memchr.$O 9_memcmp.$O 9_memmove.$O\
+ 9_memset.$O 9_getfcr.$O 9_vlop.$O 9_vlrt.$O
+}
diff --git a/sys/src/ape/lib/ap/gen/_assert.c b/sys/src/ape/lib/ap/gen/_assert.c
new file mode 100755
index 000000000..e39e147a4
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/_assert.c
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+
+void
+_assert(char *f, unsigned line)
+{
+ char buf[20], *p, *s = &buf[20];
+ write(2, "assertion failed: file ", 23);
+ for(p = f; *p; p++) continue;
+ write(2, f, p-f);
+ write(2, ":", 7);
+ *--s = '\n';
+ do *--s = line%10 + '0'; while (line /= 10);
+ write(2, s, &buf[20] - s);
+ abort();
+
+}
diff --git a/sys/src/ape/lib/ap/gen/abort.c b/sys/src/ape/lib/ap/gen/abort.c
new file mode 100755
index 000000000..67b878541
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/abort.c
@@ -0,0 +1,9 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+
+void
+abort(void)
+{
+ kill(getpid(), SIGABRT);
+}
diff --git a/sys/src/ape/lib/ap/gen/abs.c b/sys/src/ape/lib/ap/gen/abs.c
new file mode 100755
index 000000000..7d670ffb3
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/abs.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+
+int
+abs(int a)
+{
+ if(a < 0)
+ return -a;
+ return a;
+}
+
+long
+labs(long a)
+{
+ if(a < 0)
+ return -a;
+ return a;
+}
diff --git a/sys/src/ape/lib/ap/gen/atof.c b/sys/src/ape/lib/ap/gen/atof.c
new file mode 100755
index 000000000..63b8bfea4
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/atof.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+double
+atof(const char *s)
+{
+ return(strtod(s, (char **)0));
+}
diff --git a/sys/src/ape/lib/ap/gen/atoi.c b/sys/src/ape/lib/ap/gen/atoi.c
new file mode 100755
index 000000000..8b9bddd41
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/atoi.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+int
+atoi(const char *s)
+{
+ return(strtol(s, (char **)0, 10));
+}
diff --git a/sys/src/ape/lib/ap/gen/atol.c b/sys/src/ape/lib/ap/gen/atol.c
new file mode 100755
index 000000000..41e6040fe
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/atol.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+long
+atol(const char *s)
+{
+ return(strtol(s, (char **)0, 10));
+}
diff --git a/sys/src/ape/lib/ap/gen/atoll.c b/sys/src/ape/lib/ap/gen/atoll.c
new file mode 100755
index 000000000..55f28000a
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/atoll.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+long long
+atoll(const char *s)
+{
+ return(strtoll(s, (char **)0, 10));
+}
diff --git a/sys/src/ape/lib/ap/gen/bsearch.c b/sys/src/ape/lib/ap/gen/bsearch.c
new file mode 100755
index 000000000..ae0342f99
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/bsearch.c
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+#include <stdio.h>
+void*
+bsearch(const void* key, const void* base, size_t nmemb, size_t size,
+ int (*compar)(const void*, const void*))
+{
+ long i, bot, top, new;
+ void *p;
+
+ bot = 0;
+ top = bot + nmemb - 1;
+ while(bot <= top){
+ new = (top + bot)/2;
+ p = (char *)base+new*size;
+ i = (*compar)(key, p);
+ if(i == 0)
+ return p;
+ if(i > 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/gen/calloc.c b/sys/src/ape/lib/ap/gen/calloc.c
new file mode 100755
index 000000000..e52210d84
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/calloc.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+#include <string.h>
+
+void *
+calloc(size_t nmemb, size_t size)
+{
+ void *mp;
+
+ nmemb = nmemb*size;
+ if(mp = malloc(nmemb))
+ memset(mp, 0, nmemb);
+ return(mp);
+}
diff --git a/sys/src/ape/lib/ap/gen/clock.c b/sys/src/ape/lib/ap/gen/clock.c
new file mode 100755
index 000000000..d7d5d4b67
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/clock.c
@@ -0,0 +1,12 @@
+#include <time.h>
+#include <sys/times.h>
+
+clock_t
+clock(void)
+{
+ struct tms t;
+
+ if(times(&t) == (clock_t)-1)
+ return (clock_t)-1;
+ return t.tms_utime+t.tms_stime;
+}
diff --git a/sys/src/ape/lib/ap/gen/ctype.c b/sys/src/ape/lib/ap/gen/ctype.c
new file mode 100755
index 000000000..3829a171a
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/ctype.c
@@ -0,0 +1,56 @@
+#include <ctype.h>
+
+unsigned char _ctype[] =
+{
+/* 0 1 2 3 */
+/* 4 5 6 7 */
+
+/* 0*/ _IScntrl, _IScntrl, _IScntrl, _IScntrl,
+ _IScntrl, _IScntrl, _IScntrl, _IScntrl,
+/* 10*/ _IScntrl, _ISspace|_IScntrl, _ISspace|_IScntrl, _ISspace|_IScntrl,
+ _ISspace|_IScntrl, _ISspace|_IScntrl, _IScntrl, _IScntrl,
+/* 20*/ _IScntrl, _IScntrl, _IScntrl, _IScntrl,
+ _IScntrl, _IScntrl, _IScntrl, _IScntrl,
+/* 30*/ _IScntrl, _IScntrl, _IScntrl, _IScntrl,
+ _IScntrl, _IScntrl, _IScntrl, _IScntrl,
+/* 40*/ _ISspace|_ISblank, _ISpunct, _ISpunct, _ISpunct,
+ _ISpunct, _ISpunct, _ISpunct, _ISpunct,
+/* 50*/ _ISpunct, _ISpunct, _ISpunct, _ISpunct,
+ _ISpunct, _ISpunct, _ISpunct, _ISpunct,
+/* 60*/ _ISdigit|_ISxdigit, _ISdigit|_ISxdigit, _ISdigit|_ISxdigit, _ISdigit|_ISxdigit,
+ _ISdigit|_ISxdigit, _ISdigit|_ISxdigit, _ISdigit|_ISxdigit, _ISdigit|_ISxdigit,
+/* 70*/ _ISdigit|_ISxdigit, _ISdigit|_ISxdigit, _ISpunct, _ISpunct,
+ _ISpunct, _ISpunct, _ISpunct, _ISpunct,
+/*100*/ _ISpunct, _ISupper|_ISxdigit, _ISupper|_ISxdigit, _ISupper|_ISxdigit,
+ _ISupper|_ISxdigit, _ISupper|_ISxdigit, _ISupper|_ISxdigit, _ISupper,
+/*110*/ _ISupper, _ISupper, _ISupper, _ISupper,
+ _ISupper, _ISupper, _ISupper, _ISupper,
+/*120*/ _ISupper, _ISupper, _ISupper, _ISupper,
+ _ISupper, _ISupper, _ISupper, _ISupper,
+/*130*/ _ISupper, _ISupper, _ISupper, _ISpunct,
+ _ISpunct, _ISpunct, _ISpunct, _ISpunct,
+/*140*/ _ISpunct, _ISlower|_ISxdigit, _ISlower|_ISxdigit, _ISlower|_ISxdigit,
+ _ISlower|_ISxdigit, _ISlower|_ISxdigit, _ISlower|_ISxdigit, _ISlower,
+/*150*/ _ISlower, _ISlower, _ISlower, _ISlower,
+ _ISlower, _ISlower, _ISlower, _ISlower,
+/*160*/ _ISlower, _ISlower, _ISlower, _ISlower,
+ _ISlower, _ISlower, _ISlower, _ISlower,
+/*170*/ _ISlower, _ISlower, _ISlower, _ISpunct,
+ _ISpunct, _ISpunct, _ISpunct, _IScntrl,
+/*200*/ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
diff --git a/sys/src/ape/lib/ap/gen/difftime.c b/sys/src/ape/lib/ap/gen/difftime.c
new file mode 100755
index 000000000..97ac3cee9
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/difftime.c
@@ -0,0 +1,9 @@
+#include <time.h>
+
+/* Difference in seconds between two calendar times */
+
+double
+difftime(time_t t1, time_t t0)
+{
+ return (double)t1-(double)t0;
+}
diff --git a/sys/src/ape/lib/ap/gen/div.c b/sys/src/ape/lib/ap/gen/div.c
new file mode 100755
index 000000000..10d92d97b
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/div.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+div_t div(int numer, int denom)
+{
+ div_t ans;
+ ans.quot=numer/denom; /* assumes division truncates */
+ ans.rem=numer-ans.quot*denom;
+ return ans;
+}
diff --git a/sys/src/ape/lib/ap/gen/getenv.c b/sys/src/ape/lib/ap/gen/getenv.c
new file mode 100755
index 000000000..e911d3298
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/getenv.c
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+
+extern char **environ;
+
+char *
+getenv(const char *name)
+{
+ char **p = environ;
+ char *v, *s1, *s2;
+
+ while (*p != NULL){
+ for(s1 = (char *)name, s2 = *p++; *s1 == *s2; s1++, s2++)
+ continue;
+ if(*s1 == '\0' && *s2 == '=')
+ return s2+1;
+ }
+ return NULL ;
+}
diff --git a/sys/src/ape/lib/ap/gen/isalnum.c b/sys/src/ape/lib/ap/gen/isalnum.c
new file mode 100755
index 000000000..e1ab47cde
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/isalnum.c
@@ -0,0 +1,24 @@
+#include <ctype.h>
+
+#undef isalnum
+#undef isalpha
+#undef iscntrl
+#undef isdigit
+#undef isgraph
+#undef islower
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isxdigit
+int isalnum(int c){ return (_ctype+1)[c]&(_ISupper|_ISlower|_ISdigit); }
+int isalpha(int c){ return (_ctype+1)[c]&(_ISupper|_ISlower); }
+int iscntrl(int c){ return (_ctype+1)[c]&_IScntrl; }
+int isdigit(int c){ return (_ctype+1)[c]&_ISdigit; }
+int isgraph(int c){ return (_ctype+1)[c]&(_ISpunct|_ISupper|_ISlower|_ISdigit); }
+int islower(int c){ return (_ctype+1)[c]&_ISlower; }
+int isprint(int c){ return (_ctype+1)[c]&(_ISpunct|_ISupper|_ISlower|_ISdigit|_ISblank); }
+int ispunct(int c){ return (_ctype+1)[c]&_ISpunct; }
+int isspace(int c){ return (_ctype+1)[c]&_ISspace; }
+int isupper(int c){ return (_ctype+1)[c]&_ISupper; }
+int isxdigit(int c){ return (_ctype+1)[c]&_ISxdigit; }
diff --git a/sys/src/ape/lib/ap/gen/itoa.c b/sys/src/ape/lib/ap/gen/itoa.c
new file mode 100755
index 000000000..9e686556b
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/itoa.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+int
+itoa(const char *s)
+{
+ return(strtol(s, (char **)0, 10));
+}
diff --git a/sys/src/ape/lib/ap/gen/itol.c b/sys/src/ape/lib/ap/gen/itol.c
new file mode 100755
index 000000000..a618acc8a
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/itol.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+long
+itol(const char *s)
+{
+ return(strtol(s, (char **)0, 10));
+}
diff --git a/sys/src/ape/lib/ap/gen/ldiv.c b/sys/src/ape/lib/ap/gen/ldiv.c
new file mode 100755
index 000000000..01313e6ac
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/ldiv.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+ldiv_t ldiv(long int numer, long int denom)
+{
+ ldiv_t ans;
+ ans.quot=numer/denom;
+ ans.rem=numer-ans.quot*denom;
+ return ans;
+}
diff --git a/sys/src/ape/lib/ap/gen/mbwc.c b/sys/src/ape/lib/ap/gen/mbwc.c
new file mode 100755
index 000000000..66a982193
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/mbwc.c
@@ -0,0 +1,165 @@
+#include <stdlib.h>
+
+/*
+ * Use the FSS-UTF transformation proposed by posix.
+ * We define 7 byte types:
+ * T0 0xxxxxxx 7 free bits
+ * Tx 10xxxxxx 6 free bits
+ * T1 110xxxxx 5 free bits
+ * T2 1110xxxx 4 free bits
+ *
+ * Encoding is as follows.
+ * From hex Thru hex Sequence Bits
+ * 00000000 0000007F T0 7
+ * 00000080 000007FF T1 Tx 11
+ * 00000800 0000FFFF T2 Tx Tx 16
+ */
+
+int
+mblen(const char *s, size_t n)
+{
+
+ return mbtowc(0, s, n);
+}
+
+int
+mbtowc(wchar_t *pwc, const char *s, size_t n)
+{
+ int c, c1, c2;
+ long l;
+
+ if(!s)
+ return 0;
+
+ if(n < 1)
+ goto bad;
+ c = s[0] & 0xff;
+ if((c & 0x80) == 0x00) {
+ if(pwc)
+ *pwc = c;
+ if(c == 0)
+ return 0;
+ return 1;
+ }
+
+ if(n < 2)
+ goto bad;
+ c1 = (s[1] ^ 0x80) & 0xff;
+ if((c1 & 0xC0) != 0x00)
+ goto bad;
+ if((c & 0xE0) == 0xC0) {
+ l = ((c << 6) | c1) & 0x7FF;
+ if(l < 0x080)
+ goto bad;
+ if(pwc)
+ *pwc = l;
+ return 2;
+ }
+
+ if(n < 3)
+ goto bad;
+ c2 = (s[2] ^ 0x80) & 0xff;
+ if((c2 & 0xC0) != 0x00)
+ goto bad;
+ if((c & 0xF0) == 0xE0) {
+ l = ((((c << 6) | c1) << 6) | c2) & 0xFFFF;
+ if(l < 0x0800)
+ goto bad;
+ if(pwc)
+ *pwc = l;
+ return 3;
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ return -1;
+
+}
+
+int
+wctomb(char *s, wchar_t wchar)
+{
+ long c;
+
+ if(!s)
+ return 0;
+
+ c = wchar & 0xFFFF;
+ if(c < 0x80) {
+ s[0] = c;
+ return 1;
+ }
+
+ if(c < 0x800) {
+ s[0] = 0xC0 | (c >> 6);
+ s[1] = 0x80 | (c & 0x3F);
+ return 2;
+ }
+
+ s[0] = 0xE0 | (c >> 12);
+ s[1] = 0x80 | ((c >> 6) & 0x3F);
+ s[2] = 0x80 | (c & 0x3F);
+ return 3;
+}
+
+size_t
+mbstowcs(wchar_t *pwcs, const char *s, size_t n)
+{
+ int i, d, c;
+
+ for(i=0; i < n; i++) {
+ c = *s & 0xff;
+ if(c < 0x80) {
+ *pwcs = c;
+ if(c == 0)
+ break;
+ s++;
+ } else {
+ d = mbtowc(pwcs, s, 3);
+ if(d <= 0)
+ return (size_t)((d<0) ? -1 : i);
+ s += d;
+ }
+ pwcs++;
+ }
+ return i;
+}
+
+size_t
+wcstombs(char *s, const wchar_t *pwcs, size_t n)
+{
+ int i, d;
+ long c;
+ char *p, *pe;
+ char buf[3];
+
+ p = s;
+ pe = p+n-3;
+ while(p < pe) {
+ c = *pwcs++;
+ if(c < 0x80)
+ *p++ = c;
+ else
+ p += wctomb(p, c);
+ if(c == 0)
+ return p-s;
+ }
+ while(p < pe+3) {
+ c = *pwcs++;
+ d = wctomb(buf, c);
+ if(p+d <= pe+3) {
+ *p++ = buf[0];
+ if(d > 1) {
+ *p++ = buf[2];
+ if(d > 2)
+ *p++ = buf[3];
+ }
+ }
+ if(c == 0)
+ break;
+ }
+ return p-s;
+}
+
diff --git a/sys/src/ape/lib/ap/gen/memccpy.c b/sys/src/ape/lib/ap/gen/memccpy.c
new file mode 100755
index 000000000..2f7b610d2
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/memccpy.c
@@ -0,0 +1,17 @@
+#include <string.h>
+
+void*
+memccpy(void *a1, void *a2, int c, size_t n)
+{
+ unsigned char *s1, *s2;
+
+ s1 = a1;
+ s2 = a2;
+ c &= 0xFF;
+ while(n > 0) {
+ if((*s1++ = *s2++) == c)
+ return s1;
+ n--;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/gen/memchr.c b/sys/src/ape/lib/ap/gen/memchr.c
new file mode 100755
index 000000000..e63aefe8e
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/memchr.c
@@ -0,0 +1,16 @@
+#include <string.h>
+
+void*
+memchr(const void *ap, int c, size_t n)
+{
+ unsigned char *sp;
+
+ sp = ap;
+ c &= 0xFF;
+ while(n > 0) {
+ if(*sp++ == c)
+ return sp-1;
+ n--;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/gen/memcmp.c b/sys/src/ape/lib/ap/gen/memcmp.c
new file mode 100755
index 000000000..c07fbd0e9
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/memcmp.c
@@ -0,0 +1,22 @@
+#include <string.h>
+
+int
+memcmp(const void *a1, const void *a2, size_t n)
+{
+ char *s1, *s2;
+ unsigned c1, c2;
+
+ s1 = a1;
+ s2 = a2;
+ while(n > 0) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ n--;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/gen/memmove.c b/sys/src/ape/lib/ap/gen/memmove.c
new file mode 100755
index 000000000..7eec93f68
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/memmove.c
@@ -0,0 +1,35 @@
+#include <string.h>
+
+void*
+memmove(void *a1, const void *a2, size_t n)
+{
+ char *s1, *s2;
+ extern void abort(void);
+
+ if((long)n < 0)
+ abort();
+ if(a1 > a2)
+ goto back;
+ s1 = a1;
+ s2 = a2;
+ while(n > 0) {
+ *s1++ = *s2++;
+ n--;
+ }
+ return a1;
+
+back:
+ s1 = (char*)a1 + n;
+ s2 = (char*)a2 + n;
+ while(n > 0) {
+ *--s1 = *--s2;
+ n--;
+ }
+ return a1;
+}
+
+void*
+memcpy(void *a1, const void *a2, size_t n)
+{
+ return memmove(a1, a2, n);
+}
diff --git a/sys/src/ape/lib/ap/gen/memset.c b/sys/src/ape/lib/ap/gen/memset.c
new file mode 100755
index 000000000..902874412
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/memset.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+void*
+memset(void *ap, int c, size_t n)
+{
+ char *p;
+
+ p = ap;
+ while(n > 0) {
+ *p++ = c;
+ n--;
+ }
+ return ap;
+}
diff --git a/sys/src/ape/lib/ap/gen/mkfile b/sys/src/ape/lib/ap/gen/mkfile
new file mode 100755
index 000000000..e9653bba1
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/mkfile
@@ -0,0 +1,63 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+
+ALLOFILES=\
+ _assert.$O\
+ abort.$O\
+ abs.$O\
+ atof.$O\
+ atoi.$O\
+ atol.$O\
+ atoll.$O\
+ bsearch.$O\
+ calloc.$O\
+ clock.$O\
+ ctype.$O\
+ difftime.$O\
+ div.$O\
+ getenv.$O\
+ isalnum.$O\
+ itoa.$O\
+ itol.$O\
+ ldiv.$O\
+ mbwc.$O\
+ memccpy.$O\
+ memchr.$O\
+ memcmp.$O\
+ memmove.$O\
+ memset.$O\
+ mktime.$O\
+ qsort.$O\
+ raise.$O\
+ rand.$O\
+ strcat.$O\
+ strchr.$O\
+ strcmp.$O\
+ strcoll.$O\
+ strcpy.$O\
+ strcspn.$O\
+ strftime.$O\
+ strlen.$O\
+ strncat.$O\
+ strncmp.$O\
+ strncpy.$O\
+ strpbrk.$O\
+ strrchr.$O\
+ strspn.$O\
+ strstr.$O\
+ strtod.$O\
+ strtok.$O\
+ strtol.$O\
+ strtoll.$O\
+ strtoul.$O\
+ strtoull.$O\
+ strxfrm.$O\
+ toupper.$O\
+
+# cull things in the per-machine directories from this list
+OFILES= `{rc ./reduce $O $objtype $ALLOFILES}
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE
diff --git a/sys/src/ape/lib/ap/gen/mktime.c b/sys/src/ape/lib/ap/gen/mktime.c
new file mode 100755
index 000000000..2c8fa79fa
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/mktime.c
@@ -0,0 +1,122 @@
+#include <time.h>
+
+/*
+ * BUG: Doesn't do leap years in full glory,
+ * or calendar changes. In 2038 the sign bit
+ * will be needed in time_t, but we say it
+ * can't be represented.
+ */
+static int
+dysize(int y)
+{
+ y += 1900; /* arg is a tm_year, number of years since 1900 */
+ if((y%4) == 0 && ((y%100) !=0 || (y%400) == 0))
+ return 366;
+ return 365;
+}
+
+static int
+dmsize(int m, int y)
+{
+ static char sizes[12] =
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+ if(m == 1)
+ return (dysize(y)==366)? 29 : 28;
+ else
+ return sizes[m];
+}
+
+/* Reduce *v to [0, mult), adding 1 to *next for every mult
+ * subtracted from *v, and return 1 if reduction worked (no overflow)
+ */
+static int
+reduce(int *v, int *next, int mult)
+{
+ int oldnext;
+
+ while(*v < 0){
+ *v += mult;
+ oldnext = *next;
+ --*next;
+ if(!(*next < oldnext))
+ return 0;
+ }
+ while(*v >= mult){
+ *v -= mult;
+ oldnext = *next;
+ ++*next;
+ if(!(*next > oldnext))
+ return 0;
+ }
+ return 1;
+}
+
+static int
+jan1(int yr)
+{
+ int y, d;
+
+ y = yr+1900;
+ d = (4+y+(y+3)/4-(y-1701)/100+(y-1601)/400+3)%7;
+ return d;
+}
+
+time_t
+mktime(struct tm *t)
+{
+ time_t a;
+ int i, d;
+ struct tm *ptm;
+
+ if(!(reduce(&t->tm_sec, &t->tm_min, 60) &&
+ reduce(&t->tm_min, &t->tm_hour, 60) &&
+ reduce(&t->tm_hour, &t->tm_mday, 24) &&
+ reduce(&t->tm_mon, &t->tm_year, 12)))
+ return -1;
+ while(t->tm_mday < 1){
+ if(--t->tm_mon == -1){
+ t->tm_mon = 11;
+ t->tm_year--;
+ }
+ t->tm_mday += dmsize(t->tm_mon, t->tm_year);
+ }
+ while(t->tm_mday > dmsize(t->tm_mon, t->tm_year)){
+ t->tm_mday -= dmsize(t->tm_mon, t->tm_year);
+ if(++t->tm_mon == 12){
+ t->tm_mon = 0;
+ t->tm_year++;
+ }
+ }
+ a = t->tm_sec + 60*t->tm_min + 3600*t->tm_hour;
+ t->tm_yday = t->tm_mday-1;
+ for(i=0; i<t->tm_mon; i++)
+ t->tm_yday += dmsize(i, t->tm_year);
+ a += t->tm_yday*86400L;
+ if(t->tm_year < 70){
+ for(i=t->tm_year; i<70; i++)
+ if((a -= dysize(i)*86400L) < 0)
+ return -1;
+ }else if(t->tm_year > 70){
+ for(i=70; i<t->tm_year; i++)
+ if((a += dysize(i)*86400L) < 0)
+ return -1;
+ }
+ /*
+ * Now a is number of seconds past Jan 1 1970.
+ * Convert to GMT.
+ */
+ ptm = gmtime(&a);
+ d = ptm->tm_hour;
+ ptm = localtime(&a);
+ d -= ptm->tm_hour;
+ if(d < 0)
+ d += 24;
+ if(t->tm_isdst == 0 && ptm->tm_isdst)
+ d--;
+ if(t->tm_isdst > 0 && !ptm->tm_isdst)
+ d++;
+ a += d*3600;
+ t->tm_wday = (jan1(t->tm_year)+t->tm_yday)%7;
+ return a;
+}
diff --git a/sys/src/ape/lib/ap/gen/qsort.c b/sys/src/ape/lib/ap/gen/qsort.c
new file mode 100755
index 000000000..e3fb9d12f
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/qsort.c
@@ -0,0 +1,90 @@
+/* qsort -- qsort interface implemented by faster quicksort */
+#include <stdlib.h>
+
+#define SWAPINIT(a, es) swaptype = \
+ (a - (char*) 0) % sizeof(long) || es % sizeof(long) ? 2 : \
+ es == sizeof(long) ? 0 : 1;
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / (int) sizeof(TYPE); \
+ register TYPE *pi = (TYPE *) (parmi); \
+ register TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ register TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+static void swapfunc(char *a, char *b, int n, int swaptype)
+{ if (swaptype <= 1) swapcode(long, a, b, n)
+ else swapcode(char, a, b, n)
+}
+#define swap(a, b) { \
+ if (swaptype == 0) { \
+ long t = * (long *) (a); \
+ * (long *) (a) = * (long *) (b); \
+ * (long *) (b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype); \
+}
+#define vecswap(a, b, n) { if (n > 0) swapfunc(a, b, n*es, swaptype); }
+
+static char *med3func(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{ return cmp(a, b) < 0 ?
+ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ) )
+ : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ) );
+}
+#define med3(a, b, c) med3func(a, b, c, cmp)
+
+void qsort(void *va, size_t n, size_t es, int (*cmp)(const void *, const void *))
+{
+ char *a, *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int r, swaptype, na, nb, nc, nd, d;
+
+ a = va;
+ SWAPINIT(a, es);
+ if (n < 7) { /* Insertion sort on small arrays */
+ for (pm = a + es; pm < a + n*es; pm += es)
+ for (pl = pm; pl > a && cmp(pl-es, pl) > 0; pl -= es)
+ swap(pl, pl-es);
+ return;
+ }
+ pm = a + (n/2) * es;
+ if (n > 7) {
+ pl = a;
+ pn = a + (n-1) * es;
+ if (n > 40) { /* On big arrays, pseudomedian of 9 */
+ d = (n/8) * es;
+ pl = med3(pl, pl+d, pl+2*d);
+ pm = med3(pm-d, pm, pm+d);
+ pn = med3(pn-2*d, pn-d, pn);
+ }
+ pm = med3(pl, pm, pn); /* On medium arrays, median of 3 */
+ }
+ swap(a, pm); /* On tiny arrays, partition around middle */
+ pa = pb = a + es;
+ pc = pd = pn = a + (n-1)*es;
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+ if (r == 0) { swap(pa, pb); pa += es; }
+ pb += es;
+ }
+ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+ if (r == 0) { swap(pc, pd); pd -= es; }
+ pc -= es;
+ }
+ if (pb > pc) break;
+ swap(pb, pc);
+ pb += es;
+ pc -= es;
+ }
+ na = (pa - a) / es;
+ nb = (pb - pa) / es;
+ nc = (pd - pc) / es;
+ nd = (pn - pd) / es;
+ if (na < nb) { vecswap(a, a + nb*es, na); }
+ else { vecswap(a, a + na*es, nb); }
+ if (nc < nd) { vecswap(pb, pb + nd*es, nc); }
+ else { vecswap(pb, pb + nc*es, nd); }
+ if (nb > 1) qsort(a, nb, es, cmp);
+ if (nc > 1) qsort(a + (n-nc) * es, nc, es, cmp);
+}
diff --git a/sys/src/ape/lib/ap/gen/raise.c b/sys/src/ape/lib/ap/gen/raise.c
new file mode 100755
index 000000000..f93b20d3a
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/raise.c
@@ -0,0 +1,11 @@
+/* not a posix function, but implemented with posix kill, getpid */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+
+int
+raise(int sig)
+{
+ return kill(getpid(), sig);
+}
diff --git a/sys/src/ape/lib/ap/gen/rand.c b/sys/src/ape/lib/ap/gen/rand.c
new file mode 100755
index 000000000..c73ad826c
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/rand.c
@@ -0,0 +1,75 @@
+#include <stdlib.h>
+
+/*
+ * algorithm by
+ * D. P. Mitchell & J. A. Reeds
+ */
+#define LEN 607
+#define TAP 273
+#define MASK 0x7fffffffL
+#define A 48271
+#define M 2147483647
+#define Q 44488
+#define R 3399
+
+typedef unsigned long ulong;
+
+static ulong rng_vec[LEN];
+static ulong* rng_tap = rng_vec;
+static ulong* rng_feed = 0;
+
+void
+srand(unsigned int seed)
+{
+ long lo, hi, x;
+ int i;
+
+ rng_tap = rng_vec;
+ rng_feed = rng_vec+LEN-TAP;
+ seed = seed%M;
+ if(seed < 0)
+ seed += M;
+ if(seed == 0)
+ seed = 89482311;
+ x = seed;
+ /*
+ * Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1)
+ */
+ for(i = -20; i < LEN; i++) {
+ hi = x / Q;
+ lo = x % Q;
+ x = A*lo - R*hi;
+ if(x < 0)
+ x += M;
+ if(i >= 0)
+ rng_vec[i] = x;
+ }
+}
+
+static long
+lrand(void)
+{
+ ulong x;
+
+ rng_tap--;
+ if(rng_tap < rng_vec) {
+ if(rng_feed == 0) {
+ srand(1);
+ rng_tap--;
+ }
+ rng_tap += LEN;
+ }
+ rng_feed--;
+ if(rng_feed < rng_vec)
+ rng_feed += LEN;
+ x = (*rng_feed + *rng_tap) & MASK;
+ *rng_feed = x;
+ return x;
+}
+
+int
+rand(void)
+{
+
+ return lrand() & 0x7fff;
+}
diff --git a/sys/src/ape/lib/ap/gen/reduce b/sys/src/ape/lib/ap/gen/reduce
new file mode 100755
index 000000000..584f8b9ab
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/reduce
@@ -0,0 +1,16 @@
+O=$1
+shift
+objtype=$1
+shift
+
+ls -p ../$objtype/*.[cs] >[2]/dev/null | sed 's/..$//;s/^/^/' > /tmp/reduce.$pid
+#
+# if empty directory, just return the input files
+#
+if (! ~ $status '|') {
+ echo $*
+ rm /tmp/reduce.$pid
+ exit 0
+}
+echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' '
+rm /tmp/reduce.$pid
diff --git a/sys/src/ape/lib/ap/gen/strcat.c b/sys/src/ape/lib/ap/gen/strcat.c
new file mode 100755
index 000000000..6aa75d109
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strcat.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+char*
+strcat(char *s1, const char *s2)
+{
+
+ strcpy(strchr(s1, 0), s2);
+ return s1;
+}
diff --git a/sys/src/ape/lib/ap/gen/strchr.c b/sys/src/ape/lib/ap/gen/strchr.c
new file mode 100755
index 000000000..b6d935f57
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strchr.c
@@ -0,0 +1,18 @@
+#include <string.h>
+
+char*
+strchr(const char *s, int c)
+{
+ char c1;
+
+ if(c == 0) {
+ while(*s++)
+ ;
+ return s-1;
+ }
+
+ while(c1 = *s++)
+ if(c1 == c)
+ return s-1;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/gen/strcmp.c b/sys/src/ape/lib/ap/gen/strcmp.c
new file mode 100755
index 000000000..a9b4827e7
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strcmp.c
@@ -0,0 +1,19 @@
+#include <string.h>
+
+int
+strcmp(const char *s1, const char *s2)
+{
+ unsigned c1, c2;
+
+ for(;;) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ return 0;
+ }
+}
diff --git a/sys/src/ape/lib/ap/gen/strcoll.c b/sys/src/ape/lib/ap/gen/strcoll.c
new file mode 100755
index 000000000..fda140945
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strcoll.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+int
+strcoll(const char *s1, const char *s2)
+{
+ /* BUG: supposed to pay attention to LC_COLLATE of current locale */
+ return strcmp(s1, s2);
+}
diff --git a/sys/src/ape/lib/ap/gen/strcpy.c b/sys/src/ape/lib/ap/gen/strcpy.c
new file mode 100755
index 000000000..6a294eee5
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strcpy.c
@@ -0,0 +1,30 @@
+#include <string.h>
+#define N 10000
+
+static void*
+memccpy(void *a1, void *a2, int c, unsigned long n)
+{
+ char *s1, *s2;
+
+ s1 = a1;
+ s2 = a2;
+ while(n > 0) {
+ if((*s1++ = *s2++) == c)
+ return s1;
+ n--;
+ }
+ return 0;
+}
+
+char*
+strcpy(char *s1, const char *s2)
+{
+ char *os1;
+
+ os1 = s1;
+ while(!memccpy(s1, s2, 0, N)) {
+ s1 += N;
+ s2 += N;
+ }
+ return os1;
+}
diff --git a/sys/src/ape/lib/ap/gen/strcspn.c b/sys/src/ape/lib/ap/gen/strcspn.c
new file mode 100755
index 000000000..f7628e8ae
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strcspn.c
@@ -0,0 +1,20 @@
+#include <string.h>
+
+#define N 256
+
+size_t
+strcspn(const char *s, const char *b)
+{
+ char map[N], *os;
+
+ memset(map, 0, N);
+ for(;;) {
+ map[*(unsigned char*)b] = 1;
+ if(*b++ == 0)
+ break;
+ }
+ os = s;
+ while(map[*(unsigned char*)s++] == 0)
+ ;
+ return s - os - 1;
+}
diff --git a/sys/src/ape/lib/ap/gen/strftime.c b/sys/src/ape/lib/ap/gen/strftime.c
new file mode 100755
index 000000000..f86606089
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strftime.c
@@ -0,0 +1,202 @@
+#include <time.h>
+#include <string.h>
+
+static char *awday[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+static char *wday[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday"};
+static char *amon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+static char *mon[12] = {"January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"};
+static char *ampm[2] = {"AM", "PM"};
+static char *tz[2] = {"EST", "EDT"};
+
+static int jan1(int);
+static char *strval(char *, char *, char **, int, int);
+static char *dval(char *, char *, int, int);
+
+size_t
+strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
+{
+ char *sp, *se, *fp;
+ int i;
+
+ sp = s;
+ se = s+maxsize;
+ for(fp=(char *)format; *fp && sp<se; fp++){
+ if(*fp != '%')
+ *sp++ = *fp;
+ else switch(*++fp){
+ case 'a':
+ sp = strval(sp, se, awday, t->tm_wday, 7);
+ break;
+ case 'A':
+ sp = strval(sp, se, wday, t->tm_wday, 7);
+ break;
+ case 'b':
+ sp = strval(sp, se, amon, t->tm_mon, 12);
+ break;
+ case 'B':
+ sp = strval(sp, se, mon, t->tm_mon, 12);
+ break;
+ case 'c':
+ sp += strftime(sp, se-sp, "%a %b %d %H:%M:%S %Y", t);
+ break;
+ case 'd':
+ sp = dval(sp, se, t->tm_mday, 2);
+ break;
+ case 'H':
+ sp = dval(sp, se, t->tm_hour, 2);
+ break;
+ case 'I':
+ i = t->tm_hour;
+ if(i == 0)
+ i = 12;
+ else if(i > 12)
+ i -= 12;
+ sp = dval(sp, se, i, 2);
+ break;
+ case 'j':
+ sp = dval(sp, se, t->tm_yday+1, 3);
+ break;
+ case 'm':
+ sp = dval(sp, se, t->tm_mon+1, 2);
+ break;
+ case 'M':
+ sp = dval(sp, se, t->tm_min, 2);
+ break;
+ case 'p':
+ i = (t->tm_hour < 12)? 0 : 1;
+ sp = strval(sp, se, ampm, i, 2);
+ break;
+ case 'S':
+ sp = dval(sp, se, t->tm_sec, 2);
+ break;
+ case 'U':
+ i = 7-jan1(t->tm_year);
+ if(i == 7)
+ i = 0;
+ /* Now i is yday number of first sunday in year */
+ if(t->tm_yday < i)
+ i = 0;
+ else
+ i = (t->tm_yday-i)/7 + 1;
+ sp = dval(sp, se, i, 2);
+ break;
+ case 'w':
+ sp = dval(sp, se, t->tm_wday, 1);
+ break;
+ case 'W':
+ i = 8-jan1(t->tm_year);
+ if(i >= 7)
+ i -= 7;
+ /* Now i is yday number of first monday in year */
+ if(t->tm_yday < i)
+ i = 0;
+ else
+ i = (t->tm_yday-i)/7 + 1;
+ sp = dval(sp, se, i, 2);
+ break;
+ case 'x':
+ sp += strftime(sp, se-sp, "%a %b %d, %Y", t);
+ break;
+ case 'X':
+ sp += strftime(sp, se-sp, "%H:%M:%S", t);
+ break;
+ case 'y':
+ sp = dval(sp, se, t->tm_year%100, 2);
+ break;
+ case 'Y':
+ sp = dval(sp, se, t->tm_year+1900, 4);
+ break;
+ case 'Z':
+ /* hack for now: assume eastern time zone */
+ i = t->tm_isdst? 1 : 0;
+ sp = strval(sp, se, tz, i, 2);
+ break;
+ case 0:
+ fp--; /* stop loop after next fp incr */
+ break;
+ default:
+ *sp++ = *fp;
+ }
+ }
+ if(*fp)
+ sp = s; /* format string didn't end: no room for conversion */
+ if(sp<se)
+ *sp = 0;
+ return sp-s;
+}
+
+static char *
+strval(char *start, char *end, char **array, int index, int alen)
+{
+ int n;
+
+ if(index<0 || index>=alen){
+ *start = '?';
+ return start+1;
+ }
+ n = strlen(array[index]);
+ if(n > end-start)
+ n = end-start;
+ memcpy(start, array[index], n);
+ return start+n;
+}
+
+static char *
+dval(char *start, char *end, int val, int width)
+{
+ char *p;
+
+ if(val<0 || end-start<width){
+ *start = '?';
+ return start+1;
+ }
+ p = start+width-1;
+ while(p>=start){
+ *p-- = val%10 + '0';
+ val /= 10;
+ }
+ if(val>0)
+ *start = '*';
+ return start+width;
+}
+
+/*
+ * return day of the week
+ * of jan 1 of given year
+ */
+static int
+jan1(int yr)
+{
+ int y, d;
+
+/*
+ * normal gregorian calendar
+ * one extra day per four years
+ */
+
+ y = yr+1900;
+ d = 4+y+(y+3)/4;
+
+/*
+ * julian calendar
+ * regular gregorian
+ * less three days per 400
+ */
+
+ if(y > 1800) {
+ d -= (y-1701)/100;
+ d += (y-1601)/400;
+ }
+
+/*
+ * great calendar changeover instant
+ */
+
+ if(y > 1752)
+ d += 3;
+
+ return(d%7);
+}
diff --git a/sys/src/ape/lib/ap/gen/strlen.c b/sys/src/ape/lib/ap/gen/strlen.c
new file mode 100755
index 000000000..e339cb16b
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strlen.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+size_t
+strlen(const char *s)
+{
+
+ return strchr(s, 0) - s;
+}
diff --git a/sys/src/ape/lib/ap/gen/strncat.c b/sys/src/ape/lib/ap/gen/strncat.c
new file mode 100755
index 000000000..8891724b4
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strncat.c
@@ -0,0 +1,20 @@
+#include <string.h>
+
+char*
+strncat(char *s1, const char *s2, size_t n)
+{
+ char *os1;
+ long nn;
+
+ os1 = s1;
+ nn = n;
+ while(*s1++)
+ ;
+ s1--;
+ while(*s1++ = *s2++)
+ if(--nn < 0) {
+ s1[-1] = 0;
+ break;
+ }
+ return os1;
+}
diff --git a/sys/src/ape/lib/ap/gen/strncmp.c b/sys/src/ape/lib/ap/gen/strncmp.c
new file mode 100755
index 000000000..e76b09b9d
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strncmp.c
@@ -0,0 +1,23 @@
+#include <string.h>
+
+int
+strncmp(const char *s1, const char *s2, size_t n)
+{
+ unsigned c1, c2;
+ long nn;
+
+ nn = n;
+ while(nn > 0) {
+ c1 = *s1++;
+ c2 = *s2++;
+ nn--;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ break;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/gen/strncpy.c b/sys/src/ape/lib/ap/gen/strncpy.c
new file mode 100755
index 000000000..28a5a522c
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strncpy.c
@@ -0,0 +1,17 @@
+#include <string.h>
+
+char*
+strncpy(char *s1, const char *s2, size_t n)
+{
+ int i;
+ char *os1;
+
+ os1 = s1;
+ for(i = 0; i < n; i++)
+ if((*s1++ = *s2++) == 0) {
+ while(++i < n)
+ *s1++ = 0;
+ return os1;
+ }
+ return os1;
+}
diff --git a/sys/src/ape/lib/ap/gen/strpbrk.c b/sys/src/ape/lib/ap/gen/strpbrk.c
new file mode 100755
index 000000000..407f1c266
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strpbrk.c
@@ -0,0 +1,20 @@
+#include <string.h>
+#define N 256
+
+char*
+strpbrk(const char *s, const char *b)
+{
+ char map[N];
+
+ memset(map, 0, N);
+ for(;;) {
+ map[*b] = 1;
+ if(*b++ == 0)
+ break;
+ }
+ while(map[*s++] == 0)
+ ;
+ if(*--s)
+ return s;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/gen/strrchr.c b/sys/src/ape/lib/ap/gen/strrchr.c
new file mode 100755
index 000000000..038b06ad2
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strrchr.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+char*
+strrchr(const char *s, int c)
+{
+ char *r;
+
+ if(c == 0)
+ return strchr(s, 0);
+ r = 0;
+ while(s = strchr(s, c))
+ r = s++;
+ return r;
+}
diff --git a/sys/src/ape/lib/ap/gen/strspn.c b/sys/src/ape/lib/ap/gen/strspn.c
new file mode 100755
index 000000000..57ebfd1b5
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strspn.c
@@ -0,0 +1,17 @@
+#include <string.h>
+
+#define N 256
+
+size_t
+strspn(const char *s, const char *b)
+{
+ char map[N], *os;
+
+ memset(map, 0, N);
+ while(*b)
+ map[*(unsigned char *)b++] = 1;
+ os = s;
+ while(map[*(unsigned char *)s++])
+ ;
+ return s - os - 1;
+}
diff --git a/sys/src/ape/lib/ap/gen/strstr.c b/sys/src/ape/lib/ap/gen/strstr.c
new file mode 100755
index 000000000..4e6828571
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strstr.c
@@ -0,0 +1,27 @@
+#include <string.h>
+
+/* Return pointer to first occurrence of s2 in s1, NULL if none */
+
+char
+*strstr(const char *s1, const char *s2)
+{
+ char *p, *pa, *pb;
+ int c0, c;
+
+ c0 = *s2;
+ if(c0 == 0)
+ return s1;
+ s2++;
+ for(p=strchr(s1, c0); p; p=strchr(p+1, c0)) {
+ pa = p;
+ for(pb=s2;; pb++) {
+ c = *pb;
+ if(c == 0)
+ return p;
+ if(c != *++pa)
+ break;
+ }
+ }
+ return 0;
+}
+
diff --git a/sys/src/ape/lib/ap/gen/strtod.c b/sys/src/ape/lib/ap/gen/strtod.c
new file mode 100755
index 000000000..ca4939100
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strtod.c
@@ -0,0 +1,91 @@
+#include <math.h>
+#include <errno.h>
+
+/*
+ * bug: should detect overflow, set errno = ERANGE, and return +/- HUGE_VAL
+ */
+double
+strtod(const char *cp, char **endptr)
+{
+ double num, dem;
+ extern double pow10(int);
+ int neg, eneg, dig, predig, exp, c;
+ const char *p;
+
+ p = cp;
+ num = 0;
+ neg = 0;
+ dig = 0;
+ predig = 0;
+ exp = 0;
+ eneg = 0;
+
+ c = *p++;
+ while(c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' || c == '\r')
+ c = *p++;
+ if(c == '-' || c == '+'){
+ if(c == '-')
+ neg = 1;
+ c = *p++;
+ }
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ predig++;
+ c = *p++;
+ }
+ if(c == '.')
+ c = *p++;
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ dig++;
+ c = *p++;
+ }
+ if(dig+predig == 0){
+ if(endptr)
+ *endptr = (char *)cp;
+ return 0.0;
+ }
+ if(c == 'e' || c == 'E'){
+ c = *p++;
+ if(c == '-' || c == '+'){
+ if(c == '-'){
+ dig = -dig;
+ eneg = 1;
+ }
+ c = *p++;
+ }
+ while(c >= '0' && c <= '9'){
+ exp = exp*10 + c-'0';
+ c = *p++;
+ }
+ }
+ exp -= dig;
+ if(exp < 0){
+ exp = -exp;
+ eneg = !eneg;
+ }
+ dem = pow10(exp);
+ if(dem==HUGE_VAL)
+ num = eneg? 0.0 : HUGE_VAL;
+ else if(dem==0)
+ num = eneg? HUGE_VAL : 0.0;
+ else if(eneg)
+ num /= dem;
+ else
+ num *= dem;
+ if(neg)
+ num = -num;
+ if(endptr){
+ *endptr = (char *)--p;
+ /*
+ * Fix cases like 2.3e+
+ */
+ while(p > cp){
+ c = *--p;
+ if(c!='-' && c!='+' && c!='e' && c!='E')
+ break;
+ (*endptr)--;
+ }
+ }
+ return num;
+}
diff --git a/sys/src/ape/lib/ap/gen/strtok.c b/sys/src/ape/lib/ap/gen/strtok.c
new file mode 100755
index 000000000..24155782a
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strtok.c
@@ -0,0 +1,36 @@
+#include <string.h>
+
+#define N 256
+
+char*
+strtok_r(char *s, const char *b, char **last)
+{
+ char map[N], *os;
+
+ memset(map, 0, N);
+ while(*b)
+ map[*(unsigned char*)b++] = 1;
+ if(s == 0)
+ s = *last;
+ while(map[*(unsigned char*)s++])
+ ;
+ if(*--s == 0)
+ return 0;
+ os = s;
+ while(map[*(unsigned char*)s] == 0)
+ if(*s++ == 0) {
+ *last = s-1;
+ return os;
+ }
+ *s++ = 0;
+ *last = s;
+ return os;
+}
+
+char*
+strtok(char *s, const char *b)
+{
+ static char *under_rock;
+
+ return strtok_r(s, b, &under_rock);
+}
diff --git a/sys/src/ape/lib/ap/gen/strtol.c b/sys/src/ape/lib/ap/gen/strtol.c
new file mode 100755
index 000000000..1c5d99632
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strtol.c
@@ -0,0 +1,94 @@
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+
+long
+strtol(const char *nptr, char **endptr, int base)
+{
+ const char *p;
+ long n, nn;
+ int c, ovfl, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ }else if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ }else if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = (char *)p;
+ if(ovfl){
+ errno = ERANGE;
+ if(neg)
+ return LONG_MIN;
+ return LONG_MAX;
+ }
+ if(neg)
+ return -n;
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/gen/strtoll.c b/sys/src/ape/lib/ap/gen/strtoll.c
new file mode 100755
index 000000000..e633d2d08
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strtoll.c
@@ -0,0 +1,103 @@
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+
+#define VLONG_MAX ~(1LL<<63)
+#define VLONG_MIN (1LL<<63)
+
+long long
+strtoll(char *nptr, char **endptr, int base)
+{
+ char *p;
+ long long n, nn, m;
+ int c, ovfl, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;; p++) {
+ switch(*p) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ base = 10;
+ if(*p == '0') {
+ base = 8;
+ if(p[1]=='x' || p[1]=='X') {
+ p += 2;
+ base = 16;
+ }
+ }
+ } else
+ if(base==16 && *p=='0') {
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ } else
+ if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ m = VLONG_MAX/base;
+ for(;; p++,ndig++) {
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else
+ if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else
+ if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ if(n > m)
+ ovfl = 1;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = p;
+ if(ovfl){
+ errno = ERANGE;
+ if(neg)
+ return VLONG_MIN;
+ return VLONG_MAX;
+ }
+ if(neg)
+ return -n;
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/gen/strtoul.c b/sys/src/ape/lib/ap/gen/strtoul.c
new file mode 100755
index 000000000..bb7dce7ae
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strtoul.c
@@ -0,0 +1,92 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+
+unsigned long
+strtoul(const char *nptr, char **endptr, int base)
+{
+ const char *p;
+ unsigned long n, nn;
+ int c, ovfl, neg, v, ndig;
+
+ p = (char*)nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ }else if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ }else if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = (char *)p;
+ if(ovfl){
+ errno = ERANGE;
+ return ULONG_MAX;
+ }
+ if(neg)
+ return -n;
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/gen/strtoull.c b/sys/src/ape/lib/ap/gen/strtoull.c
new file mode 100755
index 000000000..76aa392a4
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strtoull.c
@@ -0,0 +1,100 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+
+#define UVLONG_MAX (1LL<<63)
+
+unsigned long long
+strtoull(char *nptr, char **endptr, int base)
+{
+ char *p;
+ unsigned long long n, nn, m;
+ int c, ovfl, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;; p++) {
+ switch(*p) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p == '-' || *p == '+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base == 0) {
+ base = 10;
+ if(*p == '0') {
+ base = 8;
+ if(p[1] == 'x' || p[1] == 'X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ } else
+ if(base == 16 && *p == '0') {
+ if(p[1] == 'x' || p[1] == 'X')
+ p += 2;
+ } else
+ if(base < 0 || 36 < base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ m = UVLONG_MAX/base;
+ for(;; p++,ndig++) {
+ c = *p;
+ v = base;
+ if('0' <= c && c <= '9')
+ v = c - '0';
+ else
+ if('a' <= c && c <= 'z')
+ v = c - 'a' + 10;
+ else
+ if('A' <= c && c <= 'Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ if(n > m)
+ ovfl = 1;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = p;
+ if(ovfl){
+ errno = ERANGE;
+ return UVLONG_MAX;
+ }
+ if(neg)
+ return -n;
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/gen/strxfrm.c b/sys/src/ape/lib/ap/gen/strxfrm.c
new file mode 100755
index 000000000..ecb095064
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/strxfrm.c
@@ -0,0 +1,17 @@
+#include <string.h>
+
+size_t
+strxfrm(char *s1, const char *s2, size_t n)
+{
+ /*
+ * BUG: supposed to transform s2 to a canonical form
+ * so that strcmp can be used instead of strcoll, but
+ * our strcoll just uses strcmp.
+ */
+
+ size_t xn = strlen(s2);
+ if(n > xn)
+ n = xn;
+ memcpy(s1, s2, n);
+ return xn;
+}
diff --git a/sys/src/ape/lib/ap/gen/toupper.c b/sys/src/ape/lib/ap/gen/toupper.c
new file mode 100755
index 000000000..eb1e8efd5
--- /dev/null
+++ b/sys/src/ape/lib/ap/gen/toupper.c
@@ -0,0 +1,17 @@
+#include <ctype.h>
+
+toupper(int c)
+{
+
+ if(c < 'a' || c > 'z')
+ return c;
+ return (c-'a'+'A');
+}
+
+tolower(int c)
+{
+
+ if(c < 'A' || c > 'Z')
+ return c;
+ return (c-'A'+'a');
+}
diff --git a/sys/src/ape/lib/ap/math/asin.c b/sys/src/ape/lib/ap/math/asin.c
new file mode 100755
index 000000000..efd3a8cc8
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/asin.c
@@ -0,0 +1,47 @@
+/*
+ asin(arg) and acos(arg) return the arcsin, arccos,
+ respectively of their arguments.
+
+ Arctan is called after appropriate range reduction.
+ */
+
+#include <math.h>
+#include <errno.h>
+
+static double pio2 = 1.570796326794896619231e0;
+
+double
+asin(double arg)
+{
+ double temp;
+ int sign;
+
+ sign = 0;
+ if(arg < 0) {
+ arg = -arg;
+ sign++;
+ }
+ if(arg > 1) {
+ errno = EDOM;
+ return 0;
+ }
+ temp = sqrt(1 - arg*arg);
+ if(arg > 0.7)
+ temp = pio2 - atan(temp/arg);
+ else
+ temp = atan(arg/temp);
+
+ if(sign)
+ temp = -temp;
+ return temp;
+}
+
+double
+acos(double arg)
+{
+ if(arg > 1 || arg < -1) {
+ errno = EDOM;
+ return 0;
+ }
+ return pio2 - asin(arg);
+}
diff --git a/sys/src/ape/lib/ap/math/atan.c b/sys/src/ape/lib/ap/math/atan.c
new file mode 100755
index 000000000..a5674d848
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/atan.c
@@ -0,0 +1,86 @@
+/*
+ floating-point arctangent
+
+ atan returns the value of the arctangent of its
+ argument in the range [-pi/2,pi/2].
+
+ atan2 returns the arctangent of arg1/arg2
+ in the range [-pi,pi].
+
+ there are no error returns.
+
+ coefficients are #5077 from Hart & Cheney. (19.56D)
+*/
+
+#include <math.h>
+
+#define sq2p1 2.414213562373095048802e0
+#define sq2m1 .414213562373095048802e0
+#define pio2 1.570796326794896619231e0
+#define pio4 .785398163397448309615e0
+#define p4 .161536412982230228262e2
+#define p3 .26842548195503973794141e3
+#define p2 .11530293515404850115428136e4
+#define p1 .178040631643319697105464587e4
+#define p0 .89678597403663861959987488e3
+#define q4 .5895697050844462222791e2
+#define q3 .536265374031215315104235e3
+#define q2 .16667838148816337184521798e4
+#define q1 .207933497444540981287275926e4
+#define q0 .89678597403663861962481162e3
+
+
+/*
+ xatan evaluates a series valid in the
+ range [-0.414...,+0.414...].
+ */
+
+static
+double
+xatan(double arg)
+{
+ double argsq, value;
+
+ /* get denormalized add in following if range arg**10 is much smaller
+ than q1, so check for that case
+ */
+ if(-.01 < arg && arg < .01)
+ value = p0/q0;
+ else {
+ argsq = arg*arg;
+ value = ((((p4*argsq + p3)*argsq + p2)*argsq + p1)*argsq + p0);
+ value = value/(((((argsq + q4)*argsq + q3)*argsq + q2)*argsq + q1)*argsq + q0);
+ }
+ return value*arg;
+}
+
+/*
+ satan reduces its argument (known to be positive)
+ to the range [0,0.414...] and calls xatan.
+ */
+
+static
+double
+satan(double arg)
+{
+
+ if(arg < sq2m1)
+ return xatan(arg);
+ if(arg > sq2p1)
+ return pio2 - xatan(1.0/arg);
+ return pio4 + xatan((arg-1.0)/(arg+1.0));
+}
+
+/*
+ atan makes its argument positive and
+ calls the inner routine satan.
+ */
+
+double
+atan(double arg)
+{
+
+ if(arg > 0)
+ return satan(arg);
+ return -satan(-arg);
+}
diff --git a/sys/src/ape/lib/ap/math/atan2.c b/sys/src/ape/lib/ap/math/atan2.c
new file mode 100755
index 000000000..51c535329
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/atan2.c
@@ -0,0 +1,30 @@
+#include <math.h>
+#include <errno.h>
+/*
+ atan2 discovers what quadrant the angle
+ is in and calls atan.
+*/
+#define pio2 1.5707963267948966192313217
+#define pi 3.1415926535897932384626434;
+
+double
+atan2(double arg1, double arg2)
+{
+
+ if(arg1 == 0.0 && arg2 == 0.0){
+ errno = EDOM;
+ return 0.0;
+ }
+ if(arg1+arg2 == arg1) {
+ if(arg1 >= 0)
+ return pio2;
+ return -pio2;
+ }
+ arg1 = atan(arg1/arg2);
+ if(arg2 < 0) {
+ if(arg1 <= 0)
+ return arg1 + pi;
+ return arg1 - pi;
+ }
+ return arg1;
+}
diff --git a/sys/src/ape/lib/ap/math/erf.c b/sys/src/ape/lib/ap/math/erf.c
new file mode 100755
index 000000000..60ba4ee05
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/erf.c
@@ -0,0 +1,116 @@
+#include <math.h>
+#include <errno.h>
+/*
+ C program for floating point error function
+
+ erf(x) returns the error function of its argument
+ erfc(x) returns 1 - erf(x)
+
+ erf(x) is defined by
+ ${2 over sqrt(pi)} int from 0 to x e sup {-t sup 2} dt$
+
+ the entry for erfc is provided because of the
+ extreme loss of relative accuracy if erf(x) is
+ called for large x and the result subtracted
+ from 1. (e.g. for x= 10, 12 places are lost).
+
+ There are no error returns.
+
+ Calls exp.
+
+ Coefficients for large x are #5667 from Hart & Cheney (18.72D).
+*/
+
+#define M 7
+#define N 9
+static double torp = 1.1283791670955125738961589031;
+static double p1[] = {
+ 0.804373630960840172832162e5,
+ 0.740407142710151470082064e4,
+ 0.301782788536507577809226e4,
+ 0.380140318123903008244444e2,
+ 0.143383842191748205576712e2,
+ -.288805137207594084924010e0,
+ 0.007547728033418631287834e0,
+};
+static double q1[] = {
+ 0.804373630960840172826266e5,
+ 0.342165257924628539769006e5,
+ 0.637960017324428279487120e4,
+ 0.658070155459240506326937e3,
+ 0.380190713951939403753468e2,
+ 0.100000000000000000000000e1,
+ 0.0,
+};
+static double p2[] = {
+ 0.18263348842295112592168999e4,
+ 0.28980293292167655611275846e4,
+ 0.2320439590251635247384768711e4,
+ 0.1143262070703886173606073338e4,
+ 0.3685196154710010637133875746e3,
+ 0.7708161730368428609781633646e2,
+ 0.9675807882987265400604202961e1,
+ 0.5641877825507397413087057563e0,
+ 0.0,
+};
+static double q2[] = {
+ 0.18263348842295112595576438e4,
+ 0.495882756472114071495438422e4,
+ 0.60895424232724435504633068e4,
+ 0.4429612803883682726711528526e4,
+ 0.2094384367789539593790281779e4,
+ 0.6617361207107653469211984771e3,
+ 0.1371255960500622202878443578e3,
+ 0.1714980943627607849376131193e2,
+ 1.0,
+};
+
+double erfc(double);
+
+double
+erf(double arg)
+{
+ int sign;
+ double argsq;
+ double d, n;
+ int i;
+
+ errno = 0;
+ sign = 1;
+ if(arg < 0) {
+ arg = -arg;
+ sign = -1;
+ }
+ if(arg < 0.5) {
+ argsq = arg*arg;
+ for(n=0,d=0,i=M-1; i>=0; i--) {
+ n = n*argsq + p1[i];
+ d = d*argsq + q1[i];
+ }
+ return sign*torp*arg*n/d;
+ }
+ if(arg >= 10)
+ return sign;
+ return sign*(1 - erfc(arg));
+}
+
+double
+erfc(double arg)
+{
+ double n, d;
+ int i;
+
+ errno = 0;
+ if(arg < 0)
+ return 2 - erfc(-arg);
+ if(arg < 0.5)
+ return 1 - erf(arg);
+ if(arg >= 10)
+ return 0;
+
+ for(n=0,d=0,i=N-1; i>=0; i--) {
+ n = n*arg + p2[i];
+ d = d*arg + q2[i];
+ }
+ return exp(-arg*arg)*n/d;
+}
diff --git a/sys/src/ape/lib/ap/math/exp.c b/sys/src/ape/lib/ap/math/exp.c
new file mode 100755
index 000000000..06d21d70f
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/exp.c
@@ -0,0 +1,44 @@
+/*
+ exp returns the exponential function of its
+ floating-point argument.
+
+ The coefficients are #1069 from Hart and Cheney. (22.35D)
+*/
+
+#include <math.h>
+#include <errno.h>
+
+#define p0 .2080384346694663001443843411e7
+#define p1 .3028697169744036299076048876e5
+#define p2 .6061485330061080841615584556e2
+#define q0 .6002720360238832528230907598e7
+#define q1 .3277251518082914423057964422e6
+#define q2 .1749287689093076403844945335e4
+#define log2e 1.4426950408889634073599247
+#define sqrt2 1.4142135623730950488016887
+#define maxf 10000
+
+double
+exp(double arg)
+{
+ double fract, temp1, temp2, xsq;
+ int ent;
+
+ if(arg == 0)
+ return 1;
+ if(arg < -maxf) {
+ errno = ERANGE;
+ return 0;
+ }
+ if(arg > maxf) {
+ errno = ERANGE;
+ return HUGE_VAL;
+ }
+ arg *= log2e;
+ ent = floor(arg);
+ fract = (arg-ent) - 0.5;
+ xsq = fract*fract;
+ temp1 = ((p2*xsq+p1)*xsq+p0)*fract;
+ temp2 = ((xsq+q2)*xsq+q1)*xsq + q0;
+ return ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent);
+}
diff --git a/sys/src/ape/lib/ap/math/fabs.c b/sys/src/ape/lib/ap/math/fabs.c
new file mode 100755
index 000000000..5566e165b
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/fabs.c
@@ -0,0 +1,10 @@
+#include <math.h>
+
+double
+fabs(double arg)
+{
+
+ if(arg < 0)
+ return -arg;
+ return arg;
+}
diff --git a/sys/src/ape/lib/ap/math/floor.c b/sys/src/ape/lib/ap/math/floor.c
new file mode 100755
index 000000000..dfab000c1
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/floor.c
@@ -0,0 +1,26 @@
+#include <math.h>
+/*
+ * floor and ceil-- greatest integer <= arg
+ * (resp least >=)
+ */
+
+double
+floor(double d)
+{
+ double fract;
+
+ if(d < 0) {
+ fract = modf(-d, &d);
+ if(fract != 0.0)
+ d += 1;
+ d = -d;
+ } else
+ modf(d, &d);
+ return d;
+}
+
+double
+ceil(double d)
+{
+ return -floor(-d);
+}
diff --git a/sys/src/ape/lib/ap/math/fmod.c b/sys/src/ape/lib/ap/math/fmod.c
new file mode 100755
index 000000000..876c64c39
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/fmod.c
@@ -0,0 +1,27 @@
+/* floating-point mod function without infinity or NaN checking */
+#include <math.h>
+double
+fmod (double x, double y)
+{
+ int sign = 0, yexp;
+ double r, yfr;
+
+ if (y == 0)
+ return 0;
+ if (y < 0)
+ y = -y;
+ yfr = frexp (y, &yexp);
+ if (x < 0) {
+ sign = 1;
+ r = -x;
+ } else
+ r = x;
+ while (r >= y) {
+ int rexp;
+ double rfr = frexp (r, &rexp);
+ r -= ldexp (y, rexp - yexp - (rfr < yfr));
+ }
+ if (sign)
+ r = -r;
+ return r;
+}
diff --git a/sys/src/ape/lib/ap/math/gamma.c b/sys/src/ape/lib/ap/math/gamma.c
new file mode 100755
index 000000000..7b541042b
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/gamma.c
@@ -0,0 +1,116 @@
+#include <math.h>
+#include <errno.h>
+
+/*
+ C program for floating point log gamma function
+
+ gamma(x) computes the log of the absolute
+ value of the gamma function.
+ The sign of the gamma function is returned in the
+ external quantity signgam.
+
+ The coefficients for expansion around zero
+ are #5243 from Hart & Cheney; for expansion
+ around infinity they are #5404.
+
+ Calls log and sin.
+*/
+
+int signgam;
+static double goobie = 0.9189385332046727417803297;
+static double pi = 3.1415926535897932384626434;
+
+#define M 6
+#define N 8
+static double p1[] = {
+ 0.83333333333333101837e-1,
+ -.277777777735865004e-2,
+ 0.793650576493454e-3,
+ -.5951896861197e-3,
+ 0.83645878922e-3,
+ -.1633436431e-2,
+};
+static double p2[] = {
+ -.42353689509744089647e5,
+ -.20886861789269887364e5,
+ -.87627102978521489560e4,
+ -.20085274013072791214e4,
+ -.43933044406002567613e3,
+ -.50108693752970953015e2,
+ -.67449507245925289918e1,
+ 0.0,
+};
+static double q2[] = {
+ -.42353689509744090010e5,
+ -.29803853309256649932e4,
+ 0.99403074150827709015e4,
+ -.15286072737795220248e4,
+ -.49902852662143904834e3,
+ 0.18949823415702801641e3,
+ -.23081551524580124562e2,
+ 0.10000000000000000000e1,
+};
+
+static double
+asym(double arg)
+{
+ double n, argsq;
+ int i;
+
+ argsq = 1 / (arg*arg);
+ n = 0;
+ for(i=M-1; i>=0; i--)
+ n = n*argsq + p1[i];
+ return (arg-.5)*log(arg) - arg + goobie + n/arg;
+}
+
+static double
+pos(double arg)
+{
+ double n, d, s;
+ int i;
+
+ if(arg < 2)
+ return pos(arg+1)/arg;
+ if(arg > 3)
+ return (arg-1)*pos(arg-1);
+
+ s = arg - 2;
+ n = 0;
+ d = 0;
+ for(i=N-1; i>=0; i--){
+ n = n*s + p2[i];
+ d = d*s + q2[i];
+ }
+ return n/d;
+}
+
+static double
+neg(double arg)
+{
+ double temp;
+
+ arg = -arg;
+ temp = sin(pi*arg);
+ if(temp == 0) {
+ errno = EDOM;
+ return HUGE_VAL;
+ }
+ if(temp < 0)
+ temp = -temp;
+ else
+ signgam = -1;
+ return -log(arg*pos(arg)*temp/pi);
+}
+
+double
+gamma(double arg)
+{
+
+ signgam = 1;
+ if(arg <= 0)
+ return neg(arg);
+ if(arg > 8)
+ return asym(arg);
+ return log(pos(arg));
+}
diff --git a/sys/src/ape/lib/ap/math/hypot.c b/sys/src/ape/lib/ap/math/hypot.c
new file mode 100755
index 000000000..25457d8a9
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/hypot.c
@@ -0,0 +1,29 @@
+#include <math.h>
+/*
+ * sqrt(a^2 + b^2)
+ * (but carefully)
+ */
+
+double
+hypot(double a, double b)
+{
+ double t;
+
+ if(a < 0)
+ a = -a;
+ if(b < 0)
+ b = -b;
+ if(a > b) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ if(b == 0)
+ return 0;
+ a /= b;
+ /*
+ * pathological overflow possible
+ * in the next line.
+ */
+ return b * sqrt(1 + a*a);
+}
diff --git a/sys/src/ape/lib/ap/math/j0.c b/sys/src/ape/lib/ap/math/j0.c
new file mode 100755
index 000000000..7dea3c9d1
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/j0.c
@@ -0,0 +1,188 @@
+#include <math.h>
+#include <errno.h>
+/*
+ floating point Bessel's function
+ of the first and second kinds
+ of order zero
+
+ j0(x) returns the value of J0(x)
+ for all real values of x.
+
+ There are no error returns.
+ Calls sin, cos, sqrt.
+
+ There is a niggling bug in J0 which
+ causes errors up to 2e-16 for x in the
+ interval [-8,8].
+ The bug is caused by an inappropriate order
+ of summation of the series. rhm will fix it
+ someday.
+
+ Coefficients are from Hart & Cheney.
+ #5849 (19.22D)
+ #6549 (19.25D)
+ #6949 (19.41D)
+
+ y0(x) returns the value of Y0(x)
+ for positive real values of x.
+ For x<=0, error number EDOM is set and a
+ large negative value is returned.
+
+ Calls sin, cos, sqrt, log, j0.
+
+ The values of Y0 have not been checked
+ to more than ten places.
+
+ Coefficients are from Hart & Cheney.
+ #6245 (18.78D)
+ #6549 (19.25D)
+ #6949 (19.41D)
+*/
+
+static double pzero, qzero;
+static double tpi = .6366197723675813430755350535e0;
+static double pio4 = .7853981633974483096156608458e0;
+static double p1[] = {
+ 0.4933787251794133561816813446e21,
+ -.1179157629107610536038440800e21,
+ 0.6382059341072356562289432465e19,
+ -.1367620353088171386865416609e18,
+ 0.1434354939140344111664316553e16,
+ -.8085222034853793871199468171e13,
+ 0.2507158285536881945555156435e11,
+ -.4050412371833132706360663322e8,
+ 0.2685786856980014981415848441e5,
+};
+static double q1[] = {
+ 0.4933787251794133562113278438e21,
+ 0.5428918384092285160200195092e19,
+ 0.3024635616709462698627330784e17,
+ 0.1127756739679798507056031594e15,
+ 0.3123043114941213172572469442e12,
+ 0.6699987672982239671814028660e9,
+ 0.1114636098462985378182402543e7,
+ 0.1363063652328970604442810507e4,
+ 1.0
+};
+static double p2[] = {
+ 0.5393485083869438325262122897e7,
+ 0.1233238476817638145232406055e8,
+ 0.8413041456550439208464315611e7,
+ 0.2016135283049983642487182349e7,
+ 0.1539826532623911470917825993e6,
+ 0.2485271928957404011288128951e4,
+ 0.0,
+};
+static double q2[] = {
+ 0.5393485083869438325560444960e7,
+ 0.1233831022786324960844856182e8,
+ 0.8426449050629797331554404810e7,
+ 0.2025066801570134013891035236e7,
+ 0.1560017276940030940592769933e6,
+ 0.2615700736920839685159081813e4,
+ 1.0,
+};
+static double p3[] = {
+ -.3984617357595222463506790588e4,
+ -.1038141698748464093880530341e5,
+ -.8239066313485606568803548860e4,
+ -.2365956170779108192723612816e4,
+ -.2262630641933704113967255053e3,
+ -.4887199395841261531199129300e1,
+ 0.0,
+};
+static double q3[] = {
+ 0.2550155108860942382983170882e6,
+ 0.6667454239319826986004038103e6,
+ 0.5332913634216897168722255057e6,
+ 0.1560213206679291652539287109e6,
+ 0.1570489191515395519392882766e5,
+ 0.4087714673983499223402830260e3,
+ 1.0,
+};
+static double p4[] = {
+ -.2750286678629109583701933175e20,
+ 0.6587473275719554925999402049e20,
+ -.5247065581112764941297350814e19,
+ 0.1375624316399344078571335453e18,
+ -.1648605817185729473122082537e16,
+ 0.1025520859686394284509167421e14,
+ -.3436371222979040378171030138e11,
+ 0.5915213465686889654273830069e8,
+ -.4137035497933148554125235152e5,
+};
+static double q4[] = {
+ 0.3726458838986165881989980e21,
+ 0.4192417043410839973904769661e19,
+ 0.2392883043499781857439356652e17,
+ 0.9162038034075185262489147968e14,
+ 0.2613065755041081249568482092e12,
+ 0.5795122640700729537480087915e9,
+ 0.1001702641288906265666651753e7,
+ 0.1282452772478993804176329391e4,
+ 1.0,
+};
+
+static
+asympt(double arg)
+{
+ double zsq, n, d;
+ int i;
+
+ zsq = 64 / (arg*arg);
+ for(n=0,d=0,i=6;i>=0;i--) {
+ n = n*zsq + p2[i];
+ d = d*zsq + q2[i];
+ }
+ pzero = n/d;
+ for(n=0,d=0,i=6;i>=0;i--) {
+ n = n*zsq + p3[i];
+ d = d*zsq + q3[i];
+ }
+ qzero = (8/arg)*(n/d);
+}
+
+double
+j0(double arg)
+{
+ double argsq, n, d;
+ int i;
+
+ if(arg < 0)
+ arg = -arg;
+ if(arg > 8) {
+ asympt(arg);
+ n = arg - pio4;
+ return sqrt(tpi/arg)*(pzero*cos(n) - qzero*sin(n));
+ }
+ argsq = arg*arg;
+ for(n=0,d=0,i=8;i>=0;i--) {
+ n = n*argsq + p1[i];
+ d = d*argsq + q1[i];
+ }
+ return n/d;
+}
+
+double
+y0(double arg)
+{
+ double argsq, n, d;
+ int i;
+
+ errno = 0;
+ if(arg <= 0) {
+ errno = EDOM;
+ return(-HUGE_VAL);
+ }
+ if(arg > 8) {
+ asympt(arg);
+ n = arg - pio4;
+ return sqrt(tpi/arg)*(pzero*sin(n) + qzero*cos(n));
+ }
+ argsq = arg*arg;
+ for(n=0,d=0,i=8;i>=0;i--) {
+ n = n*argsq + p4[i];
+ d = d*argsq + q4[i];
+ }
+ return n/d + tpi*j0(arg)*log(arg);
+}
diff --git a/sys/src/ape/lib/ap/math/j1.c b/sys/src/ape/lib/ap/math/j1.c
new file mode 100755
index 000000000..38c73fe2b
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/j1.c
@@ -0,0 +1,195 @@
+#include <math.h>
+#include <errno.h>
+/*
+ floating point Bessel's function
+ of the first and second kinds
+ of order one
+
+ j1(x) returns the value of J1(x)
+ for all real values of x.
+
+ There are no error returns.
+ Calls sin, cos, sqrt.
+
+ There is a niggling bug in J1 which
+ causes errors up to 2e-16 for x in the
+ interval [-8,8].
+ The bug is caused by an inappropriate order
+ of summation of the series. rhm will fix it
+ someday.
+
+ Coefficients are from Hart & Cheney.
+ #6050 (20.98D)
+ #6750 (19.19D)
+ #7150 (19.35D)
+
+ y1(x) returns the value of Y1(x)
+ for positive real values of x.
+ For x<=0, error number EDOM is set and a
+ large negative value is returned.
+
+ Calls sin, cos, sqrt, log, j1.
+
+ The values of Y1 have not been checked
+ to more than ten places.
+
+ Coefficients are from Hart & Cheney.
+ #6447 (22.18D)
+ #6750 (19.19D)
+ #7150 (19.35D)
+*/
+
+static double pzero, qzero;
+static double tpi = .6366197723675813430755350535e0;
+static double pio4 = .7853981633974483096156608458e0;
+static double p1[] = {
+ 0.581199354001606143928050809e21,
+ -.6672106568924916298020941484e20,
+ 0.2316433580634002297931815435e19,
+ -.3588817569910106050743641413e17,
+ 0.2908795263834775409737601689e15,
+ -.1322983480332126453125473247e13,
+ 0.3413234182301700539091292655e10,
+ -.4695753530642995859767162166e7,
+ 0.2701122710892323414856790990e4,
+};
+static double q1[] = {
+ 0.1162398708003212287858529400e22,
+ 0.1185770712190320999837113348e20,
+ 0.6092061398917521746105196863e17,
+ 0.2081661221307607351240184229e15,
+ 0.5243710262167649715406728642e12,
+ 0.1013863514358673989967045588e10,
+ 0.1501793594998585505921097578e7,
+ 0.1606931573481487801970916749e4,
+ 1.0,
+};
+static double p2[] = {
+ -.4435757816794127857114720794e7,
+ -.9942246505077641195658377899e7,
+ -.6603373248364939109255245434e7,
+ -.1523529351181137383255105722e7,
+ -.1098240554345934672737413139e6,
+ -.1611616644324610116477412898e4,
+ 0.0,
+};
+static double q2[] = {
+ -.4435757816794127856828016962e7,
+ -.9934124389934585658967556309e7,
+ -.6585339479723087072826915069e7,
+ -.1511809506634160881644546358e7,
+ -.1072638599110382011903063867e6,
+ -.1455009440190496182453565068e4,
+ 1.0,
+};
+static double p3[] = {
+ 0.3322091340985722351859704442e5,
+ 0.8514516067533570196555001171e5,
+ 0.6617883658127083517939992166e5,
+ 0.1849426287322386679652009819e5,
+ 0.1706375429020768002061283546e4,
+ 0.3526513384663603218592175580e2,
+ 0.0,
+};
+static double q3[] = {
+ 0.7087128194102874357377502472e6,
+ 0.1819458042243997298924553839e7,
+ 0.1419460669603720892855755253e7,
+ 0.4002944358226697511708610813e6,
+ 0.3789022974577220264142952256e5,
+ 0.8638367769604990967475517183e3,
+ 1.0,
+};
+static double p4[] = {
+ -.9963753424306922225996744354e23,
+ 0.2655473831434854326894248968e23,
+ -.1212297555414509577913561535e22,
+ 0.2193107339917797592111427556e20,
+ -.1965887462722140658820322248e18,
+ 0.9569930239921683481121552788e15,
+ -.2580681702194450950541426399e13,
+ 0.3639488548124002058278999428e10,
+ -.2108847540133123652824139923e7,
+ 0.0,
+};
+static double q4[] = {
+ 0.5082067366941243245314424152e24,
+ 0.5435310377188854170800653097e22,
+ 0.2954987935897148674290758119e20,
+ 0.1082258259408819552553850180e18,
+ 0.2976632125647276729292742282e15,
+ 0.6465340881265275571961681500e12,
+ 0.1128686837169442121732366891e10,
+ 0.1563282754899580604737366452e7,
+ 0.1612361029677000859332072312e4,
+ 1.0,
+};
+
+static
+asympt(double arg)
+{
+ double zsq, n, d;
+ int i;
+
+ zsq = 64/(arg*arg);
+ for(n=0,d=0,i=6;i>=0;i--) {
+ n = n*zsq + p2[i];
+ d = d*zsq + q2[i];
+ }
+ pzero = n/d;
+ for(n=0,d=0,i=6;i>=0;i--) {
+ n = n*zsq + p3[i];
+ d = d*zsq + q3[i];
+ }
+ qzero = (8/arg)*(n/d);
+}
+
+double
+j1(double arg)
+{
+ double xsq, n, d, x;
+ int i;
+
+ x = arg;
+ if(x < 0)
+ x = -x;
+ if(x > 8) {
+ asympt(x);
+ n = x - 3*pio4;
+ n = sqrt(tpi/x)*(pzero*cos(n) - qzero*sin(n));
+ if(arg < 0)
+ n = -n;
+ return n;
+ }
+ xsq = x*x;
+ for(n=0,d=0,i=8;i>=0;i--) {
+ n = n*xsq + p1[i];
+ d = d*xsq + q1[i];
+ }
+ return arg*n/d;
+}
+
+double
+y1(double arg)
+{
+ double xsq, n, d, x;
+ int i;
+
+ errno = 0;
+ x = arg;
+ if(x <= 0) {
+ errno = EDOM;
+ return -HUGE_VAL;
+ }
+ if(x > 8) {
+ asympt(x);
+ n = x - 3*pio4;
+ return sqrt(tpi/x)*(pzero*sin(n) + qzero*cos(n));
+ }
+ xsq = x*x;
+ for(n=0,d=0,i=9;i>=0;i--) {
+ n = n*xsq + p4[i];
+ d = d*xsq + q4[i];
+ }
+ return x*n/d + tpi*(j1(x)*log(x)-1/x);
+}
diff --git a/sys/src/ape/lib/ap/math/jn.c b/sys/src/ape/lib/ap/math/jn.c
new file mode 100755
index 000000000..55e985d48
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/jn.c
@@ -0,0 +1,116 @@
+#include <math.h>
+#include <errno.h>
+
+/*
+ floating point Bessel's function of
+ the first and second kinds and of
+ integer order.
+
+ int n;
+ double x;
+ jn(n,x);
+
+ returns the value of Jn(x) for all
+ integer values of n and all real values
+ of x.
+
+ There are no error returns.
+ Calls j0, j1.
+
+ For n=0, j0(x) is called,
+ for n=1, j1(x) is called,
+ for n<x, forward recursion us used starting
+ from values of j0(x) and j1(x).
+ for n>x, a continued fraction approximation to
+ j(n,x)/j(n-1,x) is evaluated and then backward
+ recursion is used starting from a supposed value
+ for j(n,x). The resulting value of j(0,x) is
+ compared with the actual value to correct the
+ supposed value of j(n,x).
+
+ yn(n,x) is similar in all respects, except
+ that forward recursion is used for all
+ values of n>1.
+*/
+
+double j0(double);
+double j1(double);
+double y0(double);
+double y1(double);
+
+double
+jn(int n, double x)
+{
+ int i;
+ double a, b, temp;
+ double xsq, t;
+
+ if(n < 0) {
+ n = -n;
+ x = -x;
+ }
+ if(n == 0)
+ return j0(x);
+ if(n == 1)
+ return j1(x);
+ if(x == 0)
+ return 0;
+ if(n > x)
+ goto recurs;
+
+ a = j0(x);
+ b = j1(x);
+ for(i=1; i<n; i++) {
+ temp = b;
+ b = (2*i/x)*b - a;
+ a = temp;
+ }
+ return b;
+
+recurs:
+ xsq = x*x;
+ for(t=0,i=n+16; i>n; i--)
+ t = xsq/(2*i - t);
+ t = x/(2*n-t);
+
+ a = t;
+ b = 1;
+ for(i=n-1; i>0; i--) {
+ temp = b;
+ b = (2*i/x)*b - a;
+ a = temp;
+ }
+ return t*j0(x)/b;
+}
+
+double
+yn(int n, double x)
+{
+ int i;
+ int sign;
+ double a, b, temp;
+
+ if (x <= 0) {
+ errno = EDOM;
+ return -HUGE_VAL;
+ }
+ sign = 1;
+ if(n < 0) {
+ n = -n;
+ if(n%2 == 1)
+ sign = -1;
+ }
+ if(n == 0)
+ return y0(x);
+ if(n == 1)
+ return sign*y1(x);
+
+ a = y0(x);
+ b = y1(x);
+ for(i=1; i<n; i++) {
+ temp = b;
+ b = (2*i/x)*b - a;
+ a = temp;
+ }
+ return sign*b;
+}
diff --git a/sys/src/ape/lib/ap/math/log.c b/sys/src/ape/lib/ap/math/log.c
new file mode 100755
index 000000000..bc1c2e1cb
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/log.c
@@ -0,0 +1,62 @@
+/*
+ log returns the natural logarithm of its floating
+ point argument.
+
+ The coefficients are #2705 from Hart & Cheney. (19.38D)
+
+ It calls frexp.
+*/
+
+#include <math.h>
+#include <errno.h>
+
+#define log2 0.693147180559945309e0
+#define ln10o1 .4342944819032518276511
+#define sqrto2 0.707106781186547524e0
+#define p0 -.240139179559210510e2
+#define p1 0.309572928215376501e2
+#define p2 -.963769093377840513e1
+#define p3 0.421087371217979714e0
+#define q0 -.120069589779605255e2
+#define q1 0.194809660700889731e2
+#define q2 -.891110902798312337e1
+
+double
+log(double arg)
+{
+ double x, z, zsq, temp;
+ int exp;
+
+ if(arg <= 0) {
+ errno = (arg==0)? ERANGE : EDOM;
+ return -HUGE_VAL;
+ }
+ x = frexp(arg, &exp);
+ while(x < 0.5) {
+ x *= 2;
+ exp--;
+ }
+ if(x < sqrto2) {
+ x *= 2;
+ exp--;
+ }
+
+ z = (x-1) / (x+1);
+ zsq = z*z;
+
+ temp = ((p3*zsq + p2)*zsq + p1)*zsq + p0;
+ temp = temp/(((zsq + q2)*zsq + q1)*zsq + q0);
+ temp = temp*z + exp*log2;
+ return temp;
+}
+
+double
+log10(double arg)
+{
+
+ if(arg <= 0) {
+ errno = (arg==0)? ERANGE : EDOM;
+ return -HUGE_VAL;
+ }
+ return log(arg) * ln10o1;
+}
diff --git a/sys/src/ape/lib/ap/math/mkfile b/sys/src/ape/lib/ap/math/mkfile
new file mode 100755
index 000000000..5e2d7483f
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/mkfile
@@ -0,0 +1,27 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ asin.$O\
+ atan.$O\
+ atan2.$O\
+ erf.$O\
+ exp.$O\
+ fabs.$O\
+ floor.$O\
+ fmod.$O\
+ gamma.$O\
+ hypot.$O\
+ j0.$O\
+ j1.$O\
+ jn.$O\
+ log.$O\
+ pow.$O\
+ sin.$O\
+ sinh.$O\
+ tan.$O\
+ tanh.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE
diff --git a/sys/src/ape/lib/ap/math/modf.c b/sys/src/ape/lib/ap/math/modf.c
new file mode 100755
index 000000000..4326cf44a
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/modf.c
@@ -0,0 +1,53 @@
+#include <math.h>
+#include <errno.h>
+
+/* modf suitable for IEEE double-precision */
+
+#define MASK 0x7ffL
+#define SIGN 0x80000000
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ } i;
+} Cheat;
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(-1 < d && d < 1) {
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ x.i.ms &= ~SIGN;
+ e = (x.i.ms >> SHIFT) & MASK;
+ if(e == MASK || e == 0){
+ errno = EDOM;
+ *ip = (d > 0)? HUGE_VAL : -HUGE_VAL;
+ return 0;
+ }
+ e -= BIAS;
+ if(e <= SHIFT+1) {
+ x.i.ms &= ~(0x1fffffL >> e);
+ x.i.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.i.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ if(d > 0){
+ *ip = x.d;
+ return d - x.d;
+ }else{
+ *ip = -x.d;
+ return d + x.d;
+ }
+}
diff --git a/sys/src/ape/lib/ap/math/pow.c b/sys/src/ape/lib/ap/math/pow.c
new file mode 100755
index 000000000..9512a649b
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/pow.c
@@ -0,0 +1,76 @@
+#include <math.h>
+#include <errno.h>
+#include <limits.h>
+
+double
+pow(double x, double y) /* return x ^ y (exponentiation) */
+{
+ double xy, y1, ye;
+ long i;
+ int ex, ey, flip;
+
+ if(y == 0.0)
+ return 1.0;
+
+ flip = 0;
+ if(y < 0.){
+ y = -y;
+ flip = 1;
+ }
+ y1 = modf(y, &ye);
+ if(y1 != 0.0){
+ if(x <= 0.)
+ goto zreturn;
+ if(y1 > 0.5) {
+ y1 -= 1.;
+ ye += 1.;
+ }
+ xy = exp(y1 * log(x));
+ }else
+ xy = 1.0;
+ if(ye > LONG_MAX){
+ if(x <= 0.){
+ zreturn:
+ if(x || flip)
+ errno = EDOM;
+ return 0.;
+ }
+ if(flip){
+ if(y == .5)
+ return 1./sqrt(x);
+ y = -y;
+ }else if(y == .5)
+ return sqrt(x);
+ return exp(y * log(x));
+ }
+ x = frexp(x, &ex);
+ ey = 0;
+ i = ye;
+ if(i)
+ for(;;){
+ if(i & 1){
+ xy *= x;
+ ey += ex;
+ }
+ i >>= 1;
+ if(i == 0)
+ break;
+ x *= x;
+ ex <<= 1;
+ if(x < .5){
+ x += x;
+ ex -= 1;
+ }
+ }
+ if(flip){
+ xy = 1. / xy;
+ ey = -ey;
+ }
+ errno = 0;
+ x = ldexp(xy, ey);
+ if(errno && ey < 0) {
+ errno = 0;
+ x = 0.;
+ }
+ return x;
+}
diff --git a/sys/src/ape/lib/ap/math/sin.c b/sys/src/ape/lib/ap/math/sin.c
new file mode 100755
index 000000000..694a223f4
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/sin.c
@@ -0,0 +1,68 @@
+/*
+ C program for floating point sin/cos.
+ Calls modf.
+ There are no error exits.
+ Coefficients are #3370 from Hart & Cheney (18.80D).
+*/
+
+#include <math.h>
+
+#define PIO2 1.570796326794896619231e0
+#define p0 .1357884097877375669092680e8
+#define p1 -.4942908100902844161158627e7
+#define p2 .4401030535375266501944918e6
+#define p3 -.1384727249982452873054457e5
+#define p4 .1459688406665768722226959e3
+#define q0 .8644558652922534429915149e7
+#define q1 .4081792252343299749395779e6
+#define q2 .9463096101538208180571257e4
+#define q3 .1326534908786136358911494e3
+
+static
+double
+sinus(double arg, int quad)
+{
+ double e, f, ysq, x, y, temp1, temp2;
+ int k;
+
+ x = arg;
+ if(x < 0) {
+ x = -x;
+ quad += 2;
+ }
+ x *= 1/PIO2; /* underflow? */
+ if(x > 32764) {
+ y = modf(x, &e);
+ e += quad;
+ modf(0.25*e, &f);
+ quad = e - 4*f;
+ } else {
+ k = x;
+ y = x - k;
+ quad += k;
+ quad &= 3;
+ }
+ if(quad & 1)
+ y = 1-y;
+ if(quad > 1)
+ y = -y;
+
+ ysq = y*y;
+ temp1 = ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y;
+ temp2 = ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0);
+ return temp1/temp2;
+}
+
+double
+cos(double arg)
+{
+ if(arg < 0)
+ arg = -arg;
+ return sinus(arg, 1);
+}
+
+double
+sin(double arg)
+{
+ return sinus(arg, 0);
+}
diff --git a/sys/src/ape/lib/ap/math/sinh.c b/sys/src/ape/lib/ap/math/sinh.c
new file mode 100755
index 000000000..58c261b76
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/sinh.c
@@ -0,0 +1,71 @@
+/*
+ sinh(arg) returns the hyperbolic sine of its floating-
+ point argument.
+
+ The exponential function is called for arguments
+ greater in magnitude than 0.5.
+
+ A series is used for arguments smaller in magnitude than 0.5.
+ The coefficients are #2029 from Hart & Cheney. (20.36D)
+
+ cosh(arg) is computed from the exponential function for
+ all arguments.
+*/
+
+#include <math.h>
+#include <errno.h>
+
+static double p0 = -0.6307673640497716991184787251e+6;
+static double p1 = -0.8991272022039509355398013511e+5;
+static double p2 = -0.2894211355989563807284660366e+4;
+static double p3 = -0.2630563213397497062819489e+2;
+static double q0 = -0.6307673640497716991212077277e+6;
+static double q1 = 0.1521517378790019070696485176e+5;
+static double q2 = -0.173678953558233699533450911e+3;
+
+double
+sinh(double arg)
+{
+ double temp, argsq;
+ int sign;
+
+ sign = 1;
+ if(arg < 0) {
+ arg = - arg;
+ sign = -1;
+ }
+ if(arg > 21) {
+ if(arg >= HUGE_VAL){
+ errno = ERANGE;
+ temp = HUGE_VAL;
+ } else
+ temp = exp(arg)/2;
+ if(sign > 0)
+ return temp;
+ else
+ return -temp;
+ }
+
+ if(arg > 0.5)
+ return sign*(exp(arg) - exp(-arg))/2;
+
+ argsq = arg*arg;
+ temp = (((p3*argsq+p2)*argsq+p1)*argsq+p0)*arg;
+ temp /= (((argsq+q2)*argsq+q1)*argsq+q0);
+ return sign*temp;
+}
+
+double
+cosh(double arg)
+{
+ if(arg < 0)
+ arg = - arg;
+ if(arg > 21) {
+ if(arg >= HUGE_VAL){
+ errno = ERANGE;
+ return HUGE_VAL;
+ } else
+ return(exp(arg)/2);
+ }
+ return (exp(arg) + exp(-arg))/2;
+}
diff --git a/sys/src/ape/lib/ap/math/tan.c b/sys/src/ape/lib/ap/math/tan.c
new file mode 100755
index 000000000..5147f8bc1
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/tan.c
@@ -0,0 +1,70 @@
+/*
+ floating point tangent
+
+ A series is used after range reduction.
+ Coefficients are #4285 from Hart & Cheney. (19.74D)
+ */
+
+#include <math.h>
+#include <errno.h>
+
+static double invpi = 1.27323954473516268;
+static double p0 = -0.1306820264754825668269611177e+5;
+static double p1 = 0.1055970901714953193602353981e+4;
+static double p2 = -0.1550685653483266376941705728e+2;
+static double p3 = 0.3422554387241003435328470489e-1;
+static double p4 = 0.3386638642677172096076369e-4;
+static double q0 = -0.1663895238947119001851464661e+5;
+static double q1 = 0.4765751362916483698926655581e+4;
+static double q2 = -0.1555033164031709966900124574e+3;
+
+double
+tan(double arg)
+{
+ double sign, temp, e, x, xsq;
+ int flag, i;
+
+ flag = 0;
+ sign = 1;
+ if(arg < 0){
+ arg = -arg;
+ sign = -1;
+ }
+ arg = arg*invpi; /* overflow? */
+ x = modf(arg, &e);
+ i = e;
+ switch(i%4) {
+ case 1:
+ x = 1 - x;
+ flag = 1;
+ break;
+
+ case 2:
+ sign = - sign;
+ flag = 1;
+ break;
+
+ case 3:
+ x = 1 - x;
+ sign = - sign;
+ break;
+
+ case 0:
+ break;
+ }
+
+ xsq = x*x;
+ temp = ((((p4*xsq+p3)*xsq+p2)*xsq+p1)*xsq+p0)*x;
+ temp = temp/(((xsq+q2)*xsq+q1)*xsq+q0);
+
+ if(flag == 1) {
+ if(temp == 0) {
+ errno = EDOM;
+ if (sign > 0)
+ return HUGE_VAL;
+ return -HUGE_VAL;
+ }
+ temp = 1/temp;
+ }
+ return sign*temp;
+}
diff --git a/sys/src/ape/lib/ap/math/tanh.c b/sys/src/ape/lib/ap/math/tanh.c
new file mode 100755
index 000000000..cad68362b
--- /dev/null
+++ b/sys/src/ape/lib/ap/math/tanh.c
@@ -0,0 +1,24 @@
+#include <math.h>
+
+/*
+ tanh(arg) computes the hyperbolic tangent of its floating
+ point argument.
+
+ sinh and cosh are called except for large arguments, which
+ would cause overflow improperly.
+ */
+
+double
+tanh(double arg)
+{
+
+ if(arg < 0) {
+ arg = -arg;
+ if(arg > 21)
+ return -1;
+ return -sinh(arg)/cosh(arg);
+ }
+ if(arg > 21)
+ return 1;
+ return sinh(arg)/cosh(arg);
+}
diff --git a/sys/src/ape/lib/ap/mips/cycles.c b/sys/src/ape/lib/ap/mips/cycles.c
new file mode 100755
index 000000000..1c32bc732
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/cycles.c
@@ -0,0 +1,5 @@
+void
+_cycles(unsigned long long *u)
+{
+ *u = 0;
+}
diff --git a/sys/src/ape/lib/ap/mips/getfcr.s b/sys/src/ape/lib/ap/mips/getfcr.s
new file mode 100755
index 000000000..9e84cbccd
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/getfcr.s
@@ -0,0 +1,15 @@
+TEXT getfsr(SB), $0
+ MOVW FCR31, R1
+ RET
+
+TEXT setfsr(SB), $0
+ MOVW R1, FCR31
+ RET
+
+TEXT getfcr(SB), $0
+ MOVW FCR31, R1
+ RET
+
+TEXT setfcr(SB), $0
+ MOVW R1, FCR31
+ RET
diff --git a/sys/src/ape/lib/ap/mips/lock.c b/sys/src/ape/lib/ap/mips/lock.c
new file mode 100755
index 000000000..f0ecbe22a
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/lock.c
@@ -0,0 +1,172 @@
+#define _LOCK_EXTENSION
+#include <stdlib.h>
+#include <string.h>
+#include "../plan9/sys9.h"
+#include <lock.h>
+
+enum
+{
+ Pagesize = 4096,
+ Semperpg = Pagesize/(16*sizeof(unsigned int)),
+ Lockaddr = 0x60000000,
+
+ POWER = 0x320,
+ MAGNUM = 0x330,
+ MAGNUMII = 0x340,
+ R4K = 0x500,
+};
+
+static int arch;
+extern int C_3ktas(int*);
+extern int C_4ktas(int*);
+extern int C_fcr0(void);
+
+static void
+lockinit(void)
+{
+ int n;
+
+ if(arch != 0)
+ return; /* allow multiple calls */
+ arch = C_fcr0();
+ switch(arch) {
+ case POWER:
+ n = _SEGATTACH(0, "lock", (void*)Lockaddr, Pagesize);
+ if(n < 0) {
+ arch = MAGNUM;
+ break;
+ }
+ memset((void*)Lockaddr, 0, Pagesize);
+ break;
+ case MAGNUM:
+ case MAGNUMII:
+ case R4K:
+ break;
+ default:
+ abort();
+ }
+
+}
+
+void
+lock(Lock *lk)
+{
+ int *hwsem;
+ int hash;
+
+retry:
+ switch(arch) {
+ case 0:
+ lockinit();
+ goto retry;
+ case MAGNUM:
+ case MAGNUMII:
+ while(C_3ktas(&lk->val))
+ _SLEEP(0);
+ return;
+ case R4K:
+ for(;;){
+ while(lk->val)
+ ;
+ if(C_4ktas(&lk->val) == 0)
+ return;
+ }
+ break;
+ case POWER:
+ /* Use low order lock bits to generate hash */
+ hash = ((int)lk/sizeof(int)) & (Semperpg-1);
+ hwsem = (int*)Lockaddr+hash;
+
+ for(;;) {
+ if((*hwsem & 1) == 0) {
+ if(lk->val)
+ *hwsem = 0;
+ else {
+ lk->val = 1;
+ *hwsem = 0;
+ return;
+ }
+ }
+ while(lk->val)
+ ;
+ }
+ }
+}
+
+int
+canlock(Lock *lk)
+{
+ int *hwsem;
+ int hash;
+
+retry:
+ switch(arch) {
+ case 0:
+ lockinit();
+ goto retry;
+ case MAGNUM:
+ case MAGNUMII:
+ if(C_3ktas(&lk->val))
+ return 0;
+ return 1;
+ case R4K:
+ if(C_4ktas(&lk->val))
+ return 0;
+ return 1;
+ case POWER:
+ /* Use low order lock bits to generate hash */
+ hash = ((int)lk/sizeof(int)) & (Semperpg-1);
+ hwsem = (int*)Lockaddr+hash;
+
+ if((*hwsem & 1) == 0) {
+ if(lk->val)
+ *hwsem = 0;
+ else {
+ lk->val = 1;
+ *hwsem = 0;
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
+
+int
+tas(int *p)
+{
+ int *hwsem;
+ int hash;
+
+retry:
+ switch(arch) {
+ case 0:
+ lockinit();
+ goto retry;
+ case MAGNUM:
+ case MAGNUMII:
+ return C_3ktas(p);
+ case R4K:
+ return C_4ktas(p);
+ case POWER:
+ /* Use low order lock bits to generate hash */
+ hash = ((int)p/sizeof(int)) & (Semperpg-1);
+ hwsem = (int*)Lockaddr+hash;
+
+ if((*hwsem & 1) == 0) {
+ if(*p)
+ *hwsem = 0;
+ else {
+ *p = 1;
+ *hwsem = 0;
+ return 0;
+ }
+ }
+ return 1;
+ }
+}
diff --git a/sys/src/ape/lib/ap/mips/main9.s b/sys/src/ape/lib/ap/mips/main9.s
new file mode 100755
index 000000000..a3c224ace
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/main9.s
@@ -0,0 +1,12 @@
+ TEXT _main(SB), $16
+ MOVW $setR30(SB), R30
+ JAL _envsetup(SB)
+ MOVW inargc-4(FP), R1
+ MOVW $inargv+0(FP), R2
+ MOVW R1, 4(R29)
+ MOVW R2, 8(R29)
+ JAL main(SB)
+loop:
+ MOVW R1, 4(R29)
+ JAL exit(SB)
+ JMP loop
diff --git a/sys/src/ape/lib/ap/mips/main9p.s b/sys/src/ape/lib/ap/mips/main9p.s
new file mode 100755
index 000000000..adc6e00b3
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/main9p.s
@@ -0,0 +1,54 @@
+#define NPRIVATES 16
+
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
+
+TEXT _mainp(SB), 1, $(3*4+NPRIVATES*4)
+ MOVW $setR30(SB), R30
+
+ /* _tos = arg */
+ MOVW R1, _tos(SB)
+/*
+ MOVW $0,FCR31
+ NOR R0,R0
+ MOVD $0.5, F26
+ SUBD F26, F26, F24
+ ADDD F26, F26, F28
+ ADDD F28, F28, F30
+*/
+ MOVW $8(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ /* _profmain(); */
+ JAL _profmain(SB)
+
+ /* _tos->prof.pp = _tos->prof.next; */
+ MOVW _tos+0(SB),R1
+ MOVW 4(R1),R2
+ MOVW R2,(R1)
+
+ JAL _envsetup(SB)
+
+ /* main(argc, argv, environ); */
+ MOVW inargc-4(FP), R1
+ MOVW $inargv+0(FP), R2
+ MOVW environ(SB), R3
+ MOVW R1, 4(R29)
+ MOVW R2, 8(R29)
+ MOVW R3, 12(R29)
+ JAL main(SB)
+loop:
+ MOVW R1, 4(R29)
+ JAL exit(SB)
+ MOVW $_profin(SB), R0 /* force loading of profile */
+ JMP loop
+
+TEXT _savearg(SB), 1, $0
+ RET
+
+TEXT _callpc(SB), 1, $0
+ MOVW argp-4(FP), R1
+ RET
diff --git a/sys/src/ape/lib/ap/mips/memchr.s b/sys/src/ape/lib/ap/mips/memchr.s
new file mode 100755
index 000000000..5d1c3cc85
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/memchr.s
@@ -0,0 +1,39 @@
+ TEXT memchr(SB), $0
+MOVW R1, 0(FP)
+
+ MOVW n+8(FP), R1
+ MOVW s1+0(FP), R2
+ MOVBU c+7(FP), R3
+ ADDU R1, R2, R6
+
+ AND $(~1), R1, R5
+ ADDU R2, R5
+ BEQ R2, R5, lt2
+
+l1:
+ MOVBU 0(R2), R4
+ MOVBU 1(R2), R7
+ BEQ R3, R4, eq0
+ ADDU $2, R2
+ BEQ R3, R7, eq
+ BNE R2, R5, l1
+
+lt2:
+ BEQ R2, R6, zret
+
+l2:
+ MOVBU (R2), R4
+ ADDU $1, R2
+ BEQ R3, R4, eq
+ BNE R2, R6, l2
+zret:
+ MOVW R0, R1
+ RET
+
+eq0:
+ MOVW R2, R1
+ RET
+
+eq:
+ SUBU $1,R2, R1
+ RET
diff --git a/sys/src/ape/lib/ap/mips/memcmp.s b/sys/src/ape/lib/ap/mips/memcmp.s
new file mode 100755
index 000000000..c9142f85e
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/memcmp.s
@@ -0,0 +1,114 @@
+ TEXT memcmp(SB), $0
+MOVW R1, 0(FP)
+
+/*
+ * performance:
+ * alligned about 1.0us/call and 17.4mb/sec
+ * unalligned is about 3.1mb/sec
+ */
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW s1+0(FP), R4 /* R4 is pointer1 */
+ MOVW s2+4(FP), R5 /* R5 is pointer2 */
+ ADDU R3,R4, R6 /* R6 is end pointer1 */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word cmp.
+ */
+ SGT $4,R3, R1
+ BNE R1, out
+
+/*
+ * test if both pointers
+ * are similarly word alligned
+ */
+ XOR R4,R5, R1
+ AND $3, R1
+ BNE R1, out
+
+/*
+ * byte at a time to word allign
+ */
+l1:
+ AND $3,R4, R1
+ BEQ R1, l2
+ MOVB 0(R4), R8
+ MOVB 0(R5), R9
+ ADDU $1, R4
+ BNE R8,R9, ne
+ ADDU $1, R5
+ JMP l1
+
+/*
+ * turn R3 into end pointer1-15
+ * cmp 16 at a time while theres room
+ */
+l2:
+ ADDU $-15,R6, R3
+l3:
+ SGTU R3,R4, R1
+ BEQ R1, l4
+ MOVW 0(R4), R8
+ MOVW 0(R5), R9
+ MOVW 4(R4), R10
+ BNE R8,R9, ne
+ MOVW 4(R5), R11
+ MOVW 8(R4), R8
+ BNE R10,R11, ne1
+ MOVW 8(R5), R9
+ MOVW 12(R4), R10
+ BNE R8,R9, ne
+ MOVW 12(R5), R11
+ ADDU $16, R4
+ BNE R10,R11, ne1
+ BNE R8,R9, ne
+ ADDU $16, R5
+ JMP l3
+
+/*
+ * turn R3 into end pointer1-3
+ * cmp 4 at a time while theres room
+ */
+l4:
+ ADDU $-3,R6, R3
+l5:
+ SGTU R3,R4, R1
+ BEQ R1, out
+ MOVW 0(R4), R8
+ MOVW 0(R5), R9
+ ADDU $4, R4
+ BNE R8,R9, ne /* only works because big endian */
+ ADDU $4, R5
+ JMP l5
+
+/*
+ * last loop, cmp byte at a time
+ */
+out:
+ SGTU R6,R4, R1
+ BEQ R1, ret
+ MOVB 0(R4), R8
+ MOVB 0(R5), R9
+ ADDU $1, R4
+ BNE R8,R9, ne
+ ADDU $1, R5
+ JMP out
+
+ne1:
+ SGTU R10,R11, R1
+ BNE R1, ret
+ MOVW $-1,R1
+ RET
+ne:
+ SGTU R8,R9, R1
+ BNE R1, ret
+ MOVW $-1,R1
+ret:
+ RET
+ END
diff --git a/sys/src/ape/lib/ap/mips/memmove.s b/sys/src/ape/lib/ap/mips/memmove.s
new file mode 100755
index 000000000..c8e30a0b4
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/memmove.s
@@ -0,0 +1,161 @@
+ TEXT memmove(SB), $0
+
+ JMP move
+
+ TEXT memcpy(SB), $0
+move:
+ MOVW R1, s1+0(FP)
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW R1, R4 /* R4 is to-pointer */
+ SGT R0, R3, R5
+ BEQ R5, ok
+ MOVW (R0), R0 /* abort if negative count */
+ok:
+ MOVW s2+4(FP), R5 /* R5 is from-pointer */
+ ADDU R3,R5, R7 /* R7 is end from-pointer */
+ ADDU R3,R4, R6 /* R6 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ SGT $4,R3, R2
+ SGTU R4,R5, R1
+ BNE R1, back
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ BNE R2, fout
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R4,R5, R1
+ AND $3, R1
+ BNE R1, fout
+
+/*
+ * byte at a time to word align
+ */
+f1:
+ AND $3,R4, R1
+ BEQ R1, f2
+ MOVB 0(R5), R8
+ ADDU $1, R5
+ MOVB R8, 0(R4)
+ ADDU $1, R4
+ JMP f1
+
+/*
+ * turn R3 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R6 is smaller than R7 --
+ * there are problems if R7 is 0.
+ */
+f2:
+ ADDU $-15,R6, R3
+f3:
+ SGTU R3,R4, R1
+ BEQ R1, f4
+ MOVW 0(R5), R8
+ MOVW 4(R5), R9
+ MOVW R8, 0(R4)
+ MOVW 8(R5), R8
+ MOVW R9, 4(R4)
+ MOVW 12(R5), R9
+ ADDU $16, R5
+ MOVW R8, 8(R4)
+ MOVW R9, 12(R4)
+ ADDU $16, R4
+ JMP f3
+
+/*
+ * turn R3 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+ ADDU $-3,R6, R3
+f5:
+ SGTU R3,R4, R1
+ BEQ R1, fout
+ MOVW 0(R5), R8
+ ADDU $4, R5
+ MOVW R8, 0(R4)
+ ADDU $4, R4
+ JMP f5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+ BEQ R7,R5, ret
+ MOVB 0(R5), R8
+ ADDU $1, R5
+ MOVB R8, 0(R4)
+ ADDU $1, R4
+ JMP fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ BNE R2, bout
+ XOR R6,R7, R1
+ AND $3, R1
+ BNE R1, bout
+b1:
+ AND $3,R7, R1
+ BEQ R1, b2
+ MOVB -1(R7), R8
+ ADDU $-1, R7
+ MOVB R8, -1(R6)
+ ADDU $-1, R6
+ JMP b1
+b2:
+ ADDU $15,R5, R3
+b3:
+ SGTU R7,R3, R1
+ BEQ R1, b4
+ MOVW -4(R7), R8
+ MOVW -8(R7), R9
+ MOVW R8, -4(R6)
+ MOVW -12(R7), R8
+ MOVW R9, -8(R6)
+ MOVW -16(R7), R9
+ ADDU $-16, R7
+ MOVW R8, -12(R6)
+ MOVW R9, -16(R6)
+ ADDU $-16, R6
+ JMP b3
+b4:
+ ADDU $3,R5, R3
+b5:
+ SGTU R7,R3, R1
+ BEQ R1, bout
+ MOVW -4(R7), R8
+ ADDU $-4, R7
+ MOVW R8, -4(R6)
+ ADDU $-4, R6
+ JMP b5
+
+bout:
+ BEQ R7,R5, ret
+ MOVB -1(R7), R8
+ ADDU $-1, R7
+ MOVB R8, -1(R6)
+ ADDU $-1, R6
+ JMP bout
+
+ret:
+ MOVW s1+0(FP), R1
+ RET
+ END
diff --git a/sys/src/ape/lib/ap/mips/memset.s b/sys/src/ape/lib/ap/mips/memset.s
new file mode 100755
index 000000000..8c9467f45
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/memset.s
@@ -0,0 +1,88 @@
+ TEXT memset(SB),$12
+MOVW R1, 0(FP)
+
+/*
+ * performance:
+ * about 1us/call and 28mb/sec
+ */
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW p+0(FP), R4 /* R4 is pointer */
+ MOVW c+4(FP), R5 /* R5 is char */
+ ADDU R3,R4, R6 /* R6 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SGT $4,R3, R1
+ BNE R1, out
+
+/*
+ * turn R5 into a word of characters
+ */
+ AND $0xff, R5
+ SLL $8,R5, R1
+ OR R1, R5
+ SLL $16,R5, R1
+ OR R1, R5
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+ AND $3,R4, R1
+ BEQ R1, l2
+ MOVB R5, 0(R4)
+ ADDU $1, R4
+ JMP l1
+
+/*
+ * turn R3 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+ ADDU $-15,R6, R3
+l3:
+ SGTU R3,R4, R1
+ BEQ R1, l4
+ MOVW R5, 0(R4)
+ MOVW R5, 4(R4)
+ ADDU $16, R4
+ MOVW R5, -8(R4)
+ MOVW R5, -4(R4)
+ JMP l3
+
+/*
+ * turn R3 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+ ADDU $-3,R6, R3
+l5:
+ SGTU R3,R4, R1
+ BEQ R1, out
+ MOVW R5, 0(R4)
+ ADDU $4, R4
+ JMP l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+ SGTU R6,R4 ,R1
+ BEQ R1, ret
+ MOVB R5, 0(R4)
+ ADDU $1, R4
+ JMP out
+
+ret:
+ MOVW s1+0(FP), R1
+ RET
+ END
diff --git a/sys/src/ape/lib/ap/mips/mkfile b/sys/src/ape/lib/ap/mips/mkfile
new file mode 100755
index 000000000..0896229a6
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/mkfile
@@ -0,0 +1,26 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ cycles.$O\
+ getfcr.$O\
+ lock.$O\
+ main9.$O\
+ main9p.$O\
+ memchr.$O\
+ memcmp.$O\
+ memmove.$O\
+ memset.$O\
+ notetramp.$O\
+ setjmp.$O\
+ strchr.$O\
+ strcmp.$O\
+ strcpy.$O\
+ tas.$O\
+ vlop.$O\
+ vlrt.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE
+
diff --git a/sys/src/ape/lib/ap/mips/notetramp.c b/sys/src/ape/lib/ap/mips/notetramp.c
new file mode 100755
index 000000000..cef6b563b
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/notetramp.c
@@ -0,0 +1,72 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#include <signal.h>
+#include <setjmp.h>
+
+/* A stack to hold pcs when signals nest */
+#define MAXSIGSTACK 20
+typedef struct Pcstack Pcstack;
+static struct Pcstack {
+ int sig;
+ void (*hdlr)(int, char*, Ureg*);
+ unsigned long restorepc;
+ Ureg *u;
+} pcstack[MAXSIGSTACK];
+static int nstack = 0;
+
+static void notecont(Ureg*, char*);
+
+void
+_notetramp(int sig, void (*hdlr)(int, char*, Ureg*), Ureg *u)
+{
+ Pcstack *p;
+
+ if(nstack >= MAXSIGSTACK)
+ _NOTED(1); /* nesting too deep; just do system default */
+ p = &pcstack[nstack];
+ p->restorepc = u->pc;
+ p->sig = sig;
+ p->hdlr = hdlr;
+ p->u = u;
+ nstack++;
+ u->pc = (unsigned long) notecont;
+ _NOTED(2); /* NSAVE: clear note but hold state */
+}
+
+static void
+notecont(Ureg *u, char *s)
+{
+ Pcstack *p;
+ void(*f)(int, char*, Ureg*);
+
+ p = &pcstack[nstack-1];
+ f = p->hdlr;
+ u->pc = p->restorepc;
+ nstack--;
+ (*f)(p->sig, s, u);
+ _NOTED(3); /* NRSTR */
+}
+
+#define JMPBUFPC 1
+#define JMPBUFSP 0
+
+extern sigset_t _psigblocked;
+
+void
+siglongjmp(sigjmp_buf j, int ret)
+{
+ struct Ureg *u;
+
+ if(j[0])
+ _psigblocked = j[1];
+ if(nstack == 0 || pcstack[nstack-1].u->sp > j[2+JMPBUFSP])
+ longjmp(j+2, ret);
+ u = pcstack[nstack-1].u;
+ nstack--;
+ u->r1 = ret;
+ if(ret == 0)
+ u->r1 = 1;
+ u->pc = j[2+JMPBUFPC];
+ u->sp = j[2+JMPBUFSP];
+ _NOTED(3); /* NRSTR */
+}
diff --git a/sys/src/ape/lib/ap/mips/setjmp.s b/sys/src/ape/lib/ap/mips/setjmp.s
new file mode 100755
index 000000000..32ff470eb
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/setjmp.s
@@ -0,0 +1,24 @@
+TEXT setjmp(SB), 1, $-4
+ MOVW R29, (R1)
+ MOVW R31, 4(R1)
+ MOVW $0, R1
+ RET
+
+TEXT sigsetjmp(SB), 1, $-4
+ MOVW savemask+4(FP), R2
+ MOVW R2, 0(R1)
+ MOVW $_psigblocked(SB), R2
+ MOVW R2, 4(R1)
+ MOVW R29, 8(R1)
+ MOVW R31, 12(R1)
+ MOVW $0, R1
+ RET
+
+TEXT longjmp(SB), 1, $-4
+ MOVW r+4(FP), R3
+ BNE R3, ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVW $1, R3 /* bless their pointed heads */
+ok: MOVW (R1), R29
+ MOVW 4(R1), R31
+ MOVW R3, R1
+ RET
diff --git a/sys/src/ape/lib/ap/mips/strchr.s b/sys/src/ape/lib/ap/mips/strchr.s
new file mode 100755
index 000000000..e009ffad2
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/strchr.s
@@ -0,0 +1,63 @@
+ TEXT strchr(SB), $0
+MOVW R1, 0(FP)
+ MOVB c+7(FP), R4
+ MOVW s+0(FP), R3
+
+ BEQ R4, l2
+
+/*
+ * char is not null
+ */
+l1:
+ MOVB (R3), R1
+ ADDU $1, R3
+ BEQ R1, ret
+ BNE R1,R4, l1
+ JMP rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+ AND $3,R3, R1
+ BEQ R1, l3
+ MOVB (R3), R1
+ ADDU $1, R3
+ BNE R1, l2
+ JMP rm1
+
+l3:
+ MOVW $0xff000000, R6
+ MOVW $0x00ff0000, R7
+
+l4:
+ MOVW (R3), R5
+ ADDU $4, R3
+ AND R6,R5, R1
+ AND R7,R5, R2
+ BEQ R1, b0
+ AND $0xff00,R5, R1
+ BEQ R2, b1
+ AND $0xff,R5, R2
+ BEQ R1, b2
+ BNE R2, l4
+
+rm1:
+ ADDU $-1,R3, R1
+ JMP ret
+
+b2:
+ ADDU $-2,R3, R1
+ JMP ret
+
+b1:
+ ADDU $-3,R3, R1
+ JMP ret
+
+b0:
+ ADDU $-4,R3, R1
+ JMP ret
+
+ret:
+ RET
diff --git a/sys/src/ape/lib/ap/mips/strcmp.s b/sys/src/ape/lib/ap/mips/strcmp.s
new file mode 100755
index 000000000..da986a2ed
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/strcmp.s
@@ -0,0 +1,21 @@
+TEXT strcmp(SB), $0
+
+ MOVW s2+4(FP), R2
+
+l1:
+ MOVB (R2), R3
+ MOVB (R1), R4
+ ADDU $1, R1
+ BEQ R3, end
+ ADDU $1, R2
+ BEQ R3, R4, l1
+
+ SGTU R4, R3, R1
+ BNE R1, ret
+ MOVW $-1, R1
+ RET
+
+end:
+ SGTU R4, R3, R1
+ret:
+ RET
diff --git a/sys/src/ape/lib/ap/mips/strcpy.s b/sys/src/ape/lib/ap/mips/strcpy.s
new file mode 100755
index 000000000..77be42669
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/strcpy.s
@@ -0,0 +1,96 @@
+TEXT strcpy(SB), $0
+
+ MOVW s2+4(FP),R2 /* R2 is from pointer */
+ MOVW R1, R3 /* R3 is to pointer */
+
+/*
+ * align 'from' pointer
+ */
+l1:
+ AND $3, R2, R5
+ ADDU $1, R2
+ BEQ R5, l2
+ MOVB -1(R2), R5
+ ADDU $1, R3
+ MOVB R5, -1(R3)
+ BNE R5, l1
+ RET
+
+/*
+ * test if 'to' is also alligned
+ */
+l2:
+ AND $3,R3, R5
+ BEQ R5, l4
+
+/*
+ * copy 4 at a time, 'to' not aligned
+ */
+l3:
+ MOVW -1(R2), R4
+ ADD $4, R2
+ ADD $4, R3
+ SRL $24,R4, R5
+ MOVB R5, -4(R3)
+ BEQ R5, out
+
+ SRL $16,R4, R5
+ AND $0xff, R5
+ MOVB R5, -3(R3)
+ BEQ R5, out
+
+ SRL $8,R4, R5
+ AND $0xff, R5
+ MOVB R5, -2(R3)
+ BEQ R5, out
+
+ AND $0xff,R4, R5
+ MOVB R5, -1(R3)
+ BNE R5, l3
+
+out:
+ RET
+
+/*
+ * word at a time both aligned
+ */
+l4:
+ MOVW $0xff000000, R7
+ MOVW $0x00ff0000, R8
+
+l5:
+ ADDU $4, R3
+ MOVW -1(R2), R4 /* fetch */
+
+ ADDU $4, R2
+ AND R7,R4, R5 /* is it byte 0 */
+ AND R8,R4, R6 /* is it byte 1 */
+ BEQ R5, b0
+
+ AND $0xff00,R4, R5 /* is it byte 2 */
+ BEQ R6, b1
+
+ AND $0xff,R4, R6 /* is it byte 3 */
+ BEQ R5, b2
+
+ MOVW R4, -4(R3) /* store */
+ BNE R6, l5
+ JMP out
+
+b0:
+ MOVB $0, -4(R3)
+ JMP out
+
+b1:
+ SRL $24, R4
+ MOVB R4, -4(R3)
+ MOVB $0, -3(R3)
+ JMP out
+
+b2:
+ SRL $24,R4, R5
+ MOVB R5, -4(R3)
+ SRL $16, R4
+ MOVB R4, -3(R3)
+ MOVB $0, -2(R3)
+ JMP out
diff --git a/sys/src/ape/lib/ap/mips/tas.s b/sys/src/ape/lib/ap/mips/tas.s
new file mode 100755
index 000000000..d754b21f6
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/tas.s
@@ -0,0 +1,33 @@
+/*
+ * magnum user level lock code
+ */
+
+#define LL(base, rt) WORD $((060<<26)|((base)<<21)|((rt)<<16))
+#define SC(base, rt) WORD $((070<<26)|((base)<<21)|((rt)<<16))
+#define NOOP WORD $0x27
+#define COP3 WORD $(023<<26)
+
+ TEXT C_3ktas(SB),$0
+ MOVW R1, R21
+btas:
+ MOVW R21, R1
+ MOVB R0, 1(R1)
+ NOOP
+ COP3
+ BLTZ R1, btas
+ RET
+
+ TEXT C_4ktas(SB), $0
+ MOVW R1, R2 /* address of key */
+tas1:
+ MOVW $1, R3
+ LL(2, 1)
+ NOOP
+ SC(2, 3)
+ NOOP
+ BEQ R3, tas1
+ RET
+
+ TEXT C_fcr0(SB), $0
+ MOVW FCR0, R1
+ RET
diff --git a/sys/src/ape/lib/ap/mips/vlop.s b/sys/src/ape/lib/ap/mips/vlop.s
new file mode 100755
index 000000000..17f487ad8
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/vlop.s
@@ -0,0 +1,17 @@
+TEXT _mulv(SB), $0
+ MOVW 8(FP), R2
+ MOVW 4(FP), R3
+ MOVW 16(FP), R4
+ MOVW 12(FP), R5
+ MULU R4, R2
+ MOVW LO, R6
+ MOVW HI, R7
+ MULU R3, R4
+ MOVW LO, R8
+ ADDU R8, R7
+ MULU R2, R5
+ MOVW LO, R8
+ ADDU R8, R7
+ MOVW R6, 4(R1)
+ MOVW R7, 0(R1)
+ RET
diff --git a/sys/src/ape/lib/ap/mips/vlrt.c b/sys/src/ape/lib/ap/mips/vlrt.c
new file mode 100755
index 000000000..964562775
--- /dev/null
+++ b/sys/src/ape/lib/ap/mips/vlrt.c
@@ -0,0 +1,719 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(qp) {
+ qp->lo = quolo;
+ qp->hi = quohi;
+ }
+ if(rp) {
+ rp->lo = numlo;
+ rp->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/sys/src/ape/lib/ap/mkfile b/sys/src/ape/lib/ap/mkfile
new file mode 100755
index 000000000..fa7d240e6
--- /dev/null
+++ b/sys/src/ape/lib/ap/mkfile
@@ -0,0 +1,24 @@
+APE=/sys/src/ape
+<$APE/config
+
+DIRS=gen math plan9 posix stdio syscall
+
+default:V: all
+
+install all:V:
+ for(i in $DIRS $objtype)@{
+ echo $i
+ cd $i
+ mk $MKFLAGS $target
+ }
+
+installall:V:
+ for(objtype in $CPUS) mk $MKFLAGS install
+
+
+clean nuke:V:
+ for(i in $DIRS $CPUS)@{
+ echo $i
+ cd $i
+ mk $MKFLAGS $target
+ }
diff --git a/sys/src/ape/lib/ap/plan9/9errstr.c b/sys/src/ape/lib/ap/plan9/9errstr.c
new file mode 100755
index 000000000..31226c18b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/9errstr.c
@@ -0,0 +1,4 @@
+#include "sys9.h"
+
+int
+_ERRSTR( \ No newline at end of file
diff --git a/sys/src/ape/lib/ap/plan9/9iounit.c b/sys/src/ape/lib/ap/plan9/9iounit.c
new file mode 100755
index 000000000..7117a9fe0
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/9iounit.c
@@ -0,0 +1,65 @@
+#include "lib.h"
+#include <string.h>
+#include <stdlib.h>
+#include <fmt.h>
+#include "sys9.h"
+#include "dir.h"
+
+/*
+ * Format:
+ 3 r M 4 (0000000000457def 11 00) 8192 512 /rc/lib/rcmain
+ */
+
+static int
+getfields(char *str, char **args, int max, int mflag)
+{
+ char r;
+ int nr, intok, narg;
+
+ if(max <= 0)
+ return 0;
+
+ narg = 0;
+ args[narg] = str;
+ if(!mflag)
+ narg++;
+ intok = 0;
+ for(;;) {
+ r = *str++;
+ if(r == 0)
+ break;
+ if(r == ' ' || r == '\t'){
+ if(narg >= max)
+ break;
+ *str = 0;
+ intok = 0;
+ args[narg] = str + nr;
+ if(!mflag)
+ narg++;
+ } else {
+ if(!intok && mflag)
+ narg++;
+ intok = 1;
+ }
+ }
+ return narg;
+}
+int
+_IOUNIT(int fd)
+{
+ int i, cfd;
+ char buf[128], *args[10];
+
+ snprint(buf, sizeof buf, "#d/%dctl", fd);
+ cfd = _OPEN(buf, OREAD);
+ if(cfd < 0)
+ return 0;
+ i = _READ(cfd, buf, sizeof buf-1);
+ _CLOSE(cfd);
+ if(i <= 0)
+ return 0;
+ buf[i] = '\0';
+ if(getfields(buf, args, 10, 1) != 10)
+ return 0;
+ return atoi(args[7]);
+}
diff --git a/sys/src/ape/lib/ap/plan9/9mallocz.c b/sys/src/ape/lib/ap/plan9/9mallocz.c
new file mode 100755
index 000000000..de5edb266
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/9mallocz.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <string.h>
+
+void*
+_MALLOCZ(int n, int clr)
+{
+ void *v;
+
+ v = malloc(n);
+ if(v && clr)
+ memset(v, 0, n);
+ return v;
+}
+
diff --git a/sys/src/ape/lib/ap/plan9/9read.c b/sys/src/ape/lib/ap/plan9/9read.c
new file mode 100755
index 000000000..ce38b3908
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/9read.c
@@ -0,0 +1,11 @@
+#include "lib.h"
+#include <string.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+long
+_READ(int fd, void *buf, long n)
+{
+ return _PREAD(fd, buf, n, -1LL);
+}
diff --git a/sys/src/ape/lib/ap/plan9/9readn.c b/sys/src/ape/lib/ap/plan9/9readn.c
new file mode 100755
index 000000000..8a0f5615c
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/9readn.c
@@ -0,0 +1,21 @@
+#include "sys9.h"
+
+long
+_READN(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = _READ(f, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
diff --git a/sys/src/ape/lib/ap/plan9/9wait.c b/sys/src/ape/lib/ap/plan9/9wait.c
new file mode 100755
index 000000000..71771df0b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/9wait.c
@@ -0,0 +1,93 @@
+#include "lib.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s)
+{
+ int quoting;
+ char *t;
+
+ quoting = 0;
+ t = s; /* s is output string, t is input string */
+ while(*t!='\0' && (quoting || strchr(qsep, *t)==nil)){
+ if(*t != '\''){
+ *s++ = *t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t++;
+ *s++ = *t++;
+ }
+ if(*s != '\0'){
+ *s = '\0';
+ if(t == s)
+ t++;
+ }
+ return t;
+}
+
+static int
+tokenize(char *s, char **args, int maxargs)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && strchr(qsep, *s)!=nil)
+ s++;
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = qtoken(s);
+ }
+
+ return nargs;
+}
+
+Waitmsg*
+_WAIT(void)
+{
+ int n, l;
+ char buf[512], *fld[5];
+ Waitmsg *w;
+
+ n = _AWAIT(buf, sizeof buf-1);
+ if(n < 0)
+ return nil;
+ buf[n] = '\0';
+ if(tokenize(buf, fld, 5) != 5){
+ strcpy(buf, "couldn't parse wait message");
+ _ERRSTR(buf, sizeof buf);
+ return nil;
+ }
+ l = strlen(fld[4])+1;
+ w = malloc(sizeof(Waitmsg)+l);
+ if(w == nil)
+ return nil;
+ w->pid = atoi(fld[0]);
+ w->time[0] = atoi(fld[1]);
+ w->time[1] = atoi(fld[2]);
+ w->time[2] = atoi(fld[3]);
+ w->msg = (char*)&w[1];
+ memmove(w->msg, fld[4], l);
+ return w;
+}
+
diff --git a/sys/src/ape/lib/ap/plan9/9write.c b/sys/src/ape/lib/ap/plan9/9write.c
new file mode 100755
index 000000000..e87a45ade
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/9write.c
@@ -0,0 +1,11 @@
+#include "lib.h"
+#include <string.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+long
+_WRITE(int fd, void *buf, long n)
+{
+ return _PWRITE(fd, buf, n, -1LL);
+}
diff --git a/sys/src/ape/lib/ap/plan9/_buf.c b/sys/src/ape/lib/ap/plan9/_buf.c
new file mode 100755
index 000000000..21fe282bb
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_buf.c
@@ -0,0 +1,472 @@
+#define _BSDTIME_EXTENSION
+#define _LOCK_EXTENSION
+#include "lib.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <lock.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <unistd.h>
+#include "sys9.h"
+
+typedef struct Muxseg {
+ Lock lock; /* for mutual exclusion access to buffer variables */
+ int curfds; /* number of fds currently buffered */
+ int selwait; /* true if selecting process is waiting */
+ int waittime; /* time for timer process to wait */
+ fd_set rwant; /* fd's that select wants to read */
+ fd_set ewant; /* fd's that select wants to know eof info on */
+ Muxbuf bufs[INITBUFS]; /* can grow, via segbrk() */
+} Muxseg;
+
+#define MUXADDR ((void*)0x6000000)
+static Muxseg *mux = 0; /* shared memory segment */
+
+/* _muxsid and _killmuxsid are known in libbsd's listen.c */
+int _muxsid = -1; /* group id of copy processes */
+static int _mainpid = -1;
+static int timerpid = -1; /* pid of a timer process */
+
+void _killmuxsid(void);
+static void _copyproc(int, Muxbuf*);
+static void _timerproc(void);
+static void _resettimer(void);
+
+static int copynotehandler(void *, char *);
+
+/* assume FD_SETSIZE is 96 */
+#define FD_ANYSET(p) ((p)->fds_bits[0] || (p)->fds_bits[1] || (p)->fds_bits[2])
+
+/*
+ * Start making fd read-buffered: make the shared segment, if necessary,
+ * allocate a slot (index into mux->bufs), and fork a child to read the fd
+ * and write into the slot-indexed buffer.
+ * Return -1 if we can't do it.
+ */
+int
+_startbuf(int fd)
+{
+ long i, n, slot;
+ int pid, sid;
+ Fdinfo *f;
+ Muxbuf *b;
+
+ if(mux == 0){
+ _RFORK(RFREND);
+ mux = (Muxseg*)_SEGATTACH(0, "shared", MUXADDR, sizeof(Muxseg));
+ if((long)mux == -1){
+ _syserrno();
+ return -1;
+ }
+ /* segattach has returned zeroed memory */
+ atexit(_killmuxsid);
+ }
+
+ if(fd == -1)
+ return 0;
+
+ lock(&mux->lock);
+ slot = mux->curfds++;
+ if(mux->curfds > INITBUFS) {
+ if(_SEGBRK(mux, mux->bufs+mux->curfds) < 0){
+ _syserrno();
+ unlock(&mux->lock);
+ return -1;
+ }
+ }
+
+ f = &_fdinfo[fd];
+ b = &mux->bufs[slot];
+ b->n = 0;
+ b->putnext = b->data;
+ b->getnext = b->data;
+ b->eof = 0;
+ b->fd = fd;
+ if(_mainpid == -1)
+ _mainpid = getpid();
+ if((pid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){
+ /* copy process ... */
+ if(_muxsid == -1) {
+ _RFORK(RFNOTEG);
+ _muxsid = getpgrp();
+ } else
+ setpgid(getpid(), _muxsid);
+ _NOTIFY(copynotehandler);
+ for(i=0; i<OPEN_MAX; i++)
+ if(i!=fd && (_fdinfo[i].flags&FD_ISOPEN))
+ _CLOSE(i);
+ _RENDEZVOUS(0, _muxsid);
+ _copyproc(fd, b);
+ }
+
+ /* parent process continues ... */
+ b->copypid = pid;
+ f->buf = b;
+ f->flags |= FD_BUFFERED;
+ unlock(&mux->lock);
+ _muxsid = _RENDEZVOUS(0, 0);
+ /* leave fd open in parent so system doesn't reuse it */
+ return 0;
+}
+
+/*
+ * The given buffered fd is being closed.
+ * Set the fd field in the shared buffer to -1 to tell copyproc
+ * to exit, and kill the copyproc.
+ */
+void
+_closebuf(int fd)
+{
+ Muxbuf *b;
+
+ b = _fdinfo[fd].buf;
+ if(!b)
+ return;
+ lock(&mux->lock);
+ b->fd = -1;
+ unlock(&mux->lock);
+ kill(b->copypid, SIGKILL);
+}
+
+/* child copy procs execute this until eof */
+static void
+_copyproc(int fd, Muxbuf *b)
+{
+ unsigned char *e;
+ int n;
+ int nzeros;
+
+ e = &b->data[PERFDMAX];
+ for(;;) {
+ /* make sure there's room */
+ lock(&mux->lock);
+ if(e - b->putnext < READMAX) {
+ if(b->getnext == b->putnext) {
+ b->getnext = b->putnext = b->data;
+ unlock(&mux->lock);
+ } else {
+ /* sleep until there's room */
+ b->roomwait = 1;
+ unlock(&mux->lock);
+ _RENDEZVOUS((unsigned long)&b->roomwait, 0);
+ }
+ } else
+ unlock(&mux->lock);
+ /*
+ * A Zero-length _READ might mean a zero-length write
+ * happened, or it might mean eof; try several times to
+ * disambiguate (posix read() discards 0-length messages)
+ */
+ nzeros = 0;
+ do {
+ n = _READ(fd, b->putnext, READMAX);
+ if(b->fd == -1) {
+ _exit(0); /* we've been closed */
+ }
+ } while(n == 0 && ++nzeros < 3);
+ lock(&mux->lock);
+ if(n <= 0) {
+ b->eof = 1;
+ if(mux->selwait && FD_ISSET(fd, &mux->ewant)) {
+ mux->selwait = 0;
+ unlock(&mux->lock);
+ _RENDEZVOUS((unsigned long)&mux->selwait, fd);
+ } else if(b->datawait) {
+ b->datawait = 0;
+ unlock(&mux->lock);
+ _RENDEZVOUS((unsigned long)&b->datawait, 0);
+ } else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) {
+ mux->selwait = 0;
+ unlock(&mux->lock);
+ _RENDEZVOUS((unsigned long)&mux->selwait, fd);
+ } else
+ unlock(&mux->lock);
+ _exit(0);
+ } else {
+ b->putnext += n;
+ b->n += n;
+ if(b->n > 0) {
+ /* parent process cannot be both in datawait and selwait */
+ if(b->datawait) {
+ b->datawait = 0;
+ unlock(&mux->lock);
+ /* wake up _bufreading process */
+ _RENDEZVOUS((unsigned long)&b->datawait, 0);
+ } else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) {
+ mux->selwait = 0;
+ unlock(&mux->lock);
+ /* wake up selecting process */
+ _RENDEZVOUS((unsigned long)&mux->selwait, fd);
+ } else
+ unlock(&mux->lock);
+ } else
+ unlock(&mux->lock);
+ }
+ }
+}
+
+/* like read(), for a buffered fd; extra arg noblock says don't wait for data if true */
+int
+_readbuf(int fd, void *addr, int nwant, int noblock)
+{
+ Muxbuf *b;
+ int ngot;
+
+ b = _fdinfo[fd].buf;
+ if(b->eof && b->n == 0) {
+goteof:
+ return 0;
+ }
+ if(b->n == 0 && noblock) {
+ errno = EAGAIN;
+ return -1;
+ }
+ /* make sure there's data */
+ lock(&mux->lock);
+ ngot = b->putnext - b->getnext;
+ if(ngot == 0) {
+ /* maybe EOF just happened */
+ if(b->eof) {
+ unlock(&mux->lock);
+ goto goteof;
+ }
+ /* sleep until there's data */
+ b->datawait = 1;
+ unlock(&mux->lock);
+ _RENDEZVOUS((unsigned long)&b->datawait, 0);
+ lock(&mux->lock);
+ ngot = b->putnext - b->getnext;
+ }
+ if(ngot == 0) {
+ unlock(&mux->lock);
+ goto goteof;
+ }
+ if(ngot > nwant)
+ ngot = nwant;
+ memcpy(addr, b->getnext, ngot);
+ b->getnext += ngot;
+ b->n -= ngot;
+ if(b->getnext == b->putnext && b->roomwait) {
+ b->getnext = b->putnext = b->data;
+ b->roomwait = 0;
+ unlock(&mux->lock);
+ /* wake up copy process */
+ _RENDEZVOUS((unsigned long)&b->roomwait, 0);
+ } else
+ unlock(&mux->lock);
+ return ngot;
+}
+
+int
+select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
+{
+ int n, i, tmp, t, slots, fd, err;
+ Fdinfo *f;
+ Muxbuf *b;
+
+ if(timeout)
+ t = timeout->tv_sec*1000 + (timeout->tv_usec+999)/1000;
+ else
+ t = -1;
+ if(!((rfds && FD_ANYSET(rfds)) || (wfds && FD_ANYSET(wfds))
+ || (efds && FD_ANYSET(efds)))) {
+ /* no requested fds */
+ if(t > 0)
+ _SLEEP(t);
+ return 0;
+ }
+
+ _startbuf(-1);
+
+ /* make sure all requested rfds and efds are buffered */
+ if(nfds >= OPEN_MAX)
+ nfds = OPEN_MAX;
+ for(i = 0; i < nfds; i++)
+ if((rfds && FD_ISSET(i, rfds)) || (efds && FD_ISSET(i, efds))){
+ f = &_fdinfo[i];
+ if(!(f->flags&FD_BUFFERED))
+ if(_startbuf(i) != 0) {
+ return -1;
+ }
+ b = f->buf;
+ if(rfds && FD_ISSET(i,rfds) && b->eof && b->n == 0)
+ if(efds == 0 || !FD_ISSET(i,efds)) {
+ errno = EBADF; /* how X tells a client is gone */
+ return -1;
+ }
+ }
+
+ /* check wfds; for now, we'll say they are all ready */
+ n = 0;
+ if(wfds && FD_ANYSET(wfds)){
+ for(i = 0; i<nfds; i++)
+ if(FD_ISSET(i, wfds)) {
+ n++;
+ }
+ }
+
+ lock(&mux->lock);
+
+ slots = mux->curfds;
+ FD_ZERO(&mux->rwant);
+ FD_ZERO(&mux->ewant);
+
+ for(i = 0; i<slots; i++) {
+ b = &mux->bufs[i];
+ fd = b->fd;
+ if(fd == -1)
+ continue;
+ err = 0;
+ if(efds && FD_ISSET(fd, efds)) {
+ if(b->eof && b->n == 0){
+ err = 1;
+ n++;
+ }else{
+ FD_CLR(fd, efds);
+ FD_SET(fd, &mux->ewant);
+ }
+ }
+ if(rfds && FD_ISSET(fd, rfds)) {
+ if(!err && (b->n > 0 || b->eof))
+ n++;
+ else{
+ FD_CLR(fd, rfds);
+ FD_SET(fd, &mux->rwant);
+ }
+ }
+ }
+ if(n || !(FD_ANYSET(&mux->rwant) || FD_ANYSET(&mux->ewant)) || t == 0) {
+ FD_ZERO(&mux->rwant);
+ FD_ZERO(&mux->ewant);
+ unlock(&mux->lock);
+ return n;
+ }
+
+ if(timeout) {
+ mux->waittime = t;
+ if(timerpid == -1)
+ _timerproc();
+ else
+ _resettimer();
+ }
+ mux->selwait = 1;
+ unlock(&mux->lock);
+ fd = _RENDEZVOUS((unsigned long)&mux->selwait, 0);
+ if(fd >= 0) {
+ b = _fdinfo[fd].buf;
+ if(FD_ISSET(fd, &mux->rwant)) {
+ FD_SET(fd, rfds);
+ n = 1;
+ } else if(FD_ISSET(fd, &mux->ewant) && b->eof && b->n == 0) {
+ FD_SET(fd, efds);
+ n = 1;
+ }
+ }
+ FD_ZERO(&mux->rwant);
+ FD_ZERO(&mux->ewant);
+ return n;
+}
+
+static int timerreset;
+static int timerpid;
+
+static void
+alarmed(int v)
+{
+ timerreset = 1;
+}
+
+/* a little over an hour */
+#define LONGWAIT 4000001
+
+static void
+_killtimerproc(void)
+{
+ if(timerpid > 0)
+ kill(timerpid, SIGKILL);
+}
+
+static void
+_timerproc(void)
+{
+ int i;
+
+ if((timerpid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){
+ /* timer process */
+ setpgid(getpid(), _muxsid);
+ signal(SIGALRM, alarmed);
+ for(i=0; i<OPEN_MAX; i++)
+ _CLOSE(i);
+ _RENDEZVOUS(1, 0);
+ for(;;) {
+ _SLEEP(mux->waittime);
+ if(timerreset) {
+ timerreset = 0;
+ } else {
+ lock(&mux->lock);
+ if(mux->selwait && mux->waittime != LONGWAIT) {
+ mux->selwait = 0;
+ mux->waittime = LONGWAIT;
+ unlock(&mux->lock);
+ _RENDEZVOUS((unsigned long)&mux->selwait, -2);
+ } else {
+ mux->waittime = LONGWAIT;
+ unlock(&mux->lock);
+ }
+ }
+ }
+ }
+ atexit(_killtimerproc);
+ /* parent process continues */
+ _RENDEZVOUS(1, 0);
+}
+
+static void
+_resettimer(void)
+{
+ kill(timerpid, SIGALRM);
+}
+
+void
+_killmuxsid(void)
+{
+ if(_muxsid != -1 && (_mainpid == getpid() || _mainpid == -1))
+ kill(-_muxsid,SIGTERM);
+}
+
+/* call this on fork(), because reading a BUFFERED fd won't work in child */
+void
+_detachbuf(void)
+{
+ int i;
+ Fdinfo *f;
+
+ if(mux == 0)
+ return;
+ _SEGDETACH(mux);
+ for(i = 0; i < OPEN_MAX; i++){
+ f = &_fdinfo[i];
+ if(f->flags&FD_BUFFERED)
+ f->flags = (f->flags&~FD_BUFFERED) | FD_BUFFEREDX;
+ /* mark 'poisoned' */
+ }
+ mux = 0;
+ _muxsid = -1;
+ _mainpid = -1;
+ timerpid = -1;
+}
+
+static int
+copynotehandler(void *u, char *msg)
+{
+ int i;
+ void(*f)(int);
+
+ if(_finishing)
+ _finish(0, 0);
+ _NOTED(1);
+}
diff --git a/sys/src/ape/lib/ap/plan9/_dirconv.c b/sys/src/ape/lib/ap/plan9/_dirconv.c
new file mode 100755
index 000000000..3889c2ee2
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_dirconv.c
@@ -0,0 +1,65 @@
+#include "lib.h"
+#include <string.h>
+#include "sys9.h"
+#include "dir.h"
+
+#define CHAR(x) *p++ = f->x
+#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
+#define LONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24; p += 4
+#define VLONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24;\
+ p[4] = 0; p[5] = 0; p[6] = 0; p[7] = 0; p += 8
+#define STRING(x,n) memcpy(p, f->x, n); p += n
+
+int
+convD2M(Dir *f, char *ap)
+{
+ unsigned char *p;
+
+ p = (unsigned char*)ap;
+ STRING(name, sizeof(f->name));
+ STRING(uid, sizeof(f->uid));
+ STRING(gid, sizeof(f->gid));
+ LONG(qid.path);
+ LONG(qid.vers);
+ LONG(mode);
+ LONG(atime);
+ LONG(mtime);
+ VLONG(length);
+ SHORT(type);
+ SHORT(dev);
+ return p - (unsigned char*)ap;
+}
+
+#undef CHAR
+#undef SHORT
+#undef LONG
+#undef VLONG
+#undef STRING
+
+#define CHAR(x) f->x = *p++
+#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
+#define LONG(x) f->x = (p[0] | (p[1]<<8) |\
+ (p[2]<<16) | (p[3]<<24)); p += 4
+#define VLONG(x) f->x = (p[0] | (p[1]<<8) |\
+ (p[2]<<16) | (p[3]<<24)); p += 8
+#define STRING(x,n) memcpy(f->x, p, n); p += n
+
+int
+convM2D(char *ap, Dir *f)
+{
+ unsigned char *p;
+
+ p = (unsigned char*)ap;
+ STRING(name, sizeof(f->name));
+ STRING(uid, sizeof(f->uid));
+ STRING(gid, sizeof(f->gid));
+ LONG(qid.path);
+ LONG(qid.vers);
+ LONG(mode);
+ LONG(atime);
+ LONG(mtime);
+ VLONG(length);
+ SHORT(type);
+ SHORT(dev);
+ return p - (unsigned char*)ap;
+}
diff --git a/sys/src/ape/lib/ap/plan9/_envsetup.c b/sys/src/ape/lib/ap/plan9/_envsetup.c
new file mode 100755
index 000000000..55cf33b85
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_envsetup.c
@@ -0,0 +1,123 @@
+#include "lib.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include "sys9.h"
+#include "dir.h"
+
+/*
+ * Called before main to initialize environ.
+ * Some plan9 environment variables
+ * have 0 bytes in them (notably $path);
+ * we change them to 1's (and execve changes back)
+ *
+ * Also, register the note handler.
+ */
+
+char **environ;
+int errno;
+unsigned long _clock;
+static char name[NAME_MAX+5] = "#e";
+static void fdsetup(char *, char *);
+static void sigsetup(char *, char *);
+
+enum {
+ Envhunk=7000,
+};
+
+void
+_envsetup(void)
+{
+ int dfd;
+ struct dirent *de;
+ int n, nd, m, i, j, f;
+ int psize, cnt;
+ int nohandle;
+ int fdinited;
+ char *ps, *p;
+ char **pp;
+ Dir *d9, *d9a;
+
+ nohandle = 0;
+ fdinited = 0;
+ cnt = 0;
+ dfd = _OPEN(name, 0);
+ if(dfd < 0) {
+ static char **emptyenvp = 0;
+ environ = emptyenvp;
+ return;
+ }
+ name[2] = '/';
+ ps = p = malloc(Envhunk);
+ psize = Envhunk;
+ nd = _dirreadall(dfd, &d9a);
+ _CLOSE(dfd);
+ for(j=0; j<nd; j++){
+ d9 = &d9a[j];
+ n = strlen(d9->name);
+ m = d9->length;
+ i = p - ps;
+ if(i+n+1+m+1 > psize) {
+ psize += (n+m+2 < Envhunk)? Envhunk : n+m+2;
+ ps = realloc(ps, psize);
+ p = ps + i;
+ }
+ memcpy(p, d9->name, n);
+ p[n] = '=';
+ strcpy(name+3, d9->name);
+ f = _OPEN(name, O_RDONLY);
+ if(f < 0 || _READ(f, p+n+1, m) != m)
+ m = 0;
+ _CLOSE(f);
+ if(p[n+m] == 0)
+ m--;
+ for(i=0; i<m; i++)
+ if(p[n+1+i] == 0)
+ p[n+1+i] = 1;
+ p[n+1+m] = 0;
+ if(strcmp(d9->name, "_fdinfo") == 0) {
+ _fdinit(p+n+1, p+n+1+m);
+ fdinited = 1;
+ } else if(strcmp(d9->name, "_sighdlr") == 0)
+ sigsetup(p+n+1, p+n+1+m);
+ else if(strcmp(d9->name, "nohandle") == 0)
+ nohandle = 1;
+ p += n+m+2;
+ cnt++;
+ }
+ free(d9a);
+ if(!fdinited)
+ _fdinit(0, 0);
+ environ = pp = malloc((1+cnt)*sizeof(char *));
+ p = ps;
+ for(i = 0; i < cnt; i++) {
+ *pp++ = p;
+ p = memchr(p, 0, ps+psize-p);
+ if (!p)
+ break;
+ p++;
+ }
+ *pp = 0;
+ if(!nohandle)
+ _NOTIFY(_notehandler);
+}
+
+static void
+sigsetup(char *s, char *se)
+{
+ int i, sig;
+ char *e;
+
+ while(s < se){
+ sig = strtoul(s, &e, 10);
+ if(s == e)
+ break;
+ s = e;
+ if(sig <= MAXSIG)
+ _sighdlr[sig] = SIG_IGN;
+ }
+}
diff --git a/sys/src/ape/lib/ap/plan9/_errno.c b/sys/src/ape/lib/ap/plan9/_errno.c
new file mode 100755
index 000000000..8e5caad7d
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_errno.c
@@ -0,0 +1,124 @@
+#include "lib.h"
+#include "sys9.h"
+#include <string.h>
+#include <errno.h>
+
+/* make this global, so programs can look at it if errno is unilluminating */
+
+/* see also: ../stdio/strerror.c, with errno-> string mapping */
+
+char _plan9err[ERRMAX];
+
+static struct errmap {
+ int errno;
+ char *ename;
+} map[] = {
+ /* from /sys/src/9/port/errstr.h */
+ {EINVAL, "inconsistent mount"},
+ {EINVAL, "not mounted"},
+ {EINVAL, "not in union"},
+ {EIO, "mount rpc error"},
+ {EIO, "mounted device shut down"},
+ {EPERM, "mounted directory forbids creation"},
+ {ENOENT, "does not exist"},
+ {ENXIO, "unknown device in # filename"},
+ {ENOTDIR, "not a directory"},
+ {EISDIR, "file is a directory"},
+ {EINVAL, "bad character in file name"},
+ {EINVAL, "file name syntax"},
+ {EPERM, "permission denied"},
+ {EPERM, "inappropriate use of fd"},
+ {EINVAL, "bad arg in system call"},
+ {EBUSY, "device or object already in use"},
+ {EIO, "i/o error"},
+ {EIO, "read or write too large"},
+ {EIO, "read or write too small"},
+ {EADDRINUSE, "network port not available"},
+ {ESHUTDOWN, "write to hungup stream"},
+ {ESHUTDOWN, "i/o on hungup channel"},
+ {EINVAL, "bad process or channel control request"},
+ {EBUSY, "no free devices"},
+ {ESRCH, "process exited"},
+ {ECHILD, "no living children"},
+ {EIO, "i/o error in demand load"},
+ {ENOMEM, "virtual memory allocation failed"},
+ {EBADF, "fd out of range or not open"},
+ {EMFILE, "no free file descriptors"},
+ {ESPIPE, "seek on a stream"},
+ {ENOEXEC, "exec header invalid"},
+ {ETIMEDOUT, "connection timed out"},
+ {ECONNREFUSED, "connection refused"},
+ {ECONNREFUSED, "connection in use"},
+ {EINTR, "interrupted"},
+ {ENOMEM, "kernel allocate failed"},
+ {EINVAL, "segments overlap"},
+ {EIO, "i/o count too small"},
+ {EGREG, "ken has left the building"},
+ {EINVAL, "bad attach specifier"},
+
+ /* from exhausted() calls in kernel */
+ {ENFILE, "no free file descriptors"},
+ {EBUSY, "no free mount devices"},
+ {EBUSY, "no free mount rpc buffer"},
+ {EBUSY, "no free segments"},
+ {ENOMEM, "no free memory"},
+ {ENOBUFS, "no free Blocks"},
+ {EBUSY, "no free routes"},
+
+ /* from ken */
+ {EINVAL, "attach -- bad specifier"},
+ {EBADF, "unknown fid"},
+ {EINVAL, "bad character in directory name"},
+ {EBADF, "read/write -- on non open fid"},
+ {EIO, "read/write -- count too big"},
+ {EIO, "phase error -- directory entry not allocated"},
+ {EIO, "phase error -- qid does not match"},
+ {EACCES, "access permission denied"},
+ {ENOENT, "directory entry not found"},
+ {EINVAL, "open/create -- unknown mode"},
+ {ENOTDIR, "walk -- in a non-directory"},
+ {ENOTDIR, "create -- in a non-directory"},
+ {EIO, "phase error -- cannot happen"},
+ {EEXIST, "create -- file exists"},
+ {EINVAL, "create -- . and .. illegal names"},
+ {ENOTEMPTY, "directory not empty"},
+ {EINVAL, "attach -- privileged user"},
+ {EPERM, "wstat -- not owner"},
+ {EPERM, "wstat -- not in group"},
+ {EINVAL, "create/wstat -- bad character in file name"},
+ {EBUSY, "walk -- too many (system wide)"},
+ {EROFS, "file system read only"},
+ {ENOSPC, "file system full"},
+ {EINVAL, "read/write -- offset negative"},
+ {EBUSY, "open/create -- file is locked"},
+ {EBUSY, "close/read/write -- lock is broken"},
+
+ /* from sockets */
+ {ENOTSOCK, "not a socket"},
+ {EPROTONOSUPPORT, "protocol not supported"},
+ {ECONNREFUSED, "connection refused"},
+ {EAFNOSUPPORT, "address family not supported"},
+ {ENOBUFS, "insufficient buffer space"},
+ {EOPNOTSUPP, "operation not supported"},
+ {EADDRINUSE, "address in use"},
+ {EGREG, "unnamed error message"},
+};
+
+#define NERRMAP (sizeof(map)/sizeof(struct errmap))
+
+/* convert last system call error to an errno */
+void
+_syserrno(void)
+{
+ int i;
+
+ if(_ERRSTR(_plan9err, sizeof _plan9err) < 0)
+ errno = EINVAL;
+ else{
+ for(i = 0; i < NERRMAP; i++)
+ if(strstr(_plan9err, map[i].ename) != 0)
+ break;
+ _ERRSTR(_plan9err, sizeof _plan9err);
+ errno = (i < NERRMAP)? map[i].errno : EINVAL;
+ }
+}
diff --git a/sys/src/ape/lib/ap/plan9/_exit.c b/sys/src/ape/lib/ap/plan9/_exit.c
new file mode 100755
index 000000000..e3886ff18
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_exit.c
@@ -0,0 +1,58 @@
+#include "lib.h"
+#include "sys9.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+int _finishing = 0;
+int _sessleader = 0;
+
+static char exitstatus[ERRMAX];
+
+void
+_exit(int status)
+{
+ _finish(status, 0);
+}
+
+void
+_finish(int status, char *term)
+{
+ int i, nalive;
+ char *cp;
+
+ if(_finishing)
+ _EXITS(exitstatus);
+ _finishing = 1;
+ if(status){
+ cp = _ultoa(exitstatus, status & 0xFF);
+ *cp = 0;
+ }else if(term){
+ strncpy(exitstatus, term, ERRMAX);
+ exitstatus[ERRMAX-1] = '\0';
+ }
+ if(_sessleader)
+ kill(0, SIGTERM);
+ _EXITS(exitstatus);
+}
+
+/* emulate: return p+sprintf(p, "%uld", v) */
+#define IDIGIT 15
+char *
+_ultoa(char *p, unsigned long v)
+{
+ char s[IDIGIT];
+ int n, i;
+
+ s[IDIGIT-1] = 0;
+ for(i = IDIGIT-2; i; i--){
+ n = v % 10;
+ s[i] = n + '0';
+ v = v / 10;
+ if(v == 0)
+ break;
+ }
+ strcpy(p, s+i);
+ return p + (IDIGIT-1-i);
+}
diff --git a/sys/src/ape/lib/ap/plan9/_fcall.c b/sys/src/ape/lib/ap/plan9/_fcall.c
new file mode 100755
index 000000000..394f4cc08
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_fcall.c
@@ -0,0 +1,422 @@
+#include <string.h>
+#include "sys9.h"
+#include "lib.h"
+#include "dir.h"
+#include "fcall.h"
+
+typedef unsigned char uchar;
+
+#define CHAR(x) *p++ = f->x
+#define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
+#define LONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24; p += 4
+#define VLONG(x) p[0] = f->x; p[1] = f->x>>8; p[2] = f->x>>16; p[3] = f->x>>24;\
+ p[4] = 0; p[5] = 0; p[6] = 0; p[7] = 0; p += 8
+#define STRING(x,n) memcpy(p, f->x, n); p += n
+
+int
+convS2M(Fcall *f, char *ap)
+{
+ uchar *p;
+
+ p = (uchar*)ap;
+ CHAR(type);
+ SHORT(tag);
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tosession:
+ case Tnop:
+ break;
+
+ case Tsession:
+ STRING(chal, sizeof(f->chal));
+ break;
+
+ case Tflush:
+ SHORT(oldtag);
+ break;
+
+ case Tattach:
+ SHORT(fid);
+ STRING(uname, sizeof(f->uname));
+ STRING(aname, sizeof(f->aname));
+ STRING(ticket, sizeof(f->ticket));
+ STRING(auth, sizeof(f->auth));
+ break;
+
+ case Toattach:
+ SHORT(fid);
+ STRING(uname, sizeof(f->uname));
+ STRING(aname, sizeof(f->aname));
+ STRING(ticket, NAMELEN);
+ break;
+
+ case Tauth:
+ SHORT(fid);
+ STRING(uname, sizeof(f->uname));
+ STRING(ticket, 8+NAMELEN);
+ break;
+
+ case Tclone:
+ SHORT(fid);
+ SHORT(newfid);
+ break;
+
+ case Twalk:
+ SHORT(fid);
+ STRING(name, sizeof(f->name));
+ break;
+
+ case Topen:
+ SHORT(fid);
+ CHAR(mode);
+ break;
+
+ case Tcreate:
+ SHORT(fid);
+ STRING(name, sizeof(f->name));
+ LONG(perm);
+ CHAR(mode);
+ break;
+
+ case Tread:
+ SHORT(fid);
+ VLONG(offset);
+ SHORT(count);
+ break;
+
+ case Twrite:
+ SHORT(fid);
+ VLONG(offset);
+ SHORT(count);
+ p++; /* pad(1) */
+ STRING(data, f->count);
+ break;
+
+ case Tclunk:
+ SHORT(fid);
+ break;
+
+ case Tremove:
+ SHORT(fid);
+ break;
+
+ case Tstat:
+ SHORT(fid);
+ break;
+
+ case Twstat:
+ SHORT(fid);
+ STRING(stat, sizeof(f->stat));
+ break;
+
+ case Tclwalk:
+ SHORT(fid);
+ SHORT(newfid);
+ STRING(name, sizeof(f->name));
+ break;
+/*
+ */
+ case Rosession:
+ case Rnop:
+ break;
+
+ case Rsession:
+ STRING(chal, sizeof(f->chal));
+ STRING(authid, sizeof(f->authid));
+ STRING(authdom, sizeof(f->authdom));
+ break;
+
+ case Rerror:
+ STRING(ename, sizeof(f->ename));
+ break;
+
+ case Rflush:
+ break;
+
+ case Rattach:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ STRING(rauth, sizeof(f->rauth));
+ break;
+
+ case Roattach:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Rauth:
+ SHORT(fid);
+ STRING(ticket, 8+8+7+7);
+ break;
+
+ case Rclone:
+ SHORT(fid);
+ break;
+
+ case Rwalk:
+ case Rclwalk:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Ropen:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Rcreate:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Rread:
+ SHORT(fid);
+ SHORT(count);
+ p++; /* pad(1) */
+ STRING(data, f->count);
+ break;
+
+ case Rwrite:
+ SHORT(fid);
+ SHORT(count);
+ break;
+
+ case Rclunk:
+ SHORT(fid);
+ break;
+
+ case Rremove:
+ SHORT(fid);
+ break;
+
+ case Rstat:
+ SHORT(fid);
+ STRING(stat, sizeof(f->stat));
+ break;
+
+ case Rwstat:
+ SHORT(fid);
+ break;
+ }
+ return p - (uchar*)ap;
+}
+
+#undef CHAR
+#undef SHORT
+#undef LONG
+#undef VLONG
+#undef STRING
+
+#define CHAR(x) f->x = *p++
+#define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
+#define LONG(x) f->x = (p[0] | (p[1]<<8) |\
+ (p[2]<<16) | (p[3]<<24)); p += 4
+#define VLONG(x) f->x = (p[0] | (p[1]<<8) |\
+ (p[2]<<16) | (p[3]<<24)); p += 8
+#define STRING(x,n) memcpy(f->x, p, n); p += n
+
+int
+convM2S(char *ap, Fcall *f, int n)
+{
+ uchar *p;
+
+ p = (uchar*)ap;
+ CHAR(type);
+ SHORT(tag);
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tnop:
+ case Tosession:
+ break;
+
+ case Tsession:
+ STRING(chal, sizeof(f->chal));
+ break;
+
+ case Tflush:
+ SHORT(oldtag);
+ break;
+
+ case Tattach:
+ SHORT(fid);
+ STRING(uname, sizeof(f->uname));
+ STRING(aname, sizeof(f->aname));
+ STRING(ticket, sizeof(f->ticket));
+ STRING(auth, sizeof(f->auth));
+ break;
+
+ case Toattach:
+ SHORT(fid);
+ STRING(uname, sizeof(f->uname));
+ STRING(aname, sizeof(f->aname));
+ STRING(ticket, NAMELEN);
+ break;
+
+ case Tauth:
+ SHORT(fid);
+ STRING(uname, sizeof(f->uname));
+ STRING(ticket, 8+NAMELEN);
+ break;
+
+ case Tclone:
+ SHORT(fid);
+ SHORT(newfid);
+ break;
+
+ case Twalk:
+ SHORT(fid);
+ STRING(name, sizeof(f->name));
+ break;
+
+ case Topen:
+ SHORT(fid);
+ CHAR(mode);
+ break;
+
+ case Tcreate:
+ SHORT(fid);
+ STRING(name, sizeof(f->name));
+ LONG(perm);
+ CHAR(mode);
+ break;
+
+ case Tread:
+ SHORT(fid);
+ VLONG(offset);
+ SHORT(count);
+ break;
+
+ case Twrite:
+ SHORT(fid);
+ VLONG(offset);
+ SHORT(count);
+ p++; /* pad(1) */
+ f->data = (char*)p; p += f->count;
+ break;
+
+ case Tclunk:
+ SHORT(fid);
+ break;
+
+ case Tremove:
+ SHORT(fid);
+ break;
+
+ case Tstat:
+ SHORT(fid);
+ break;
+
+ case Twstat:
+ SHORT(fid);
+ STRING(stat, sizeof(f->stat));
+ break;
+
+ case Tclwalk:
+ SHORT(fid);
+ SHORT(newfid);
+ STRING(name, sizeof(f->name));
+ break;
+/*
+ */
+ case Rnop:
+ case Rosession:
+ break;
+
+ case Rsession:
+ STRING(chal, sizeof(f->chal));
+ STRING(authid, sizeof(f->authid));
+ STRING(authdom, sizeof(f->authdom));
+ break;
+
+ case Rerror:
+ STRING(ename, sizeof(f->ename));
+ break;
+
+ case Rflush:
+ break;
+
+ case Rattach:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ STRING(rauth, sizeof(f->rauth));
+ break;
+
+ case Roattach:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Rauth:
+ SHORT(fid);
+ STRING(ticket, 8+8+7+7);
+ break;
+
+ case Rclone:
+ SHORT(fid);
+ break;
+
+ case Rwalk:
+ case Rclwalk:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Ropen:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Rcreate:
+ SHORT(fid);
+ LONG(qid.path);
+ LONG(qid.vers);
+ break;
+
+ case Rread:
+ SHORT(fid);
+ SHORT(count);
+ p++; /* pad(1) */
+ f->data = (char*)p; p += f->count;
+ break;
+
+ case Rwrite:
+ SHORT(fid);
+ SHORT(count);
+ break;
+
+ case Rclunk:
+ SHORT(fid);
+ break;
+
+ case Rremove:
+ SHORT(fid);
+ break;
+
+ case Rstat:
+ SHORT(fid);
+ STRING(stat, sizeof(f->stat));
+ break;
+
+ case Rwstat:
+ SHORT(fid);
+ break;
+ }
+ if((uchar*)ap+n == p)
+ return n;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/_fdinfo.c b/sys/src/ape/lib/ap/plan9/_fdinfo.c
new file mode 100755
index 000000000..85bbeca95
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_fdinfo.c
@@ -0,0 +1,169 @@
+#define _BSDTIME_EXTENSION
+#include "lib.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include <string.h>
+
+extern int errno;
+Fdinfo _fdinfo[OPEN_MAX];
+
+/*
+ called from _envsetup, either with the value of the environment
+ variable _fdinfo (from s to se-1), or with s==0 if there was no _fdinfo
+*/
+static void
+defaultfdinit(void)
+{
+ int i;
+ Fdinfo *fi;
+
+ for(i = 0; i <= 2; i++) {
+ fi = &_fdinfo[i];
+ fi->flags = FD_ISOPEN;
+ fi->oflags = (i == 0)? O_RDONLY : O_WRONLY;
+ if(_isatty(i))
+ fi->flags |= FD_ISTTY;
+ }
+}
+
+static int
+readprocfdinit(void)
+{
+ /* construct info from /proc/$pid/fd */
+ char buf[8192];
+ Fdinfo *fi;
+ int fd, pfd, pid, n, tot, m;
+ char *s, *nexts;
+
+ memset(buf, 0, sizeof buf);
+ pfd = _OPEN("#c/pid", 0);
+ if(pfd < 0)
+ return -1;
+ if(_PREAD(pfd, buf, 100, 0) < 0){
+ _CLOSE(pfd);
+ return -1;
+ }
+ _CLOSE(pfd);
+ pid = strtoul(buf, 0, 10);
+ strcpy(buf, "#p/");
+ _ultoa(buf+3, pid);
+ strcat(buf, "/fd");
+ pfd = _OPEN(buf, 0);
+ if(pfd < 0)
+ return -1;
+ memset(buf, 0, sizeof buf);
+ tot = 0;
+ for(;;){
+ n = _PREAD(pfd, buf+tot, sizeof buf-tot, tot);
+ if(n <= 0)
+ break;
+ tot += n;
+ }
+ _CLOSE(pfd);
+ if(n < 0)
+ return -1;
+ buf[sizeof buf-1] = '\0';
+ s = strchr(buf, '\n'); /* skip current directory */
+ if(s == 0)
+ return -1;
+ s++;
+ m = 0;
+ for(; s && *s; s=nexts){
+ nexts = strchr(s, '\n');
+ if(nexts)
+ *nexts++ = '\0';
+ errno = 0;
+ fd = strtoul(s, &s, 10);
+ if(errno != 0)
+ return -1;
+ if(fd >= OPEN_MAX)
+ continue;
+ if(fd == pfd)
+ continue;
+ fi = &_fdinfo[fd];
+ fi->flags = FD_ISOPEN;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == 'r'){
+ m |= 1;
+ s++;
+ }
+ if(*s == 'w'){
+ m |= 2;
+ }
+ if(m==1)
+ fi->oflags = O_RDONLY;
+ else if(m==2)
+ fi->oflags = O_WRONLY;
+ else
+ fi->oflags = O_RDWR;
+ if(strlen(s) >= 9 && strcmp(s+strlen(s)-9, "/dev/cons") == 0)
+ fi->flags |= FD_ISTTY;
+ }
+ return 0;
+}
+
+static void
+sfdinit(int usedproc, char *s, char *se)
+{
+ int i;
+ Fdinfo *fi;
+ unsigned long fd, fl, ofl;
+ char *e;
+ struct stat sbuf;
+
+ while(s < se){
+ fd = strtoul(s, &e, 10);
+ if(s == e)
+ break;
+ s = e;
+ fl = strtoul(s, &e, 10);
+ if(s == e)
+ break;
+ s = e;
+ ofl = strtoul(s, &e, 10);
+ if(s == e)
+ break;
+ s = e;
+ if(fd < OPEN_MAX){
+ fi = &_fdinfo[fd];
+ if(usedproc && !(fi->flags&FD_ISOPEN))
+ continue; /* should probably ignore all of $_fdinit */
+ fi->flags = fl;
+ fi->oflags = ofl;
+ if(_isatty(fd))
+ fi->flags |= FD_ISTTY;
+ }
+ }
+
+}
+
+void
+_fdinit(char *s, char *se)
+{
+ int i, usedproc;
+ Fdinfo *fi;
+ struct stat sbuf;
+
+ usedproc = 0;
+ if(readprocfdinit() == 0)
+ usedproc = 1;
+else
+_WRITE(2, "FAILED\n", 7);
+ if(s)
+ sfdinit(usedproc, s, se);
+ if(!s && !usedproc)
+ defaultfdinit();
+
+ for(i = 0; i < OPEN_MAX; i++) {
+ fi = &_fdinfo[i];
+ if(fi->flags&FD_ISOPEN){
+ if(fstat(i, &sbuf) >= 0) {
+ fi->uid = sbuf.st_uid;
+ fi->gid = sbuf.st_gid;
+ }
+ }
+ }
+}
+
diff --git a/sys/src/ape/lib/ap/plan9/_getpw.c b/sys/src/ape/lib/ap/plan9/_getpw.c
new file mode 100755
index 000000000..151d7f3c8
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_getpw.c
@@ -0,0 +1,174 @@
+#include "lib.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "sys9.h"
+#include "dir.h"
+
+/*
+ * Search /adm/users for line with second field == *pname (if
+ * not NULL), else with first field == *pnum. Return non-zero
+ * if found, and fill in *pnum, *pname, and *plist to fields
+ * 1, 2, and 4
+ */
+
+enum {NAMEMAX = 20, MEMOMAX = 40 };
+
+static char *admusers = "/adm/users";
+
+/* we hold a fixed-length memo list of past lookups, and use a move-to-front
+ strategy to organize the list
+*/
+typedef struct Memo {
+ char name[NAMEMAX];
+ int num;
+ char *glist;
+} Memo;
+
+static Memo *memo[MEMOMAX];
+static int nmemo = 0;
+
+int
+_getpw(int *pnum, char **pname, char **plist)
+{
+ Dir *d;
+ int f, n, i, j, matchnum, m, matched;
+ char *eline, *f1, *f2, *f3, *f4;
+ Memo *mem;
+ static char *au = NULL;
+ vlong length;
+
+ if(!pname)
+ return 0;
+ if(au == NULL){
+ d = _dirstat(admusers);
+ if(d == nil)
+ return 0;
+ length = d->length;
+ free(d);
+ if((au = (char *)malloc(length+2)) == NULL)
+ return 0;
+ f = open(admusers, O_RDONLY);
+ if(f < 0)
+ return 0;
+ n = read(f, au, length);
+ if(n < 0)
+ return 0;
+ au[n] = 0;
+ }
+ matchnum = (*pname == NULL);
+ matched = 0;
+ /* try using memo */
+ for(i = 0; i<nmemo; i++) {
+ mem = memo[i];
+ if(matchnum)
+ matched = (mem->num == *pnum);
+ else
+ matched = (strcmp(mem->name, *pname) == 0);
+ if(matched) {
+ break;
+ }
+ }
+ if(!matched)
+ for(f1 = au, eline = au; !matched && *eline; f1 = eline+1){
+ eline = strchr(f1, '\n');
+ if(!eline)
+ eline = strchr(f1, 0);
+ if(*f1 == '#' || *f1 == '\n')
+ continue;
+ n = eline-f1;
+ f2 = memchr(f1, ':', n);
+ if(!f2)
+ continue;
+ f2++;
+ f3 = memchr(f2, ':', n-(f2-f1));
+ if(!f3)
+ continue;
+ f3++;
+ f4 = memchr(f3, ':', n-(f3-f1));
+ if(!f4)
+ continue;
+ f4++;
+ if(matchnum)
+ matched = (atoi(f1) == *pnum);
+ else{
+ int length;
+
+ length = f3-f2-1;
+ matched = length==strlen(*pname) && memcmp(*pname, f2, length)==0;
+ }
+ if(matched){
+ /* allocate and fill in a Memo structure */
+ mem = (Memo*)malloc(sizeof(struct Memo));
+ if(!mem)
+ return 0;
+ m = (f3-f2)-1;
+ if(m > NAMEMAX-1)
+ m = NAMEMAX-1;
+ memcpy(mem->name, f2, m);
+ mem->name[m] = 0;
+ mem->num = atoi(f1);
+ m = n-(f4-f1);
+ if(m > 0){
+ mem->glist = (char*)malloc(m+1);
+ if(mem->glist) {
+ memcpy(mem->glist, f4, m);
+ mem->glist[m] = 0;
+ }
+ } else
+ mem->glist = 0;
+ /* prepare for following move-to-front */
+ if(nmemo == MEMOMAX) {
+ free(memo[nmemo-1]);
+ i = nmemo-1;
+ } else {
+ i = nmemo++;
+ }
+ }
+ }
+ if(matched) {
+ if(matchnum)
+ *pname = mem->name;
+ else
+ *pnum = mem->num;
+ if(plist)
+ *plist = mem->glist;
+ if(i > 0) {
+ /* make room at front */
+ for(j = i; j > 0; j--)
+ memo[j] = memo[j-1];
+ }
+ memo[0] = mem;
+ return 1;
+ }
+ return 0;
+}
+
+char **
+_grpmems(char *list)
+{
+ char **v;
+ char *p;
+ static char *holdvec[200];
+ static char holdlist[1000];
+
+ p = list;
+ v = holdvec;
+ if(p) {
+ strncpy(holdlist, list, sizeof(holdlist));
+ while(v< &holdvec[sizeof(holdvec)]-1 && *p){
+ *v++ = p;
+ p = strchr(p, ',');
+ if(p){
+ p++;
+ *p = 0;
+ }else
+ break;
+ }
+ }
+ *v = 0;
+ return holdvec;
+}
diff --git a/sys/src/ape/lib/ap/plan9/_nap.c b/sys/src/ape/lib/ap/plan9/_nap.c
new file mode 100755
index 000000000..d21eff79c
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/_nap.c
@@ -0,0 +1,20 @@
+#include "lib.h"
+#include <unistd.h>
+#include <time.h>
+#include "sys9.h"
+
+/*
+ * This is an extension to POSIX
+ */
+unsigned int
+_nap(unsigned int millisecs)
+{
+ time_t t0, t1;
+
+ t0 = time(0);
+ if(_SLEEP(millisecs) < 0){
+ t1 = time(0);
+ return t1-t0;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/access.c b/sys/src/ape/lib/ap/plan9/access.c
new file mode 100755
index 000000000..c51b37d6c
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/access.c
@@ -0,0 +1,62 @@
+#include "lib.h"
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+int
+access(const char *name, int mode)
+{
+ int fd, n;
+ Dir *db;
+ struct stat st;
+ static char omode[] = {
+ 0,
+ 3,
+ 1,
+ 2,
+ 0,
+ 2,
+ 2,
+ 2
+ };
+ char tname[1024];
+
+ if(mode == 0){
+ db = _dirstat(name);
+ if(db == nil){
+ _syserrno();
+ return -1;
+ }
+ free(db);
+ return 0;
+ }
+ fd = open(name, omode[mode&7]);
+ if(fd >= 0){
+ close(fd);
+ return 0;
+ }
+ else if(stat(name, &st)==0 && S_ISDIR(st.st_mode)){
+ if(mode & (R_OK|X_OK)){
+ fd = open(name, O_RDONLY);
+ if(fd < 0)
+ return -1;
+ close(fd);
+ }
+ if(mode & W_OK){
+ strncpy(tname, name, sizeof(tname)-9);
+ strcat(tname, "/_AcChAcK");
+ fd = creat(tname, 0666);
+ if(fd < 0)
+ return -1;
+ close(fd);
+ _REMOVE(tname);
+ }
+ return 0;
+ }
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/acid.c b/sys/src/ape/lib/ap/plan9/acid.c
new file mode 100755
index 000000000..5109a215e
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/acid.c
@@ -0,0 +1,31 @@
+/* include struct defs to get acid library
+ cpp -I/sys/include/ape -I/$objtype/include/ape -I./include acid.c > t.c
+ vc -a t.c > acidlib
+*/
+#define _POSIX_SOURCE 1
+#define _BSD_EXTENSION 1
+#define _LOCK_EXTENSION
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <lock.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <math.h>
+#include <float.h>
+#include <sys/utsname.h>
+/* #include "lib.h" buf.c below */
+/* #include "sys9.h" buf.c below */
+#include "_buf.c"
+#include "dir.h"
+#include "fcall.h"
diff --git a/sys/src/ape/lib/ap/plan9/acidlib b/sys/src/ape/lib/ap/plan9/acidlib
new file mode 100755
index 000000000..a4f14503f
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/acidlib
@@ -0,0 +1,706 @@
+sizeof_1_ = 8;
+aggr _1_
+{
+ 'D' 0 quot;
+ 'D' 4 rem;
+};
+
+defn
+_1_(addr) {
+ complex _1_ addr;
+ print(" quot ", addr.quot, "\n");
+ print(" rem ", addr.rem, "\n");
+};
+
+sizeof_2_ = 8;
+aggr _2_
+{
+ 'D' 0 quot;
+ 'D' 4 rem;
+};
+
+defn
+_2_(addr) {
+ complex _2_ addr;
+ print(" quot ", addr.quot, "\n");
+ print(" rem ", addr.rem, "\n");
+};
+
+sizeofsigaction = 12;
+aggr sigaction
+{
+ 'X' 0 sa_handler;
+ 'D' 4 sa_mask;
+ 'D' 8 sa_flags;
+};
+
+defn
+sigaction(addr) {
+ complex sigaction addr;
+ print(" sa_handler ", addr.sa_handler\X, "\n");
+ print(" sa_mask ", addr.sa_mask, "\n");
+ print(" sa_flags ", addr.sa_flags, "\n");
+};
+
+sizeof_3_ = 32;
+aggr _3_
+{
+ 'D' 0 fd;
+ 'C' 4 flags;
+ 'C' 5 state;
+ 'X' 8 buf;
+ 'X' 12 rp;
+ 'X' 16 wp;
+ 'X' 20 lp;
+ 'U' 24 bufl;
+ 'a' 28 unbuf;
+};
+
+defn
+_3_(addr) {
+ complex _3_ addr;
+ print(" fd ", addr.fd, "\n");
+ print(" flags ", addr.flags, "\n");
+ print(" state ", addr.state, "\n");
+ print(" buf ", addr.buf\X, "\n");
+ print(" rp ", addr.rp\X, "\n");
+ print(" wp ", addr.wp\X, "\n");
+ print(" lp ", addr.lp\X, "\n");
+ print(" bufl ", addr.bufl, "\n");
+ print(" unbuf ", addr.unbuf, "\n");
+};
+
+sizeof_4_ = 4;
+aggr _4_
+{
+ 'D' 0 val;
+};
+
+defn
+_4_(addr) {
+ complex _4_ addr;
+ print(" val ", addr.val, "\n");
+};
+
+sizeoftimeval = 8;
+aggr timeval
+{
+ 'D' 0 tv_sec;
+ 'D' 4 tv_usec;
+};
+
+defn
+timeval(addr) {
+ complex timeval addr;
+ print(" tv_sec ", addr.tv_sec, "\n");
+ print(" tv_usec ", addr.tv_usec, "\n");
+};
+
+sizeoftimezone = 8;
+aggr timezone
+{
+ 'D' 0 tz_minuteswest;
+ 'D' 4 tz_dsttime;
+};
+
+defn
+timezone(addr) {
+ complex timezone addr;
+ print(" tz_minuteswest ", addr.tz_minuteswest, "\n");
+ print(" tz_dsttime ", addr.tz_dsttime, "\n");
+};
+
+sizeoffd_set = 12;
+aggr fd_set
+{
+ 'a' 0 fds_bits;
+};
+
+defn
+fd_set(addr) {
+ complex fd_set addr;
+ mem(addr, "3X");
+};
+
+sizeofstat = 28;
+aggr stat
+{
+ 'u' 0 st_dev;
+ 'u' 2 st_ino;
+ 'u' 4 st_mode;
+ 'd' 6 st_nlink;
+ 'd' 8 st_uid;
+ 'd' 10 st_gid;
+ 'D' 12 st_size;
+ 'D' 16 st_atime;
+ 'D' 20 st_mtime;
+ 'D' 24 st_ctime;
+};
+
+defn
+stat(addr) {
+ complex stat addr;
+ print(" st_dev ", addr.st_dev, "\n");
+ print(" st_ino ", addr.st_ino, "\n");
+ print(" st_mode ", addr.st_mode, "\n");
+ print(" st_nlink ", addr.st_nlink, "\n");
+ print(" st_uid ", addr.st_uid, "\n");
+ print(" st_gid ", addr.st_gid, "\n");
+ print(" st_size ", addr.st_size, "\n");
+ print(" st_atime ", addr.st_atime, "\n");
+ print(" st_mtime ", addr.st_mtime, "\n");
+ print(" st_ctime ", addr.st_ctime, "\n");
+};
+
+sizeofflock = 16;
+aggr flock
+{
+ 'd' 0 l_type;
+ 'd' 2 l_whence;
+ 'D' 4 l_start;
+ 'D' 8 l_len;
+ 'D' 12 l_pid;
+};
+
+defn
+flock(addr) {
+ complex flock addr;
+ print(" l_type ", addr.l_type, "\n");
+ print(" l_whence ", addr.l_whence, "\n");
+ print(" l_start ", addr.l_start, "\n");
+ print(" l_len ", addr.l_len, "\n");
+ print(" l_pid ", addr.l_pid, "\n");
+};
+
+sizeofdirent = 28;
+aggr dirent
+{
+ 'a' 0 d_name;
+};
+
+defn
+dirent(addr) {
+ complex dirent addr;
+ print(" d_name ", addr.d_name, "\n");
+};
+
+sizeof_dirdesc = 16;
+aggr _dirdesc
+{
+ 'D' 0 dd_fd;
+ 'D' 4 dd_loc;
+ 'D' 8 dd_size;
+ 'X' 12 dd_buf;
+};
+
+defn
+_dirdesc(addr) {
+ complex _dirdesc addr;
+ print(" dd_fd ", addr.dd_fd, "\n");
+ print(" dd_loc ", addr.dd_loc, "\n");
+ print(" dd_size ", addr.dd_size, "\n");
+ print(" dd_buf ", addr.dd_buf\X, "\n");
+};
+
+sizeoftermios = 28;
+aggr termios
+{
+ 'U' 0 c_iflag;
+ 'U' 4 c_oflag;
+ 'U' 8 c_cflag;
+ 'U' 12 c_lflag;
+ 'a' 16 c_cc;
+};
+
+defn
+termios(addr) {
+ complex termios addr;
+ print(" c_iflag ", addr.c_iflag, "\n");
+ print(" c_oflag ", addr.c_oflag, "\n");
+ print(" c_cflag ", addr.c_cflag, "\n");
+ print(" c_lflag ", addr.c_lflag, "\n");
+ print(" c_cc ", addr.c_cc, "\n");
+};
+
+sizeofutsname = 20;
+aggr utsname
+{
+ 'X' 0 sysname;
+ 'X' 4 nodename;
+ 'X' 8 release;
+ 'X' 12 version;
+ 'X' 16 machine;
+};
+
+defn
+utsname(addr) {
+ complex utsname addr;
+ print(" sysname ", addr.sysname\X, "\n");
+ print(" nodename ", addr.nodename\X, "\n");
+ print(" release ", addr.release\X, "\n");
+ print(" version ", addr.version\X, "\n");
+ print(" machine ", addr.machine\X, "\n");
+};
+
+sizeofMuxbuf = 16400;
+aggr Muxbuf
+{
+ 'D' 0 n;
+ 'X' 4 putnext;
+ 'X' 8 getnext;
+ 'b' 12 fd;
+ 'b' 13 eof;
+ 'b' 14 roomwait;
+ 'b' 15 datawait;
+ 'a' 16 data;
+};
+
+defn
+Muxbuf(addr) {
+ complex Muxbuf addr;
+ print(" n ", addr.n, "\n");
+ print(" putnext ", addr.putnext\X, "\n");
+ print(" getnext ", addr.getnext\X, "\n");
+ print(" fd ", addr.fd, "\n");
+ print(" eof ", addr.eof, "\n");
+ print(" roomwait ", addr.roomwait, "\n");
+ print(" datawait ", addr.datawait, "\n");
+ print(" data ", addr.data, "\n");
+};
+
+sizeofFdinfo = 16;
+aggr Fdinfo
+{
+ 'U' 0 flags;
+ 'U' 4 oflags;
+ 'X' 8 name;
+ 'A' Muxbuf 12 buf;
+};
+
+defn
+Fdinfo(addr) {
+ complex Fdinfo addr;
+ print(" flags ", addr.flags, "\n");
+ print(" oflags ", addr.oflags, "\n");
+ print(" name ", addr.name\X, "\n");
+ print(" buf ", addr.buf\X, "\n");
+};
+
+sizeofWaitmsg = 112;
+aggr Waitmsg
+{
+ 'a' 0 pid;
+ 'a' 12 time;
+ 'a' 48 msg;
+};
+
+defn
+Waitmsg(addr) {
+ complex Waitmsg addr;
+ print(" pid ", addr.pid, "\n");
+ print(" time ", addr.time, "\n");
+ print(" msg ", addr.msg, "\n");
+};
+
+sizeof_5_ = 8;
+aggr _5_
+{
+ 'D' 0 hlength;
+ 'D' 4 length;
+};
+
+defn
+_5_(addr) {
+ complex _5_ addr;
+ print(" hlength ", addr.hlength, "\n");
+ print(" length ", addr.length, "\n");
+};
+
+sizeof_6_ = 8;
+aggr _6_
+{
+ 'a' 0 clength;
+ 'D' 0 vlength;
+ {
+ 'D' 0 hlength;
+ 'D' 4 length;
+ };
+};
+
+defn
+_6_(addr) {
+ complex _6_ addr;
+ print(" clength ", addr.clength, "\n");
+ print(" vlength ", addr.vlength, "\n");
+ print("_5_ {\n");
+ _5_(addr+0);
+ print("}\n");
+};
+
+sizeofQid = 8;
+aggr Qid
+{
+ 'U' 0 path;
+ 'U' 4 vers;
+};
+
+defn
+Qid(addr) {
+ complex Qid addr;
+ print(" path ", addr.path, "\n");
+ print(" vers ", addr.vers, "\n");
+};
+
+sizeofDir = 116;
+aggr Dir
+{
+ 'a' 0 name;
+ 'a' 28 uid;
+ 'a' 56 gid;
+ Qid 84 qid;
+ 'U' 92 mode;
+ 'D' 96 atime;
+ 'D' 100 mtime;
+ {
+ 'a' 104 clength;
+ 'D' 104 vlength;
+ {
+ 'D' 104 hlength;
+ 'D' 108 length;
+ };
+ };
+ 'd' 112 type;
+ 'd' 114 dev;
+};
+
+defn
+Dir(addr) {
+ complex Dir addr;
+ print(" name ", addr.name, "\n");
+ print(" uid ", addr.uid, "\n");
+ print(" gid ", addr.gid, "\n");
+ print("Qid qid {\n");
+ Qid(addr.qid);
+ print("}\n");
+ print(" mode ", addr.mode, "\n");
+ print(" atime ", addr.atime, "\n");
+ print(" mtime ", addr.mtime, "\n");
+ print("_6_ {\n");
+ _6_(addr+104);
+ print("}\n");
+ print(" type ", addr.type, "\n");
+ print(" dev ", addr.dev, "\n");
+};
+
+sizeof_7_ = 28;
+aggr _7_
+{
+ 'u' 0 oldtag;
+ Qid 4 qid;
+ 'a' 12 rauth;
+};
+
+defn
+_7_(addr) {
+ complex _7_ addr;
+ print(" oldtag ", addr.oldtag, "\n");
+ print("Qid qid {\n");
+ Qid(addr.qid);
+ print("}\n");
+ print(" rauth ", addr.rauth, "\n");
+};
+
+sizeof_8_ = 144;
+aggr _8_
+{
+ 'a' 0 uname;
+ 'a' 28 aname;
+ 'a' 56 ticket;
+ 'a' 128 auth;
+};
+
+defn
+_8_(addr) {
+ complex _8_ addr;
+ print(" uname ", addr.uname, "\n");
+ print(" aname ", addr.aname, "\n");
+ print(" ticket ", addr.ticket, "\n");
+ print(" auth ", addr.auth, "\n");
+};
+
+sizeof_9_ = 148;
+aggr _9_
+{
+ 'a' 0 ename;
+ 'a' 64 authid;
+ 'a' 92 authdom;
+ 'a' 140 chal;
+};
+
+defn
+_9_(addr) {
+ complex _9_ addr;
+ print(" ename ", addr.ename, "\n");
+ print(" authid ", addr.authid, "\n");
+ print(" authdom ", addr.authdom, "\n");
+ print(" chal ", addr.chal, "\n");
+};
+
+sizeof_10_ = 36;
+aggr _10_
+{
+ 'D' 0 perm;
+ 'd' 4 newfid;
+ 'a' 6 name;
+ 'C' 34 mode;
+};
+
+defn
+_10_(addr) {
+ complex _10_ addr;
+ print(" perm ", addr.perm, "\n");
+ print(" newfid ", addr.newfid, "\n");
+ print(" name ", addr.name, "\n");
+ print(" mode ", addr.mode, "\n");
+};
+
+sizeof_11_ = 12;
+aggr _11_
+{
+ 'D' 0 offset;
+ 'D' 4 count;
+ 'X' 8 data;
+};
+
+defn
+_11_(addr) {
+ complex _11_ addr;
+ print(" offset ", addr.offset, "\n");
+ print(" count ", addr.count, "\n");
+ print(" data ", addr.data\X, "\n");
+};
+
+sizeof_12_ = 116;
+aggr _12_
+{
+ 'a' 0 stat;
+};
+
+defn
+_12_(addr) {
+ complex _12_ addr;
+ print(" stat ", addr.stat, "\n");
+};
+
+sizeof_13_ = 148;
+aggr _13_
+{
+ {
+ 'u' 0 oldtag;
+ Qid 4 qid;
+ 'a' 12 rauth;
+ };
+ {
+ 'a' 0 uname;
+ 'a' 28 aname;
+ 'a' 56 ticket;
+ 'a' 128 auth;
+ };
+ {
+ 'a' 0 ename;
+ 'a' 64 authid;
+ 'a' 92 authdom;
+ 'a' 140 chal;
+ };
+ {
+ 'D' 0 perm;
+ 'd' 4 newfid;
+ 'a' 6 name;
+ 'C' 34 mode;
+ };
+ {
+ 'D' 0 offset;
+ 'D' 4 count;
+ 'X' 8 data;
+ };
+ {
+ 'a' 0 stat;
+ };
+};
+
+defn
+_13_(addr) {
+ complex _13_ addr;
+ print("_7_ {\n");
+ _7_(addr+0);
+ print("}\n");
+ print("_8_ {\n");
+ _8_(addr+0);
+ print("}\n");
+ print("_9_ {\n");
+ _9_(addr+0);
+ print("}\n");
+ print("_10_ {\n");
+ _10_(addr+0);
+ print("}\n");
+ print("_11_ {\n");
+ _11_(addr+0);
+ print("}\n");
+ print("_12_ {\n");
+ _12_(addr+0);
+ print("}\n");
+};
+
+sizeofFcall = 156;
+aggr Fcall
+{
+ 'C' 0 type;
+ 'd' 2 fid;
+ 'u' 4 tag;
+ {
+ {
+ 'u' 8 oldtag;
+ Qid 12 qid;
+ 'a' 20 rauth;
+ };
+ {
+ 'a' 8 uname;
+ 'a' 36 aname;
+ 'a' 64 ticket;
+ 'a' 136 auth;
+ };
+ {
+ 'a' 8 ename;
+ 'a' 72 authid;
+ 'a' 100 authdom;
+ 'a' 148 chal;
+ };
+ {
+ 'D' 8 perm;
+ 'd' 12 newfid;
+ 'a' 14 name;
+ 'C' 42 mode;
+ };
+ {
+ 'D' 8 offset;
+ 'D' 12 count;
+ 'X' 16 data;
+ };
+ {
+ 'a' 8 stat;
+ };
+ };
+};
+
+defn
+Fcall(addr) {
+ complex Fcall addr;
+ print(" type ", addr.type, "\n");
+ print(" fid ", addr.fid, "\n");
+ print(" tag ", addr.tag, "\n");
+ print("_13_ {\n");
+ _13_(addr+8);
+ print("}\n");
+};
+
+sizeofMuxbuf = 16400;
+aggr Muxbuf
+{
+ 'D' 0 n;
+ 'X' 4 putnext;
+ 'X' 8 getnext;
+ 'b' 12 fd;
+ 'b' 13 eof;
+ 'b' 14 roomwait;
+ 'b' 15 datawait;
+ 'a' 16 data;
+};
+
+defn
+Muxbuf(addr) {
+ complex Muxbuf addr;
+ print(" n ", addr.n, "\n");
+ print(" putnext ", addr.putnext\X, "\n");
+ print(" getnext ", addr.getnext\X, "\n");
+ print(" fd ", addr.fd, "\n");
+ print(" eof ", addr.eof, "\n");
+ print(" roomwait ", addr.roomwait, "\n");
+ print(" datawait ", addr.datawait, "\n");
+ print(" data ", addr.data, "\n");
+};
+
+sizeofFdinfo = 16;
+aggr Fdinfo
+{
+ 'U' 0 flags;
+ 'U' 4 oflags;
+ 'X' 8 name;
+ 'A' Muxbuf 12 buf;
+};
+
+defn
+Fdinfo(addr) {
+ complex Fdinfo addr;
+ print(" flags ", addr.flags, "\n");
+ print(" oflags ", addr.oflags, "\n");
+ print(" name ", addr.name\X, "\n");
+ print(" buf ", addr.buf\X, "\n");
+};
+
+sizeofWaitmsg = 112;
+aggr Waitmsg
+{
+ 'a' 0 pid;
+ 'a' 12 time;
+ 'a' 48 msg;
+};
+
+defn
+Waitmsg(addr) {
+ complex Waitmsg addr;
+ print(" pid ", addr.pid, "\n");
+ print(" time ", addr.time, "\n");
+ print(" msg ", addr.msg, "\n");
+};
+
+sizeofMuxseg = 65640;
+aggr Muxseg
+{
+ _4_ 0 lock;
+ 'D' 4 curfds;
+ 'D' 8 selwait;
+ 'D' 12 waittime;
+ fd_set 16 rwant;
+ fd_set 28 ewant;
+ 'a' 40 bufs;
+};
+
+defn
+Muxseg(addr) {
+ complex Muxseg addr;
+ print("_4_ lock {\n");
+ _4_(addr.lock);
+ print("}\n");
+ print(" curfds ", addr.curfds, "\n");
+ print(" selwait ", addr.selwait, "\n");
+ print(" waittime ", addr.waittime, "\n");
+ print("fd_set rwant {\n");
+ fd_set(addr.rwant);
+ print("}\n");
+ print("fd_set ewant {\n");
+ fd_set(addr.ewant);
+ print("}\n");
+ print(" bufs ", addr.bufs, "\n");
+};
+
+complex Muxseg mux;
+complex Fdinfo _startbuf:f;
+complex Muxbuf _startbuf:b;
+complex Muxbuf _copyproc:b;
+complex Muxbuf _readbuf:b;
+complex fd_set select:rfds;
+complex fd_set select:wfds;
+complex fd_set select:efds;
+complex timeval select:timeout;
+complex Fdinfo select:f;
+complex Muxbuf select:b;
diff --git a/sys/src/ape/lib/ap/plan9/alarm.c b/sys/src/ape/lib/ap/plan9/alarm.c
new file mode 100755
index 000000000..f8a24aa65
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/alarm.c
@@ -0,0 +1,9 @@
+#include "lib.h"
+#include <unistd.h>
+#include "sys9.h"
+
+unsigned int
+alarm(unsigned seconds)
+{
+ return _ALARM(seconds*1000);
+}
diff --git a/sys/src/ape/lib/ap/plan9/brk.c b/sys/src/ape/lib/ap/plan9/brk.c
new file mode 100755
index 000000000..0b3240377
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/brk.c
@@ -0,0 +1,36 @@
+#include "lib.h"
+#include <errno.h>
+#include "sys9.h"
+
+char end[];
+static char *bloc = { end };
+extern int _BRK_(void*);
+
+char *
+brk(char *p)
+{
+ unsigned long n;
+
+ n = (unsigned long)p;
+ n += 3;
+ n &= ~3;
+ if(_BRK_((void*)n) < 0){
+ errno = ENOMEM;
+ return (char *)-1;
+ }
+ bloc = (char *)n;
+ return 0;
+}
+
+void *
+sbrk(unsigned long n)
+{
+ n += 3;
+ n &= ~3;
+ if(_BRK_((void *)(bloc+n)) < 0){
+ errno = ENOMEM;
+ return (void *)-1;
+ }
+ bloc += n;
+ return (void *)(bloc-n);
+}
diff --git a/sys/src/ape/lib/ap/plan9/buf.prom b/sys/src/ape/lib/ap/plan9/buf.prom
new file mode 100755
index 000000000..e8751dadd
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/buf.prom
@@ -0,0 +1,360 @@
+#define NBUFS 2
+#define READMAX 2
+#define BUFSIZ 2*READMAX
+#define EOF 255
+#define TIMEOUT 254
+#define FILEMAXLEN 20
+
+byte n[NBUFS];
+byte ntotal[NBUFS];
+byte putnext[NBUFS];
+byte getnext[NBUFS];
+bool eof[NBUFS];
+bool roomwait[NBUFS];
+bool datawait[NBUFS];
+byte rwant;
+
+/* use one big data array to simulate 2-d array */
+#define bufstart(slot) (slot*BUFSIZ)
+#define bufend(slot) ((slot+1)*BUFSIZ)
+/* bit data[BUFSIZ*NBUFS]; */
+
+bool selwait;
+/* bool hastimeout; */
+
+#define get 0
+#define release 1
+
+chan lock = [0] of { bit };
+chan lockkill = [0] of { bit };
+chan sel = [0] of { byte };
+chan selcall = [0] of { byte };
+chan selans = [0] of { byte, byte };
+chan selkill = [0] of { bit };
+chan readcall = [0] of { byte, byte };
+chan readans = [0] of { byte };
+chan readkill = [0] of { bit };
+chan croom[NBUFS] = [0] of { bit };
+chan cdata[NBUFS] = [0] of { bit };
+
+proctype Lockrendez()
+{
+ do
+ :: lock!get -> lock?release
+ :: lockkill?release -> break
+ od
+}
+
+proctype Copy(byte fd)
+{
+ byte num;
+ bit b;
+
+ do :: 1 ->
+ /* make sure there's room */
+ lock?get;
+ if
+ :: (BUFSIZ-putnext[fd]) < READMAX ->
+ if
+ :: getnext[fd] == putnext[fd] ->
+ getnext[fd] = 0;
+ putnext[fd] = 0;
+ lock!release
+ :: getnext[fd] != putnext[fd] ->
+ roomwait[fd] = 1;
+ lock!release;
+ croom[fd]?b
+ fi
+ :: (BUFSIZ-putnext[fd]) >= READMAX ->
+ lock!release
+ fi;
+ /* simulate read into data buf at putnext */
+ if
+ :: ntotal[fd] > FILEMAXLEN ->
+ num = EOF
+ :: ntotal[fd] <= FILEMAXLEN ->
+ if
+ :: num = 1
+ :: num = READMAX
+ :: num = EOF
+ fi
+ fi;
+ /* here is where data transfer would happen */
+ lock?get;
+ if
+ :: num == EOF ->
+ eof[fd] = 1;
+/* printf("Copy %d got eof\n", fd);/**/
+ if
+ :: datawait[fd] ->
+ datawait[fd] = 0;
+ lock!release;
+ cdata[fd]!1
+ :: !datawait[fd] && (rwant & (1<<fd)) && selwait ->
+ selwait = 0;
+ lock!release;
+ sel!fd
+ :: !datawait[fd] && !((rwant & (1<<fd)) && selwait) ->
+ lock!release
+ fi;
+ break
+ :: num != EOF ->
+/* printf("Copy %d putting %d in; old putnext=%d, old n=%d\n", fd, num, putnext[fd], n[fd]); /* */
+ putnext[fd] = putnext[fd] + num;
+ n[fd] = n[fd] + num;
+ ntotal[fd] = ntotal[fd] + num;
+ assert(n[fd] > 0);
+ if
+ :: datawait[fd] ->
+ datawait[fd] = 0;
+ lock!release;
+ cdata[fd]!1
+ :: !datawait[fd] && (rwant & (1<<fd)) && selwait ->
+ selwait = 0;
+ lock!release;
+ sel!fd
+ :: !datawait[fd] && !((rwant & (1<<fd)) && selwait) ->
+ lock!release
+ fi
+ fi;
+ od
+}
+
+proctype Read()
+{
+ byte ngot;
+ byte fd;
+ byte nwant;
+ bit b;
+
+ do
+ :: readcall?fd,nwant ->
+ if
+ :: eof[fd] && n[fd] == 0 ->
+ readans!EOF
+ :: !(eof[fd] && n[fd] == 0) ->
+ lock?get;
+ ngot = putnext[fd] - getnext[fd];
+/* printf("Reading %d, want %d: ngot = %d - %d, n = %d\n", fd, nwant, putnext[fd], getnext[fd], n[fd]); /* */
+ if
+ :: ngot == 0 ->
+ if
+ :: eof[fd] ->
+ skip
+ :: !eof[fd] ->
+ /* sleep until there's data */
+ datawait[fd] = 1;
+/* printf("Read sleeping\n"); /* */
+ lock!release;
+ cdata[fd]?b;
+ lock?get;
+ ngot = putnext[fd] - getnext[fd];
+/* printf("Read awoke, ngot = %d\n", ngot); /**/
+ fi
+ :: ngot != 0 -> skip
+ fi;
+ if
+ :: ngot > nwant -> ngot = nwant
+ :: ngot <= nwant -> skip
+ fi;
+ /* here would take ngot elements from data, from getnext[fd] ... */
+ getnext[fd] = getnext[fd] + ngot;
+ assert(n[fd] >= ngot);
+ n[fd] = n[fd] - ngot;
+ if
+ :: ngot == 0 ->
+ assert(eof[fd]);
+ ngot = EOF
+ :: ngot != 0 -> skip
+ fi;
+ if
+ :: getnext[fd] == putnext[fd] && roomwait[fd] ->
+ getnext[fd] = 0;
+ putnext[fd] = 0;
+ roomwait[fd] = 0;
+ lock!release;
+ croom[fd]!0
+ :: getnext[fd] != putnext[fd] || !roomwait[fd] ->
+ lock!release
+ fi;
+ readans!ngot
+ fi
+ :: readkill?b -> break
+ od
+}
+
+proctype Select()
+{
+ byte num;
+ byte i;
+ byte fd;
+ byte r;
+ bit b;
+
+ do
+ :: selcall?r ->
+/* printf("Select called, r=%d\n", r); /**/
+ i = 0;
+ do
+ :: i < NBUFS ->
+ if
+ :: r & (1<<i) ->
+ if
+ :: eof[i] && n[i] == 0 ->
+/* printf("Select got eof on %d\n", i);/**/
+ num = EOF;
+ r = i;
+ goto donesel
+ :: !eof[i] || n[i] != 0 -> skip
+ fi
+ :: !(r & (1<<i)) -> skip
+ fi;
+ i = i+1
+ :: i >= NBUFS -> break
+ od;
+ num = 0;
+ lock?get;
+ rwant = 0;
+ i = 0;
+ do
+ :: i < NBUFS ->
+ if
+ :: r & (1<<i) ->
+ if
+ :: n[i] > 0 || eof[i] ->
+/* printf("Select found %d has n==%d\n", i, n[i]); /**/
+ num = num+1
+ :: n[i] == 0 && !eof[i] ->
+/* printf("Select asks to wait for %d\n", i); /**/
+ r = r &(~(1<<i));
+ rwant = rwant | (1<<i)
+ fi
+ :: !(r & (1<<i)) -> skip
+ fi;
+ i = i+1
+ :: i >= NBUFS -> break
+ od;
+ if
+ :: num > 0 || rwant == 0 ->
+ rwant = 0;
+ lock!release;
+ :: num == 0 && rwant != 0 ->
+ selwait = 1;
+ lock!release;
+/* printf("Select sleeps\n"); /**/
+ sel?fd;
+/* printf("Select wakes up, fd=%d\n", fd); /**/
+ if
+ :: fd != TIMEOUT ->
+ if
+ :: (rwant & (1<<fd)) && (n[fd] > 0) ->
+ r = r | (1<<fd);
+ num = 1
+ :: !(rwant & (1<<fd)) || (n[fd] == 0) ->
+ num = 0
+ fi
+ :: fd == TIMEOUT -> skip
+ fi;
+ rwant = 0
+ fi;
+ donesel:
+ selans!num,r
+ :: selkill?b -> break
+ od
+}
+
+/* This routine is written knowing NBUFS == 2 in several places */
+proctype User()
+{
+ byte ndone;
+ byte i;
+ byte rw;
+ byte num;
+ byte nwant;
+ byte fd;
+ bool goteof[NBUFS];
+
+ ndone = 0;
+ do
+ :: ndone == NBUFS -> break
+ :: ndone < NBUFS ->
+ if
+ :: 1->
+ /* maybe use Read */
+/* printf("User trying to read. Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/
+ /* randomly pick fd 0 or 1 from non-eof ones */
+ if
+ :: !goteof[0] -> fd = 0
+ :: !goteof[1] -> fd = 1
+ fi;
+ if
+ :: nwant = 1
+ :: nwant = READMAX
+ fi;
+ readcall!fd,nwant;
+ readans?num;
+ if
+ :: num == EOF ->
+ goteof[fd] = 1;
+ ndone = ndone + 1
+ :: num != EOF -> assert(num != 0)
+ fi
+ :: 1->
+/* printf("User trying to select. Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/
+ /* maybe use Select, then Read */
+ /* randomly set the "i want" bit for non-eof fds */
+ if
+ :: !goteof[0] && !goteof[1] -> rw = (1<<0) | (1<<1)
+ :: !goteof[0] -> rw = (1<<0)
+ :: !goteof[1] -> rw = (1<<1)
+ fi;
+ selcall!rw;
+ selans?i,rw;
+ if
+ :: i == EOF ->
+ goteof[rw] = 1;
+ ndone = ndone + 1
+ :: i != EOF ->
+ /* this next statement knows NBUFS == 2 ! */
+ if
+ :: rw & (1<<0) -> fd = 0
+ :: rw & (1<<1) -> fd = 1
+ :: rw == 0 -> fd = EOF
+ fi;
+ if
+ :: nwant = 1
+ :: nwant = READMAX
+ fi;
+ if
+ :: fd != EOF ->
+ readcall!fd,nwant;
+ readans?num;
+ assert(num != 0)
+ :: fd == EOF -> skip
+ fi
+ fi
+ fi
+ od;
+ lockkill!release;
+ selkill!release;
+ readkill!release
+}
+
+init
+{
+ byte i;
+
+ atomic {
+ run Lockrendez();
+ i = 0;
+ do
+ :: i < NBUFS ->
+ run Copy(i);
+ i = i+1
+ :: i >= NBUFS -> break
+ od;
+ run Select();
+ run Read();
+ run User()
+ }
+}
diff --git a/sys/src/ape/lib/ap/plan9/cfgetospeed.c b/sys/src/ape/lib/ap/plan9/cfgetospeed.c
new file mode 100755
index 000000000..cc89f4a86
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/cfgetospeed.c
@@ -0,0 +1,26 @@
+#include <termios.h>
+
+speed_t
+cfgetospeed(const struct termios *p)
+{
+ return B0;
+}
+
+int
+cfsetospeed(struct termios *p, speed_t s)
+{
+ return 0;
+}
+
+speed_t
+cfgetispeed(const struct termios *p)
+{
+ return B0;
+}
+
+int
+cfsetispeed(struct termios *p, speed_t s)
+{
+ return 0;
+}
+
diff --git a/sys/src/ape/lib/ap/plan9/chdir.c b/sys/src/ape/lib/ap/plan9/chdir.c
new file mode 100755
index 000000000..245f116d0
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/chdir.c
@@ -0,0 +1,14 @@
+#include "lib.h"
+#include <unistd.h>
+#include "sys9.h"
+
+int
+chdir(const char *f)
+{
+ int n;
+
+ n = _CHDIR(f);
+ if(n < 0)
+ _syserrno();
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/chmod.c b/sys/src/ape/lib/ap/plan9/chmod.c
new file mode 100755
index 000000000..8b6daad22
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/chmod.c
@@ -0,0 +1,33 @@
+#include "lib.h"
+#include <errno.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+int
+chmod(const char *path, mode_t mode)
+{
+ Dir d;
+
+ _nulldir(&d);
+ d.mode = mode & 0777;
+ if(_dirwstat(path, &d) < 0){
+ _syserrno();
+ return -1;
+ }
+ return 0;
+}
+
+int
+fchmod(int fd, mode_t mode)
+{
+ Dir d;
+
+ _nulldir(&d);
+ d.mode = mode & 0777;
+ if(_dirfwstat(fd, &d) < 0){
+ _syserrno();
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/chown.c b/sys/src/ape/lib/ap/plan9/chown.c
new file mode 100755
index 000000000..22b651d14
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/chown.c
@@ -0,0 +1,39 @@
+#include "lib.h"
+#include "sys9.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "dir.h"
+
+int
+chown(const char *path, uid_t owner, gid_t group)
+{
+ int num;
+ Dir d;
+
+ _nulldir(&d);
+
+ /* find owner, group */
+ d.uid = nil;
+ num = owner;
+ if(!_getpw(&num, &d.uid, 0)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ d.gid = nil;
+ num = group;
+ if(!_getpw(&num, &d.gid, 0)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(_dirwstat(path, &d) < 0){
+ _syserrno();
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/close.c b/sys/src/ape/lib/ap/plan9/close.c
new file mode 100755
index 000000000..258788a39
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/close.c
@@ -0,0 +1,34 @@
+#include "lib.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "sys9.h"
+
+int
+close(int d)
+{
+ int n;
+ Fdinfo *f;
+
+ n = -1;
+ f = &_fdinfo[d];
+ if(d<0 || d>=OPEN_MAX || !(f->flags&FD_ISOPEN))
+ errno = EBADF;
+ else{
+ if(f->flags&(FD_BUFFERED|FD_BUFFEREDX)) {
+ if(f->flags&FD_BUFFERED)
+ _closebuf(d);
+ f->flags &= ~FD_BUFFERED;
+ }
+ n = _CLOSE(d);
+ if(n < 0)
+ _syserrno();
+ _fdinfo[d].flags = 0;
+ _fdinfo[d].oflags = 0;
+ if(_fdinfo[d].name){
+ free(_fdinfo[d].name);
+ _fdinfo[d].name = 0;
+ }
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/convD2M.c b/sys/src/ape/lib/ap/plan9/convD2M.c
new file mode 100755
index 000000000..fc1ade5c5
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/convD2M.c
@@ -0,0 +1,93 @@
+#include "lib.h"
+#include <string.h>
+#include "sys9.h"
+#include "dir.h"
+
+uint
+_convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns, nsv[4], ss;
+
+ if(nbuf < BIT16SZ)
+ return 0;
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++){
+ nsv[i] = strlen(sv[i]);
+ ns += nsv[i];
+ }
+
+ ss = STATFIXLEN + ns;
+
+ /* set size befor erroring, so user can know how much is needed */
+ /* note that length excludes count field itself */
+ PBIT16(p, ss-BIT16SZ);
+ p += BIT16SZ;
+
+ if(ss > nbuf)
+ return BIT16SZ;
+
+ PBIT16(p, d->type);
+ p += BIT16SZ;
+ PBIT32(p, d->dev);
+ p += BIT32SZ;
+ PBIT8(p, d->qid.type);
+ p += BIT8SZ;
+ PBIT32(p, d->qid.vers);
+ p += BIT32SZ;
+ PBIT64(p, d->qid.path);
+ p += BIT64SZ;
+ PBIT32(p, d->mode);
+ p += BIT32SZ;
+ PBIT32(p, d->atime);
+ p += BIT32SZ;
+ PBIT32(p, d->mtime);
+ p += BIT32SZ;
+ PBIT64(p, d->length);
+ p += BIT64SZ;
+
+ for(i = 0; i < 4; i++){
+ ns = nsv[i];
+ if(p + ns + BIT16SZ > ebuf)
+ return 0;
+ PBIT16(p, ns);
+ p += BIT16SZ;
+ memmove(p, sv[i], ns);
+ p += ns;
+ }
+
+ if(ss != p - buf)
+ return 0;
+
+ return p - buf;
+}
+
+uint
+_sizeD2M(Dir *d)
+{
+ char *sv[4];
+ int i, ns;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++)
+ if(sv[i])
+ ns += strlen(sv[i]);
+
+ return STATFIXLEN + ns;
+}
+
diff --git a/sys/src/ape/lib/ap/plan9/convM2D.c b/sys/src/ape/lib/ap/plan9/convM2D.c
new file mode 100755
index 000000000..222e88927
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/convM2D.c
@@ -0,0 +1,74 @@
+#include "lib.h"
+#include <string.h>
+#include "sys9.h"
+#include "dir.h"
+#define nil ((void*)0)
+
+static char nullstring[] = "";
+
+uint
+_convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns, nsv[4];
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ p += BIT16SZ; /* ignore size */
+ d->type = GBIT16(p);
+ p += BIT16SZ;
+ d->dev = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.type = GBIT8(p);
+ p += BIT8SZ;
+ d->qid.vers = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.path = GBIT64(p);
+ p += BIT64SZ;
+ d->mode = GBIT32(p);
+ p += BIT32SZ;
+ d->atime = GBIT32(p);
+ p += BIT32SZ;
+ d->mtime = GBIT32(p);
+ p += BIT32SZ;
+ d->length = GBIT64(p);
+ p += BIT64SZ;
+
+ d->name = nil;
+ d->uid = nil;
+ d->gid = nil;
+ d->muid = nil;
+
+ for(i = 0; i < 4; i++){
+ if(p + BIT16SZ > ebuf)
+ return 0;
+ ns = GBIT16(p);
+ p += BIT16SZ;
+ if(p + ns > ebuf)
+ return 0;
+ if(strs){
+ nsv[i] = ns;
+ sv[i] = strs;
+ memmove(strs, p, ns);
+ strs += ns;
+ *strs++ = '\0';
+ }
+ p += ns;
+ }
+
+ if(strs){
+ d->name = sv[0];
+ d->uid = sv[1];
+ d->gid = sv[2];
+ d->muid = sv[3];
+ }else{
+ d->name = nullstring;
+ d->uid = nullstring;
+ d->gid = nullstring;
+ d->muid = nullstring;
+ }
+
+ return p - buf;
+}
diff --git a/sys/src/ape/lib/ap/plan9/creat.c b/sys/src/ape/lib/ap/plan9/creat.c
new file mode 100755
index 000000000..a0f917a62
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/creat.c
@@ -0,0 +1,13 @@
+#include "lib.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int
+creat(const char *name, mode_t mode)
+{
+ int n;
+
+ n = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ /* no need to _syserrno; open did it already */
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/ctermid.c b/sys/src/ape/lib/ap/plan9/ctermid.c
new file mode 100755
index 000000000..a8689a71f
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/ctermid.c
@@ -0,0 +1,20 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+char *
+ctermid(char *s)
+{
+ static char buf[L_ctermid];
+
+ if(s == 0)
+ s = buf;
+ strncpy(s, "/dev/cons", sizeof buf);
+ return(s);
+}
+
+char *
+ctermid_r(char *s)
+{
+ return s ? ctermid(s) : NULL;
+}
diff --git a/sys/src/ape/lib/ap/plan9/ctime.c b/sys/src/ape/lib/ap/plan9/ctime.c
new file mode 100755
index 000000000..34a0b12a5
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/ctime.c
@@ -0,0 +1,321 @@
+/*
+ * This routine converts time as follows.
+ * The epoch is 0000 Jan 1 1970 GMT.
+ * The argument time is in seconds since then.
+ * The localtime(t) entry returns a pointer to an array
+ * containing
+ *
+ * seconds (0-59)
+ * minutes (0-59)
+ * hours (0-23)
+ * day of month (1-31)
+ * month (0-11)
+ * year-1970
+ * weekday (0-6, Sun is 0)
+ * day of the year
+ * daylight savings flag
+ *
+ * The routine gets the daylight savings time from the environment.
+ *
+ * asctime(tvec))
+ * where tvec is produced by localtime
+ * returns a ptr to a character string
+ * that has the ascii time in the form
+ *
+ * \\
+ * Thu Jan 01 00:00:00 1970n0
+ * 01234567890123456789012345
+ * 0 1 2
+ *
+ * ctime(t) just calls localtime, then asctime.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+static char dmsize[12] =
+{
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * The following table is used for 1974 and 1975 and
+ * gives the day number of the first day after the Sunday of the
+ * change.
+ */
+
+static int dysize(int);
+static void ct_numb(char*, int);
+static void readtimezone(void);
+static int rd_name(char**, char*);
+static int rd_long(char**, long*);
+
+#define TZSIZE 150
+
+static
+struct
+{
+ char stname[4];
+ char dlname[4];
+ long stdiff;
+ long dldiff;
+ long dlpairs[TZSIZE];
+} timezone;
+
+char*
+ctime(const time_t *t)
+{
+ return asctime(localtime(t));
+}
+
+struct tm*
+gmtime_r(const time_t *timp, struct tm *result)
+{
+ int d0, d1;
+ long hms, day;
+ time_t tim;
+
+ tim = *timp;
+ /*
+ * break initial number into days
+ */
+ hms = tim % 86400L;
+ day = tim / 86400L;
+ if(hms < 0) {
+ hms += 86400L;
+ day -= 1;
+ }
+
+ /*
+ * generate hours:minutes:seconds
+ */
+ result->tm_sec = hms % 60;
+ d1 = hms / 60;
+ result->tm_min = d1 % 60;
+ d1 /= 60;
+ result->tm_hour = d1;
+
+ /*
+ * day is the day number.
+ * generate day of the week.
+ * The addend is 4 mod 7 (1/1/1970 was Thursday)
+ */
+
+ result->tm_wday = (day + 7340036L) % 7;
+
+ /*
+ * year number
+ */
+ if(day >= 0)
+ for(d1 = 70; day >= dysize(d1); d1++)
+ day -= dysize(d1);
+ else
+ for (d1 = 70; day < 0; d1--)
+ day += dysize(d1-1);
+ result->tm_year = d1;
+ result->tm_yday = d0 = day;
+
+ /*
+ * generate month
+ */
+
+ if(dysize(d1) == 366)
+ dmsize[1] = 29;
+ for(d1 = 0; d0 >= dmsize[d1]; d1++)
+ d0 -= dmsize[d1];
+ dmsize[1] = 28;
+ result->tm_mday = d0 + 1;
+ result->tm_mon = d1;
+ result->tm_isdst = 0;
+ return result;
+}
+
+struct tm*
+gmtime(const time_t *timp)
+{
+ static struct tm xtime;
+
+ return gmtime_r(timp, &xtime);
+}
+
+struct tm*
+localtime_r(const time_t *timp, struct tm *result)
+{
+ struct tm *ct;
+ time_t t, tim;
+ long *p;
+ int i, dlflag;
+
+ tim = *timp;
+ if(timezone.stname[0] == 0)
+ readtimezone();
+ t = tim + timezone.stdiff;
+ dlflag = 0;
+ for(p = timezone.dlpairs; *p; p += 2)
+ if(t >= p[0])
+ if(t < p[1]) {
+ t = tim + timezone.dldiff;
+ dlflag++;
+ break;
+ }
+ ct = gmtime_r(&t, result);
+ ct->tm_isdst = dlflag;
+ return ct;
+}
+
+struct tm*
+localtime(const time_t *timp)
+{
+ static struct tm xtime;
+
+ return localtime_r(timp, &xtime);
+}
+
+char*
+asctime_r(const struct tm *t, char *buf)
+{
+ char *ncp;
+
+ strcpy(buf, "Thu Jan 01 00:00:00 1970\n");
+ ncp = &"SunMonTueWedThuFriSat"[t->tm_wday*3];
+ buf[0] = *ncp++;
+ buf[1] = *ncp++;
+ buf[2] = *ncp;
+ ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->tm_mon*3];
+ buf[4] = *ncp++;
+ buf[5] = *ncp++;
+ buf[6] = *ncp;
+ ct_numb(buf+8, t->tm_mday);
+ ct_numb(buf+11, t->tm_hour+100);
+ ct_numb(buf+14, t->tm_min+100);
+ ct_numb(buf+17, t->tm_sec+100);
+ if(t->tm_year >= 100) {
+ buf[20] = '2';
+ buf[21] = '0';
+ }
+ ct_numb(buf+22, t->tm_year+100);
+ return buf;
+}
+
+char*
+asctime(const struct tm *t)
+{
+ static char cbuf[30];
+
+ return asctime_r(t, cbuf);
+}
+
+static
+dysize(int y)
+{
+ if((y%4) == 0)
+ return 366;
+ return 365;
+}
+
+static
+void
+ct_numb(char *cp, int n)
+{
+ cp[0] = ' ';
+ if(n >= 10)
+ cp[0] = (n/10)%10 + '0';
+ cp[1] = n%10 + '0';
+}
+
+static
+void
+readtimezone(void)
+{
+ char buf[TZSIZE*11+30], *p;
+ int i;
+
+ memset(buf, 0, sizeof(buf));
+ i = open("/env/timezone", 0);
+ if(i < 0)
+ goto error;
+ if(read(i, buf, sizeof(buf)) >= sizeof(buf))
+ goto error;
+ close(i);
+ p = buf;
+ if(rd_name(&p, timezone.stname))
+ goto error;
+ if(rd_long(&p, &timezone.stdiff))
+ goto error;
+ if(rd_name(&p, timezone.dlname))
+ goto error;
+ if(rd_long(&p, &timezone.dldiff))
+ goto error;
+ for(i=0; i<TZSIZE; i++) {
+ if(rd_long(&p, &timezone.dlpairs[i]))
+ goto error;
+ if(timezone.dlpairs[i] == 0)
+ return;
+ }
+
+error:
+ timezone.stdiff = 0;
+ strcpy(timezone.stname, "GMT");
+ timezone.dlpairs[0] = 0;
+}
+
+static
+rd_name(char **f, char *p)
+{
+ int c, i;
+
+ for(;;) {
+ c = *(*f)++;
+ if(c != ' ' && c != '\n')
+ break;
+ }
+ for(i=0; i<3; i++) {
+ if(c == ' ' || c == '\n')
+ return 1;
+ *p++ = c;
+ c = *(*f)++;
+ }
+ if(c != ' ' && c != '\n')
+ return 1;
+ *p = 0;
+ return 0;
+}
+
+static
+rd_long(char **f, long *p)
+{
+ int c, s;
+ long l;
+
+ s = 0;
+ for(;;) {
+ c = *(*f)++;
+ if(c == '-') {
+ s++;
+ continue;
+ }
+ if(c != ' ' && c != '\n')
+ break;
+ }
+ if(c == 0) {
+ *p = 0;
+ return 0;
+ }
+ l = 0;
+ for(;;) {
+ if(c == ' ' || c == '\n')
+ break;
+ if(c < '0' || c > '9')
+ return 1;
+ l = l*10 + c-'0';
+ c = *(*f)++;
+ }
+ if(s)
+ l = -l;
+ *p = l;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/cuserid.c b/sys/src/ape/lib/ap/plan9/cuserid.c
new file mode 100755
index 000000000..bf78bb3d2
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/cuserid.c
@@ -0,0 +1,21 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * BUG: supposed to be for effective uid,
+ * but plan9 doesn't have that concept
+ */
+char *
+cuserid(char *s)
+{
+ char *logname;
+ static char buf[L_cuserid];
+
+ if((logname = getlogin()) == NULL)
+ return(NULL);
+ if(s == 0)
+ s = buf;
+ strncpy(s, logname, sizeof buf);
+ return(s);
+}
diff --git a/sys/src/ape/lib/ap/plan9/dir.h b/sys/src/ape/lib/ap/plan9/dir.h
new file mode 100755
index 000000000..2af4f3e96
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/dir.h
@@ -0,0 +1,80 @@
+typedef long long vlong;
+typedef unsigned long long uvlong;
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#define GBIT8(p) ((p)[0])
+#define GBIT16(p) ((p)[0]|((p)[1]<<8))
+#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))
+#define GBIT64(p) ((vlong)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\
+ ((vlong)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32))
+
+#define PBIT8(p,v) (p)[0]=(v)
+#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
+#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24
+#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\
+ (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56
+
+#define BIT8SZ 1
+#define BIT16SZ 2
+#define BIT32SZ 4
+#define BIT64SZ 8
+#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ)
+
+/* STATFIXLEN includes leading 16-bit count */
+/* The count, however, excludes itself; total size is BIT16SZ+count */
+#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */
+
+typedef union
+{
+ char clength[8];
+ vlong vlength;
+ struct
+ {
+ long hlength;
+ long length;
+ };
+} Length;
+
+typedef
+struct Qid
+{
+ uvlong path;
+ ulong vers;
+ uchar type;
+} Qid;
+
+typedef
+struct Dir {
+ /* system-modified data */
+ ushort type; /* server type */
+ uint dev; /* server subtype */
+ /* file data */
+ Qid qid; /* unique id from server */
+ ulong mode; /* permissions */
+ ulong atime; /* last read time */
+ ulong mtime; /* last write time */
+ vlong length; /* file length: see <u.h> */
+ char *name; /* last element of path */
+ char *uid; /* owner name */
+ char *gid; /* group name */
+ char *muid; /* last modifier name */
+} Dir;
+
+void _dirtostat(struct stat *, Dir*, Fdinfo*);
+uint _convM2D(uchar*, uint, Dir*, char*);
+uint _convD2M(Dir*, uchar*, uint);
+Dir *_dirstat(char*);
+int _dirwstat(char*, Dir*);
+Dir *_dirfstat(int);
+int _dirfwstat(int, Dir*);
+long _dirread(int, Dir**);
+long _dirreadall(int, Dir**);
+void _nulldir(Dir*);
+uint _sizeD2M(Dir*);
+
+#ifndef nil
+#define nil ((void*)0)
+#endif
diff --git a/sys/src/ape/lib/ap/plan9/dirread.c b/sys/src/ape/lib/ap/plan9/dirread.c
new file mode 100755
index 000000000..e03d32d77
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/dirread.c
@@ -0,0 +1,119 @@
+#include "lib.h"
+#include <string.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+static int
+statcheck(uchar *buf, uint nbuf)
+{
+ uchar *ebuf;
+ int i;
+
+ ebuf = buf + nbuf;
+
+ buf += STATFIXLEN - 4 * BIT16SZ;
+
+ for(i = 0; i < 4; i++){
+ if(buf + BIT16SZ > ebuf)
+ return -1;
+ buf += BIT16SZ + GBIT16(buf);
+ }
+
+ if(buf != ebuf)
+ return -1;
+
+ return 0;
+}
+
+static
+long
+dirpackage(uchar *buf, long ts, Dir **d)
+{
+ char *s;
+ long ss, i, n, nn, m;
+
+ if(ts == 0){
+ *d = nil;
+ return 0;
+ }
+
+ /*
+ * first find number of all stats, check they look like stats, & size all associated strings
+ */
+ ss = 0;
+ n = 0;
+ for(i = 0; i < ts; i += m){
+ m = BIT16SZ + GBIT16(&buf[i]);
+ if(statcheck(&buf[i], m) < 0)
+ break;
+ ss += m;
+ n++;
+ }
+
+ if(i != ts)
+ return -1;
+
+ *d = malloc(n * sizeof(Dir) + ss);
+ if(*d == nil)
+ return -1;
+
+ /*
+ * then convert all buffers
+ */
+ s = (char*)*d + n * sizeof(Dir);
+ nn = 0;
+ for(i = 0; i < ts; i += m){
+ m = BIT16SZ + GBIT16((uchar*)&buf[i]);
+ if(nn >= n || _convM2D(&buf[i], m, *d + nn, s) != m){
+ free(*d);
+ return -1;
+ }
+ nn++;
+ s += m;
+ }
+
+ return nn;
+}
+
+long
+_dirread(int fd, Dir **d)
+{
+ uchar *buf;
+ long ts;
+
+ buf = malloc(DIRMAX);
+ if(buf == nil)
+ return -1;
+ ts = _READ(fd, buf, DIRMAX);
+ if(ts >= 0)
+ ts = dirpackage(buf, ts, d);
+ free(buf);
+ return ts;
+}
+
+long
+_dirreadall(int fd, Dir **d)
+{
+ uchar *buf, *nbuf;
+ long n, ts;
+
+ buf = nil;
+ ts = 0;
+ for(;;){
+ nbuf = realloc(buf, ts+DIRMAX);
+ if(nbuf == nil){
+ free(buf);
+ return -1;
+ }
+ buf = nbuf;
+ n = _READ(fd, buf+ts, DIRMAX);
+ if(n <= 0)
+ break;
+ ts += n;
+ }
+ if(ts >= 0)
+ ts = dirpackage(buf, ts, d);
+ free(buf);
+ return ts;
+}
diff --git a/sys/src/ape/lib/ap/plan9/dirstat.c b/sys/src/ape/lib/ap/plan9/dirstat.c
new file mode 100755
index 000000000..f054b4f6e
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/dirstat.c
@@ -0,0 +1,107 @@
+#include "lib.h"
+#include <string.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+enum
+{
+ DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */
+};
+
+Dir*
+_dirstat(char *name)
+{
+ Dir *d;
+ uchar *buf;
+ int n, nd, i;
+
+ nd = DIRSIZE;
+ for(i=0; i<2; i++){ /* should work by the second try */
+ d = malloc(sizeof(Dir) + BIT16SZ +nd);
+ if(d == nil)
+ return nil;
+ buf = (uchar*)&d[1];
+ n = _STAT(name, buf, BIT16SZ+nd);
+ if(n < BIT16SZ){
+ free(d);
+ return nil;
+ }
+ nd = GBIT16((uchar*)buf); /* size needed to store whole stat buffer */
+ if(nd <= n){
+ _convM2D(buf, n, d, (char*)&d[1]);
+ return d;
+ }
+ /* else sizeof(Dir)+BIT16SZ+nd is plenty */
+ free(d);
+ }
+ return nil;
+}
+
+int
+_dirwstat(char *name, Dir *d)
+{
+ uchar *buf;
+ int r;
+
+ r = _sizeD2M(d);
+ buf = malloc(r);
+ if(buf == nil)
+ return -1;
+ _convD2M(d, buf, r);
+ r = _WSTAT(name, buf, r);
+ free(buf);
+ return r;
+}
+
+Dir*
+_dirfstat(int fd)
+{
+ Dir *d;
+ uchar *buf;
+ int n, nd, i;
+
+ nd = DIRSIZE;
+ for(i=0; i<2; i++){ /* should work by the second try */
+ d = malloc(sizeof(Dir) + nd);
+ if(d == nil)
+ return nil;
+ buf = (uchar*)&d[1];
+ n = _FSTAT(fd, buf, nd);
+ if(n < BIT16SZ){
+ free(d);
+ return nil;
+ }
+ nd = GBIT16(buf); /* size needed to store whole stat buffer */
+ if(nd <= n){
+ _convM2D(buf, n, d, (char*)&d[1]);
+ return d;
+ }
+ /* else sizeof(Dir)+nd is plenty */
+ free(d);
+ }
+ return nil;
+}
+
+int
+_dirfwstat(int fd, Dir *d)
+{
+ uchar *buf;
+ int r;
+
+ r = _sizeD2M(d);
+ buf = malloc(r);
+ if(buf == nil)
+ return -1;
+ _convD2M(d, buf, r);
+ r = _FWSTAT(fd, buf, r);
+ free(buf);
+ return r;
+}
+
+void
+_nulldir(Dir *d)
+{
+ memset(d, ~0, sizeof(Dir));
+ d->name = d->uid = d->gid = d->muid = "";
+}
diff --git a/sys/src/ape/lib/ap/plan9/dirtostat.c b/sys/src/ape/lib/ap/plan9/dirtostat.c
new file mode 100755
index 000000000..6abc6dfa7
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/dirtostat.c
@@ -0,0 +1,52 @@
+#include "lib.h"
+#include <sys/stat.h>
+#include <errno.h>
+#include "sys9.h"
+#include "dir.h"
+
+/* fi is non-null if there is an fd associated with s */
+void
+_dirtostat(struct stat *s, Dir *d, Fdinfo *fi)
+{
+ int num;
+ char *nam;
+
+ s->st_dev = (d->type<<8)|(d->dev&0xFF);
+ s->st_ino = d->qid.path;
+ s->st_mode = d->mode&0777;
+ if(fi && (fi->flags&FD_ISTTY))
+ s->st_mode |= S_IFCHR;
+ else if(d->mode & 0x80000000)
+ s->st_mode |= S_IFDIR;
+ else if(d->type == '|' || d->type == 's')
+ s->st_mode |= S_IFIFO;
+ else if(d->type != 'M')
+ s->st_mode |= S_IFCHR;
+ else
+ s->st_mode |= S_IFREG;
+ s->st_nlink = 1;
+ s->st_uid = 1;
+ s->st_gid = 1;
+ if(fi && (fi->flags&FD_BUFFERED))
+ s->st_size = fi->buf->n;
+ else
+ s->st_size = d->length;
+ s->st_atime = d->atime;
+ s->st_mtime = d->mtime;
+ s->st_ctime = d->mtime;
+ if(fi && fi->uid != -2){
+ s->st_uid = fi->uid;
+ s->st_gid = fi->gid;
+ } else {
+ nam = d->uid;
+ if(_getpw(&num, &nam, 0))
+ s->st_uid = num;
+ nam = d->gid;
+ if(_getpw(&num, &nam, 0))
+ s->st_gid = num;
+ if(fi){
+ fi->uid = s->st_uid;
+ fi->gid = s->st_gid;
+ }
+ }
+}
diff --git a/sys/src/ape/lib/ap/plan9/dup.c b/sys/src/ape/lib/ap/plan9/dup.c
new file mode 100755
index 000000000..37883be52
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/dup.c
@@ -0,0 +1,24 @@
+#include "lib.h"
+#include <unistd.h>
+#include <errno.h>
+
+int
+dup(int oldd)
+{
+ return fcntl(oldd, F_DUPFD, 0);
+}
+
+int
+dup2(int oldd, int newd)
+{
+ int n;
+
+ if(newd < 0 || newd >= OPEN_MAX){
+ errno = EBADF;
+ return -1;
+ }
+ if(oldd == newd && _fdinfo[newd].flags&FD_ISOPEN)
+ return newd;
+ close(newd);
+ return fcntl(oldd, F_DUPFD, newd);
+}
diff --git a/sys/src/ape/lib/ap/plan9/execl.c b/sys/src/ape/lib/ap/plan9/execl.c
new file mode 100755
index 000000000..79ffa44c3
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/execl.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+
+extern char **environ;
+
+int
+execl(const char *name, const char *arg0, ...)
+{
+ return execve(name, &arg0, environ);
+}
diff --git a/sys/src/ape/lib/ap/plan9/execle.c b/sys/src/ape/lib/ap/plan9/execle.c
new file mode 100755
index 000000000..f607c4914
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/execle.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+
+int
+execle(const char *name, const char *arg0, const char *aore, ...)
+{
+ char *p;
+
+ for(p=(char *)(&name)+1; *p; )
+ p++;
+ return execve(name, &arg0, (char **)p+1);
+}
diff --git a/sys/src/ape/lib/ap/plan9/execlp.c b/sys/src/ape/lib/ap/plan9/execlp.c
new file mode 100755
index 000000000..ff5d71761
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/execlp.c
@@ -0,0 +1,24 @@
+#include <unistd.h>
+#include <string.h>
+#include <sys/limits.h>
+
+/*
+ * BUG: instead of looking at PATH env variable,
+ * just try prepending /bin/ if name fails...
+ */
+
+extern char **environ;
+
+int
+execlp(const char *name, const char *arg0, ...)
+{
+ int n;
+ char buf[PATH_MAX];
+
+ if((n=execve(name, &arg0, environ)) < 0){
+ strcpy(buf, "/bin/");
+ strcpy(buf+5, name);
+ n = execve(buf, &name+1, environ);
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/execv.c b/sys/src/ape/lib/ap/plan9/execv.c
new file mode 100755
index 000000000..409e96003
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/execv.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+
+extern char **environ;
+
+int
+execv(const char *name, const char *argv[])
+{
+ return execve(name, argv, environ);
+}
diff --git a/sys/src/ape/lib/ap/plan9/execve.c b/sys/src/ape/lib/ap/plan9/execve.c
new file mode 100755
index 000000000..1d5c3c2fe
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/execve.c
@@ -0,0 +1,103 @@
+#include "lib.h"
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include "sys9.h"
+
+extern char **environ;
+
+int
+execve(const char *name, const char *argv[], const char *envp[])
+{
+ int n, f, i;
+ char **e, *ss, *se;
+ Fdinfo *fi;
+ unsigned long flags;
+ char nam[256+5];
+ char buf[1000];
+
+ _RFORK(RFCENVG);
+ /*
+ * To pass _fdinfo[] across exec, put lines like
+ * fd flags oflags
+ * in $_fdinfo (for open fd's)
+ */
+
+ f = _CREATE("#e/_fdinfo", OWRITE, 0666);
+ ss = buf;
+ for(n = 0; n<OPEN_MAX; n++){
+ fi = &_fdinfo[n];
+ flags = fi->flags;
+ if(flags&FD_CLOEXEC){
+ _CLOSE(n);
+ fi->flags = 0;
+ fi->oflags = 0;
+ }else if(flags&FD_ISOPEN){
+ ss = _ultoa(ss, n);
+ *ss++ = ' ';
+ ss = _ultoa(ss, flags);
+ *ss++ = ' ';
+ ss = _ultoa(ss, fi->oflags);
+ *ss++ = '\n';
+ if(ss-buf < sizeof(buf)-50){
+ _WRITE(f, buf, ss-buf);
+ ss = buf;
+ }
+ }
+ }
+ if(ss > buf)
+ _WRITE(f, buf, ss-buf);
+ _CLOSE(f);
+ /*
+ * To pass _sighdlr[] across exec, set $_sighdlr
+ * to list of blank separated fd's that have
+ * SIG_IGN (the rest will be SIG_DFL).
+ * We write the variable, even if no signals
+ * are ignored, in case the current value of the
+ * variable ignored some.
+ */
+ f = _CREATE("#e/_sighdlr", OWRITE, 0666);
+ if(f >= 0){
+ ss = buf;
+ for(i = 0, n=0; i <=MAXSIG && ss < &buf[sizeof(buf)]-5; i++) {
+ if(_sighdlr[i] == SIG_IGN) {
+ ss = _ultoa(ss, i);
+ *ss++ = ' ';
+ }
+ }
+ _WRITE(f, buf, ss-buf);
+ _CLOSE(f);
+ }
+ if(envp){
+ strcpy(nam, "#e/");
+ for(e = envp; (ss = *e); e++) {
+ se = strchr(ss, '=');
+ if(!se || ss==se)
+ continue; /* what is name? value? */
+ n = se-ss;
+ if(n >= sizeof(nam)-3)
+ n = sizeof(nam)-3-1;
+ memcpy(nam+3, ss, n);
+ nam[3+n] = 0;
+ f = _CREATE(nam, OWRITE, 0666);
+ if(f < 0)
+ continue;
+ se++; /* past = */
+ n = strlen(se);
+ /* temporarily decode nulls (see _envsetup()) */
+ for(i=0; i < n; i++)
+ if(se[i] == 1)
+ se[i] = 0;
+ _WRITE(f, se, n);
+ /* put nulls back */
+ for(i=0; i < n; i++)
+ if(se[i] == 0)
+ se[i] = 1;
+ _CLOSE(f);
+ }
+ }
+ n = _EXEC(name, argv);
+ _syserrno();
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/execvp.c b/sys/src/ape/lib/ap/plan9/execvp.c
new file mode 100755
index 000000000..f2ed53d1d
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/execvp.c
@@ -0,0 +1,24 @@
+#include <unistd.h>
+#include <sys/limits.h>
+#include <string.h>
+
+extern char **environ;
+
+/*
+ * BUG: instead of looking at PATH env variable,
+ * just try prepending /bin/ if name fails...
+ */
+
+int
+execvp(const char *name, const char **argv)
+{
+ int n;
+ char buf[PATH_MAX];
+
+ if((n=execve(name, argv, environ)) < 0){
+ strcpy(buf, "/bin/");
+ strcpy(buf+5, name);
+ n = execve(buf, argv, environ);
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/fcall.h b/sys/src/ape/lib/ap/plan9/fcall.h
new file mode 100755
index 000000000..8090a19a4
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/fcall.h
@@ -0,0 +1,118 @@
+typedef struct Fcall Fcall;
+
+/* see /sys/include/auth.h */
+enum
+{
+ DOMLEN= 48, /* length of an authentication domain name */
+ DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */
+ CHALLEN= 8, /* length of a challenge */
+ NETCHLEN= 16, /* max network challenge length */
+ CONFIGLEN= 14,
+
+ KEYDBLEN= NAMELEN+DESKEYLEN+4+2
+};
+#define TICKETLEN (CHALLEN+2*NAMELEN+DESKEYLEN+1)
+#define AUTHENTLEN (CHALLEN+4+1)
+
+struct Fcall
+{
+ char type;
+ short fid;
+ unsigned short tag;
+ union
+ {
+ struct
+ {
+ unsigned short oldtag; /* T-Flush */
+ Qid qid; /* R-Attach, R-Walk, R-Open, R-Create */
+ char rauth[AUTHENTLEN]; /* Rattach */
+ };
+ struct
+ {
+ char uname[NAMELEN]; /* T-Attach */
+ char aname[NAMELEN]; /* T-Attach */
+ char ticket[TICKETLEN]; /* T-Attach */
+ char auth[AUTHENTLEN];/* T-Attach */
+ };
+ struct
+ {
+ char ename[ERRLEN]; /* R-Error */
+ char authid[NAMELEN]; /* R-session */
+ char authdom[DOMLEN]; /* R-session */
+ char chal[CHALLEN]; /* T-session/R-session */
+ };
+ struct
+ {
+ long perm; /* T-Create */
+ short newfid; /* T-Clone, T-Clwalk */
+ char name[NAMELEN]; /* T-Walk, T-Clwalk, T-Create */
+ char mode; /* T-Create, T-Open */
+ };
+ struct
+ {
+ long offset; /* T-Read, T-Write */
+ long count; /* T-Read, T-Write, R-Read */
+ char *data; /* T-Write, R-Read */
+ };
+ struct
+ {
+ char stat[DIRLEN]; /* T-Wstat, R-Stat */
+ };
+ };
+};
+
+#define MAXFDATA 8192
+#define MAXMSG 160 /* max header sans data */
+#define NOTAG 0xFFFF /* Dummy tag */
+
+enum
+{
+ Tmux = 48,
+ Rmux, /* illegal */
+ Tnop = 50,
+ Rnop,
+ Tosession = 52, /* illegal */
+ Rosession, /* illegal */
+ Terror = 54, /* illegal */
+ Rerror,
+ Tflush = 56,
+ Rflush,
+ Toattach = 58, /* illegal */
+ Roattach, /* illegal */
+ Tclone = 60,
+ Rclone,
+ Twalk = 62,
+ Rwalk,
+ Topen = 64,
+ Ropen,
+ Tcreate = 66,
+ Rcreate,
+ Tread = 68,
+ Rread,
+ Twrite = 70,
+ Rwrite,
+ Tclunk = 72,
+ Rclunk,
+ Tremove = 74,
+ Rremove,
+ Tstat = 76,
+ Rstat,
+ Twstat = 78,
+ Rwstat,
+ Tclwalk = 80,
+ Rclwalk,
+ Tauth = 82, /* illegal */
+ Rauth, /* illegal */
+ Tsession = 84,
+ Rsession,
+ Tattach = 86,
+ Rattach,
+};
+
+int convM2S(char*, Fcall*, int);
+int convS2M(Fcall*, char*);
+
+int convM2D(char*, Dir*);
+int convD2M(Dir*, char*);
+
+char* getS(int, char*, Fcall*, long*);
diff --git a/sys/src/ape/lib/ap/plan9/fcntl.c b/sys/src/ape/lib/ap/plan9/fcntl.c
new file mode 100755
index 000000000..053e38ec3
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/fcntl.c
@@ -0,0 +1,81 @@
+#include "lib.h"
+#include <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "sys9.h"
+
+/*
+ * BUG: advisory locking not implemented
+ */
+
+#define OFL (O_ACCMODE|O_NONBLOCK|O_APPEND)
+
+int
+fcntl(int fd, int cmd, ...)
+{
+ int arg, i, ans, err;
+ Fdinfo *fi, *fans;
+ va_list va;
+ unsigned long oflags;
+
+ err = 0;
+ ans = 0;
+ va_start(va, cmd);
+ arg = va_arg(va, int);
+ va_end(va);
+ fi = &_fdinfo[fd];
+ if(fd<0 || fd>=OPEN_MAX || !(fi->flags&FD_ISOPEN))
+ err = EBADF;
+ else switch(cmd){
+ case F_DUPFD:
+ if(fi->flags&(FD_BUFFERED|FD_BUFFEREDX)){
+ err = EGREG; /* dup of buffered fd not implemented */
+ break;
+ }
+ oflags = fi->oflags;
+ for(i = (arg>0)? arg : 0; i<OPEN_MAX; i++)
+ if(!(_fdinfo[i].flags&FD_ISOPEN))
+ break;
+ if(i == OPEN_MAX)
+ err = EMFILE;
+ else {
+ ans = _DUP(fd, i);
+ if(ans != i){
+ if(ans < 0){
+ _syserrno();
+ err = errno;
+ }else
+ err = EBADF;
+ }else{
+ fans = &_fdinfo[ans];
+ fans->flags = fi->flags&~FD_CLOEXEC;
+ fans->oflags = oflags;
+ fans->uid = fi->uid;
+ fans->gid = fi->gid;
+ }
+ }
+ break;
+ case F_GETFD:
+ ans = fi->flags&FD_CLOEXEC;
+ break;
+ case F_SETFD:
+ fi->flags = (fi->flags&~FD_CLOEXEC)|(arg&FD_CLOEXEC);
+ break;
+ case F_GETFL:
+ ans = fi->oflags&OFL;
+ break;
+ case F_SETFL:
+ fi->oflags = (fi->oflags&~OFL)|(arg&OFL);
+ break;
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+ err = EINVAL;
+ break;
+ }
+ if(err){
+ errno = err;
+ ans = -1;
+ }
+ return ans;
+}
diff --git a/sys/src/ape/lib/ap/plan9/fork.c b/sys/src/ape/lib/ap/plan9/fork.c
new file mode 100755
index 000000000..8137bc688
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/fork.c
@@ -0,0 +1,19 @@
+#include "lib.h"
+#include <errno.h>
+#include <unistd.h>
+#include "sys9.h"
+
+pid_t
+fork(void)
+{
+ int n;
+
+ n = _RFORK(RFENVG|RFFDG|RFPROC);
+ if(n < 0)
+ _syserrno();
+ if(n == 0) {
+ _detachbuf();
+ _sessleader = 0;
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/frexp.c b/sys/src/ape/lib/ap/plan9/frexp.c
new file mode 100755
index 000000000..588f90cee
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/frexp.c
@@ -0,0 +1,89 @@
+#include <math.h>
+#include <errno.h>
+#define _RESEARCH_SOURCE
+#include <float.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+#ifdef IEEE_8087
+ long ls;
+ long ms;
+#else
+ long ms;
+ long ls;
+#endif
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0;
+ if(e >= MASK){
+ errno = ERANGE;
+ if(d < 0)
+ return -HUGE_VAL;
+ return HUGE_VAL;
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ double f;
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ f = modf(-d, ip);
+ *ip = -*ip;
+ return -f;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/sys/src/ape/lib/ap/plan9/fstat.c b/sys/src/ape/lib/ap/plan9/fstat.c
new file mode 100755
index 000000000..62e6c653a
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/fstat.c
@@ -0,0 +1,20 @@
+#include "lib.h"
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+int
+fstat(int fd, struct stat *buf)
+{
+ Dir *d;
+
+ if((d = _dirfstat(fd)) == nil){
+ _syserrno();
+ return -1;
+ }
+ _dirtostat(buf, d, &_fdinfo[fd]);
+ free(d);
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/fsync.c b/sys/src/ape/lib/ap/plan9/fsync.c
new file mode 100755
index 000000000..f37d35c04
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/fsync.c
@@ -0,0 +1,10 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+int
+fsync(int fd)
+{
+ errno = EINVAL;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/ftruncate.c b/sys/src/ape/lib/ap/plan9/ftruncate.c
new file mode 100755
index 000000000..aa867488c
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/ftruncate.c
@@ -0,0 +1,23 @@
+#include "lib.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include "dir.h"
+
+int
+ftruncate(int fd, off_t length)
+{
+ Dir d;
+
+ if(length < 0){
+ errno = EINVAL;
+ return -1;
+ }
+ _nulldir(&d);
+ d.length = length;
+ if(_dirfwstat(fd, &d) < 0){
+ _syserrno();
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getcwd.c b/sys/src/ape/lib/ap/plan9/getcwd.c
new file mode 100755
index 000000000..db6936b56
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getcwd.c
@@ -0,0 +1,32 @@
+#include "lib.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include "sys9.h"
+#include "dir.h"
+
+char*
+getcwd(char *buf, size_t len)
+{
+ int fd;
+
+ fd = _OPEN(".", OREAD);
+ if(fd < 0) {
+ errno = EACCES;
+ return 0;
+ }
+ if(_FD2PATH(fd, buf, len) < 0) {
+ errno = EIO;
+ _CLOSE(fd);
+ return 0;
+ }
+ _CLOSE(fd);
+
+/* RSC: is this necessary? */
+ if(buf[0] == '\0')
+ strcpy(buf, "/");
+ return buf;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getgid.c b/sys/src/ape/lib/ap/plan9/getgid.c
new file mode 100755
index 000000000..e1f5fc39b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getgid.c
@@ -0,0 +1,21 @@
+#include <sys/types.h>
+#include <grp.h>
+#include <unistd.h>
+
+/*
+ * BUG: assumes group that is same as user name
+ * is the one wanted (plan 9 has no "current group")
+ */
+gid_t
+getgid(void)
+{
+ struct group *g;
+ g = getgrnam(getlogin());
+ return g? g->gr_gid : 1;
+}
+
+gid_t
+getegid(void)
+{
+ return getgid();
+}
diff --git a/sys/src/ape/lib/ap/plan9/getgrgid.c b/sys/src/ape/lib/ap/plan9/getgrgid.c
new file mode 100755
index 000000000..77e2997fa
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getgrgid.c
@@ -0,0 +1,25 @@
+#include <stddef.h>
+#include <grp.h>
+
+extern int _getpw(int *, char **, char **);
+extern char **_grpmems(char *);
+
+static struct group holdgroup;
+
+struct group *
+getgrgid(gid_t gid)
+{
+ int num;
+ char *nam, *mem;
+
+ num = gid;
+ nam = 0;
+ mem = 0;
+ if(_getpw(&num, &nam, &mem)){
+ holdgroup.gr_name = nam;
+ holdgroup.gr_gid = num;
+ holdgroup.gr_mem = _grpmems(mem);
+ return &holdgroup;
+ }
+ return NULL;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getgrnam.c b/sys/src/ape/lib/ap/plan9/getgrnam.c
new file mode 100755
index 000000000..7033120e4
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getgrnam.c
@@ -0,0 +1,25 @@
+#include <stddef.h>
+#include <grp.h>
+
+extern int _getpw(int *, char **, char **);
+extern char **_grpmems(char *);
+
+static struct group holdgroup;
+
+struct group *
+getgrnam(const char *name)
+{
+ int num;
+ char *nam, *mem;
+
+ num = 0;
+ nam = name;
+ mem = 0;
+ if(_getpw(&num, &nam, &mem)){
+ holdgroup.gr_name = nam;
+ holdgroup.gr_gid = num;
+ holdgroup.gr_mem = _grpmems(mem);
+ return &holdgroup;
+ }
+ return NULL;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getgroups.c b/sys/src/ape/lib/ap/plan9/getgroups.c
new file mode 100755
index 000000000..e226a65b4
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getgroups.c
@@ -0,0 +1,10 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+int
+getgroups(int gidsize, gid_t grouplist[])
+{
+ errno = EINVAL;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getlogin.c b/sys/src/ape/lib/ap/plan9/getlogin.c
new file mode 100755
index 000000000..8d2d51ce0
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getlogin.c
@@ -0,0 +1,27 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/limits.h>
+
+char *
+getlogin_r(char *buf, int len)
+{
+ int f, n;
+
+ f = open("/dev/user", O_RDONLY);
+ if(f < 0)
+ return 0;
+ n = read(f, buf, len);
+ buf[len-1] = 0;
+ close(f);
+ return (n>=0)? buf : 0;
+}
+
+char *
+getlogin(void)
+{
+ static char buf[NAME_MAX+1];
+
+ return getlogin_r(buf, sizeof buf);
+}
diff --git a/sys/src/ape/lib/ap/plan9/getpgrp.c b/sys/src/ape/lib/ap/plan9/getpgrp.c
new file mode 100755
index 000000000..310028784
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getpgrp.c
@@ -0,0 +1,27 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include "sys9.h"
+#include "lib.h"
+
+pid_t
+getpgrp(void)
+{
+ int n, f, pid;
+ char pgrpbuf[15], fname[30];
+
+ pid = getpid();
+ sprintf(fname, "/proc/%d/noteid", pid);
+ f = open(fname, 0);
+ n = read(f, pgrpbuf, sizeof pgrpbuf);
+ if(n < 0)
+ _syserrno();
+ else
+ n = atoi(pgrpbuf);
+ close(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getpid.c b/sys/src/ape/lib/ap/plan9/getpid.c
new file mode 100755
index 000000000..66eaaae8d
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getpid.c
@@ -0,0 +1,22 @@
+#include "lib.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "sys9.h"
+
+pid_t
+getpid(void)
+{
+ int n, f;
+ char pidbuf[15];
+
+ f = _OPEN("#c/pid", 0);
+ n = _READ(f, pidbuf, sizeof pidbuf);
+ if(n < 0)
+ _syserrno();
+ else
+ n = atoi(pidbuf);
+ _CLOSE(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getppid.c b/sys/src/ape/lib/ap/plan9/getppid.c
new file mode 100755
index 000000000..01759221b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getppid.c
@@ -0,0 +1,23 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "sys9.h"
+
+pid_t
+getppid(void)
+{
+ int n, f;
+ char ppidbuf[15];
+
+ f = open("#c/ppid", 0);
+ n = read(f, ppidbuf, sizeof ppidbuf);
+ if(n < 0)
+ errno = EINVAL;
+ else
+ n = atoi(ppidbuf);
+ close(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getpwnam.c b/sys/src/ape/lib/ap/plan9/getpwnam.c
new file mode 100755
index 000000000..e9d1c5b4e
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getpwnam.c
@@ -0,0 +1,29 @@
+#include "lib.h"
+#include <stddef.h>
+#include <pwd.h>
+#include <string.h>
+
+static struct passwd holdpw;
+static char dirbuf[40] = "/usr/";
+static char *rc = "/bin/rc";
+
+struct passwd *
+getpwnam(const char *name)
+{
+ int num;
+ char *nam, *mem;
+
+ num = 0;
+ nam = name;
+ mem = 0;
+ if(_getpw(&num, &nam, &mem)){
+ holdpw.pw_name = nam;
+ holdpw.pw_uid = num;
+ holdpw.pw_gid = num;
+ strncpy(dirbuf+5, nam, sizeof(dirbuf)-6);
+ holdpw.pw_dir = dirbuf;
+ holdpw.pw_shell = rc;
+ return &holdpw;
+ }
+ return NULL;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getpwuid.c b/sys/src/ape/lib/ap/plan9/getpwuid.c
new file mode 100755
index 000000000..e2983765b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getpwuid.c
@@ -0,0 +1,30 @@
+#include <stddef.h>
+#include <pwd.h>
+#include <string.h>
+
+extern int _getpw(int *, char **, char **);
+
+static struct passwd holdpw;
+static char dirbuf[40] = "/usr/";
+static char *rc = "/bin/rc";
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+ int num;
+ char *nam, *mem;
+
+ num = uid;
+ nam = 0;
+ mem = 0;
+ if(_getpw(&num, &nam, &mem)){
+ holdpw.pw_name = nam;
+ holdpw.pw_uid = num;
+ holdpw.pw_gid = num;
+ strncpy(dirbuf+5, nam, sizeof(dirbuf)-6);
+ holdpw.pw_dir = dirbuf;
+ holdpw.pw_shell = rc;
+ return &holdpw;
+ }
+ return NULL;
+}
diff --git a/sys/src/ape/lib/ap/plan9/getuid.c b/sys/src/ape/lib/ap/plan9/getuid.c
new file mode 100755
index 000000000..05d4c0832
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/getuid.c
@@ -0,0 +1,17 @@
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+
+uid_t
+getuid(void)
+{
+ struct passwd *p;
+ p = getpwnam(getlogin());
+ return p? p->pw_uid : 1;
+}
+
+uid_t
+geteuid(void)
+{
+ return getuid();
+}
diff --git a/sys/src/ape/lib/ap/plan9/isatty.c b/sys/src/ape/lib/ap/plan9/isatty.c
new file mode 100755
index 000000000..e04cd891d
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/isatty.c
@@ -0,0 +1,29 @@
+#include "lib.h"
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "sys9.h"
+#include "dir.h"
+
+int
+_isatty(int fd)
+{
+ int t;
+ char buf[64];
+
+ if(_FD2PATH(fd, buf, sizeof buf) < 0)
+ return 0;
+
+ /* might be /mnt/term/dev/cons */
+ return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
+}
+
+/* The FD_ISTTY flag is set via _isatty in _fdsetup or open */
+int
+isatty(fd)
+{
+ if(_fdinfo[fd].flags&FD_ISTTY)
+ return 1;
+ else
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/kill.c b/sys/src/ape/lib/ap/plan9/kill.c
new file mode 100755
index 000000000..95bbbdcc7
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/kill.c
@@ -0,0 +1,60 @@
+#include "lib.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+static int
+note(int pid, char *msg, char *fmt)
+{
+ int f;
+ char pname[50];
+
+ sprintf(pname, fmt, pid);
+ f = open(pname, O_WRONLY);
+ if(f < 0){
+ errno = ESRCH;
+ return -1;
+ }
+ if(msg != 0 && write(f, msg, strlen(msg)) < 0){
+ close(f);
+ errno = EPERM;
+ return -1;
+ }
+ close(f);
+ return 0;
+}
+
+int
+kill(pid_t pid, int sig)
+{
+ char *msg;
+ int sid, r, mpid;
+
+ if(sig == 0)
+ msg = 0;
+ else {
+ msg = _sigstring(sig);
+ if(msg == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ if(pid < 0) {
+ sid = getpgrp();
+ mpid = getpid();
+ if(setpgid(mpid, -pid) == 0) {
+ r = note(mpid, msg, "/proc/%d/notepg");
+ setpgid(mpid, sid);
+ } else {
+ r = -1;
+ }
+ } else if(pid == 0)
+ r = note(getpid(), msg, "/proc/%d/notepg");
+ else
+ r = note(pid, msg, "/proc/%d/note");
+ return r;
+}
diff --git a/sys/src/ape/lib/ap/plan9/lib.h b/sys/src/ape/lib/ap/plan9/lib.h
new file mode 100755
index 000000000..91a51d5d3
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/lib.h
@@ -0,0 +1,72 @@
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <fcntl.h>
+#include <ureg.h>
+
+typedef struct Ureg Ureg;
+
+/* mux buf for selecting (see _buf.c) */
+enum {
+ READMAX = 8192, /* read at most this much with _READ */
+ PERFDMAX = 2*READMAX, /* stop _READing an fd when it has this much */
+ INITBUFS = 4, /* allow enough room for this many PERFDMAX */
+};
+
+typedef struct Muxbuf {
+ int n; /* # unprocessed chars in buf */
+ unsigned char* putnext; /* place for copy process to put next data */
+ unsigned char* getnext; /* place for parent process to get next data */
+ char fd; /* fd for which this is a buffer */
+ unsigned char eof; /* true if eof after current data exhausted */
+ unsigned char roomwait; /* true if copy process is waiting for room */
+ unsigned char datawait; /* true if parent process is waiting for data */
+ int copypid; /* pid of copyproc */
+ unsigned char data[PERFDMAX];
+} Muxbuf;
+
+/* be sure to change _fdinfo[] init in _fdinfo if you change this */
+typedef struct Fdinfo{
+ unsigned long flags;
+ unsigned long oflags;
+ uid_t uid;
+ gid_t gid;
+ char *name;
+ /*
+ * the following is used if flags&FD_BUFFERED
+ */
+ Muxbuf *buf; /* holds buffered data and state */
+} Fdinfo;
+
+/* #define FD_CLOEXEC 1 is in fcntl.h */
+
+#define FD_ISOPEN 0x2
+#define FD_BUFFERED 0x4
+#define FD_BUFFEREDX 0x8
+#define FD_ISTTY 0x20
+
+#define MAXSIG SIGUSR2
+
+extern Fdinfo _fdinfo[];
+
+extern int _finishing;
+extern int _sessleader;
+extern void (*_sighdlr[])(int, char*, Ureg*);
+extern char *_sigstring(int);
+extern int _stringsig(char *);
+extern long _psigblocked;
+extern int _startbuf(int);
+extern int _selbuf(int);
+extern void _closebuf(int);
+extern int _readbuf(int, void*, int, int);
+extern void _detachbuf(void);
+extern void _finish(int, char *);
+extern char *_ultoa(char *, unsigned long);
+extern int _notehandler(void *, char *);
+extern void _notetramp(int, void (*)(int, char*, Ureg*), Ureg*);
+extern void _syserrno(void);
+extern int _getpw(int *, char **, char **);
+extern int _isatty(int);
+extern void _fdinit(char*, char*);
+
+
+void checkbug(char *, int);
diff --git a/sys/src/ape/lib/ap/plan9/link.c b/sys/src/ape/lib/ap/plan9/link.c
new file mode 100755
index 000000000..9bf3755fb
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/link.c
@@ -0,0 +1,12 @@
+#include <unistd.h>
+#include <errno.h>
+
+/*
+ * BUG: LINK_MAX==1 isn't really allowed
+ */
+int
+link(const char *name1, const char *name2)
+{
+ errno = EMLINK;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/lseek.c b/sys/src/ape/lib/ap/plan9/lseek.c
new file mode 100755
index 000000000..8c4eba39d
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/lseek.c
@@ -0,0 +1,24 @@
+#include "lib.h"
+#include <unistd.h>
+#include <errno.h>
+#include "sys9.h"
+
+/*
+ * BUG: errno mapping
+ */
+off_t
+lseek(int d, off_t offset, int whence)
+{
+ long long n;
+ int flags;
+
+ flags = _fdinfo[d].flags;
+ if(flags&(FD_BUFFERED|FD_BUFFEREDX|FD_ISTTY)) {
+ errno = ESPIPE;
+ return -1;
+ }
+ n = _SEEK(d, offset, whence);
+ if(n < 0)
+ _syserrno();
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/malloc.c b/sys/src/ape/lib/ap/plan9/malloc.c
new file mode 100755
index 000000000..09f3c178e
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/malloc.c
@@ -0,0 +1,142 @@
+#include <stdlib.h>
+#include <string.h>
+
+typedef unsigned int uint;
+
+enum
+{
+ MAGIC = 0xbada110c,
+ MAX2SIZE = 32,
+ CUTOFF = 12,
+};
+
+typedef struct Bucket Bucket;
+struct Bucket
+{
+ int size;
+ int magic;
+ Bucket *next;
+ int pad;
+ char data[1];
+};
+
+typedef struct Arena Arena;
+struct Arena
+{
+ Bucket *btab[MAX2SIZE];
+};
+static Arena arena;
+
+#define datoff ((int)((Bucket*)0)->data)
+#define nil ((void*)0)
+
+extern void *sbrk(unsigned long);
+
+void*
+malloc(size_t size)
+{
+ uint next;
+ int pow, n;
+ Bucket *bp, *nbp;
+
+ for(pow = 1; pow < MAX2SIZE; pow++) {
+ if(size <= (1<<pow))
+ goto good;
+ }
+
+ return nil;
+good:
+ /* Allocate off this list */
+ bp = arena.btab[pow];
+ if(bp) {
+ arena.btab[pow] = bp->next;
+
+ if(bp->magic != 0)
+ abort();
+
+ bp->magic = MAGIC;
+ return bp->data;
+ }
+ size = sizeof(Bucket)+(1<<pow);
+ size += 7;
+ size &= ~7;
+
+ if(pow < CUTOFF) {
+ n = (CUTOFF-pow)+2;
+ bp = sbrk(size*n);
+ if((int)bp < 0)
+ return nil;
+
+ next = (uint)bp+size;
+ nbp = (Bucket*)next;
+ arena.btab[pow] = nbp;
+ for(n -= 2; n; n--) {
+ next = (uint)nbp+size;
+ nbp->next = (Bucket*)next;
+ nbp->size = pow;
+ nbp = nbp->next;
+ }
+ nbp->size = pow;
+ }
+ else {
+ bp = sbrk(size);
+ if((int)bp < 0)
+ return nil;
+ }
+
+ bp->size = pow;
+ bp->magic = MAGIC;
+
+ return bp->data;
+}
+
+void
+free(void *ptr)
+{
+ Bucket *bp, **l;
+
+ if(ptr == nil)
+ return;
+
+ /* Find the start of the structure */
+ bp = (Bucket*)((uint)ptr - datoff);
+
+ if(bp->magic != MAGIC)
+ abort();
+
+ bp->magic = 0;
+ l = &arena.btab[bp->size];
+ bp->next = *l;
+ *l = bp;
+}
+
+void*
+realloc(void *ptr, size_t n)
+{
+ void *new;
+ uint osize;
+ Bucket *bp;
+
+ if(ptr == nil)
+ return malloc(n);
+
+ /* Find the start of the structure */
+ bp = (Bucket*)((uint)ptr - datoff);
+
+ if(bp->magic != MAGIC)
+ abort();
+
+ /* enough space in this bucket */
+ osize = 1<<bp->size;
+ if(osize >= n)
+ return ptr;
+
+ new = malloc(n);
+ if(new == nil)
+ return nil;
+
+ memmove(new, ptr, osize);
+ free(ptr);
+
+ return new;
+}
diff --git a/sys/src/ape/lib/ap/plan9/mkdir.c b/sys/src/ape/lib/ap/plan9/mkdir.c
new file mode 100755
index 000000000..1773150b5
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/mkdir.c
@@ -0,0 +1,27 @@
+#include "lib.h"
+#include <sys/stat.h>
+#include <errno.h>
+#include "sys9.h"
+
+/*
+ * BUG: errno mapping
+ */
+int
+mkdir(const char *name, mode_t mode)
+{
+ int n;
+ struct stat st;
+
+ if(stat(name, &st)==0) {
+ errno = EEXIST;
+ return -1;
+ }
+ n = _CREATE(name, 0, 0x80000000|(mode&0777));
+ if(n < 0)
+ _syserrno();
+ else{
+ _CLOSE(n);
+ n = 0;
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/mkfile b/sys/src/ape/lib/ap/plan9/mkfile
new file mode 100755
index 000000000..502d00f8b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/mkfile
@@ -0,0 +1,110 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ _buf.$O\
+ _dirconv.$O\
+ _envsetup.$O\
+ _errno.$O\
+ _exit.$O\
+ _fdinfo.$O\
+ _getpw.$O\
+ _nap.$O\
+ 9mallocz.$O\
+ 9iounit.$O\
+ 9read.$O\
+ 9readn.$O\
+ 9wait.$O\
+ 9write.$O\
+ access.$O\
+ alarm.$O\
+ brk.$O\
+ cfgetospeed.$O\
+ chdir.$O\
+ chmod.$O\
+ chown.$O\
+ close.$O\
+ convM2D.$O\
+ convD2M.$O\
+ creat.$O\
+ ctermid.$O\
+ ctime.$O\
+ cuserid.$O\
+ dirread.$O\
+ dirstat.$O\
+ dirtostat.$O\
+ dup.$O\
+ execl.$O\
+ execle.$O\
+ execlp.$O\
+ execv.$O\
+ execve.$O\
+ execvp.$O\
+ fcntl.$O\
+ fork.$O\
+ frexp.$O\
+ fstat.$O\
+ fsync.$O\
+ ftruncate.$O\
+ getcwd.$O\
+ getgid.$O\
+ getgrgid.$O\
+ getgrnam.$O\
+ getgroups.$O\
+ getlogin.$O\
+ getpgrp.$O\
+ getpid.$O\
+ getppid.$O\
+ getpwnam.$O\
+ getpwuid.$O\
+ getuid.$O\
+ isatty.$O\
+ kill.$O\
+ link.$O\
+ lseek.$O\
+ malloc.$O\
+ mkdir.$O\
+ nan.$O\
+ open.$O\
+ opendir.$O\
+ pause.$O\
+ pipe.$O\
+ profile.$O\
+ qlock.$O\
+ read.$O\
+ rename.$O\
+ rmdir.$O\
+ setgid.$O\
+ setpgid.$O\
+ setsid.$O\
+ setuid.$O\
+ signal.$O\
+ sigpending.$O\
+ sigprocmask.$O\
+ sigsuspend.$O\
+ sleep.$O\
+ sqrt.$O\
+ stat.$O\
+ system.$O\
+ tcgetattr.$O\
+ time.$O\
+ times.$O\
+ tmpfile.$O\
+ ttyname.$O\
+ umask.$O\
+ uname.$O\
+ unlink.$O\
+ utime.$O\
+ wait.$O\
+ write.$O\
+
+UPDATE=\
+ mkfile\
+ /386/lib/ape/libap.a\
+ ${OFILES:%.$O=%.c}\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE -D_BSD_EXTENSION
+
+$OFILES: lib.h
diff --git a/sys/src/ape/lib/ap/plan9/nan.c b/sys/src/ape/lib/ap/plan9/nan.c
new file mode 100755
index 000000000..db7c13fe8
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/nan.c
@@ -0,0 +1,54 @@
+#include <float.h>
+#include <math.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ FPdbleword a;
+
+ a.hi = NANEXP;
+ a.lo = 1;
+ return a.x;
+}
+
+int
+isNaN(double d)
+{
+ FPdbleword a;
+
+ a.x = d;
+ if((a.hi & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ FPdbleword a;
+
+ a.hi = NANEXP;
+ a.lo = 0;
+ if(sign < 0)
+ a.hi |= NANSIGN;
+ return a.x;
+}
+
+int
+isInf(double d, int sign)
+{
+ FPdbleword a;
+
+ a.x = d;
+ if(a.lo != 0)
+ return 0;
+ if(a.hi == NANEXP)
+ return sign >= 0;
+ if(a.hi == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/open.c b/sys/src/ape/lib/ap/plan9/open.c
new file mode 100755
index 000000000..1cfe0d6b5
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/open.c
@@ -0,0 +1,62 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "lib.h"
+#include <sys/stat.h>
+#include "sys9.h"
+
+/*
+ * O_NOCTTY has no effect
+ */
+int
+open(const char *path, int flags, ...)
+{
+ int n;
+ long f;
+ int mode;
+ Fdinfo *fi;
+ va_list va;
+ struct stat sbuf;
+
+ f = flags&O_ACCMODE;
+ if(flags&O_CREAT){
+ if(access(path, 0) >= 0){
+ if(flags&O_EXCL){
+ errno = EEXIST;
+ return -1;
+ }else{
+ if((flags&O_TRUNC)&&(flags&(O_RDWR|O_WRONLY)))
+ f |= 16;
+ n = _OPEN(path, f);
+ }
+ }else{
+ va_start(va, flags);
+ mode = va_arg(va, int);
+ va_end(va);
+ n = _CREATE(path, f, mode&0777);
+ }
+ if(n < 0)
+ _syserrno();
+ }else{
+ if((flags&O_TRUNC)&&(flags&(O_RDWR|O_WRONLY)))
+ f |= 16;
+ n = _OPEN(path, f);
+ if(n < 0)
+ _syserrno();
+ }
+ if(n >= 0){
+ fi = &_fdinfo[n];
+ fi->flags = FD_ISOPEN;
+ fi->oflags = flags&(O_ACCMODE|O_NONBLOCK|O_APPEND);
+ fi->uid = -2;
+ fi->gid = -2;
+ fi->name = malloc(strlen(path)+1);
+ if(fi->name)
+ strcpy(fi->name, path);
+ if(fi->oflags&O_APPEND)
+ _SEEK(n, 0, 2);
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/opendir.c b/sys/src/ape/lib/ap/plan9/opendir.c
new file mode 100755
index 000000000..ebc22dbf6
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/opendir.c
@@ -0,0 +1,121 @@
+#include "lib.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include "sys9.h"
+#include "dir.h"
+
+#define DBLOCKSIZE 20
+
+DIR *
+opendir(const char *filename)
+{
+ int f;
+ DIR *d;
+ struct stat sb;
+ Dir *d9;
+
+ if((d9 = _dirstat(filename)) == nil){
+ _syserrno();
+ return NULL;
+ }
+ _dirtostat(&sb, d9, 0);
+ free(d9);
+ if(S_ISDIR(sb.st_mode) == 0) {
+ errno = ENOTDIR;
+ return NULL;
+ }
+
+ f = open(filename, O_RDONLY);
+ if(f < 0){
+ _syserrno();
+ return NULL;
+ }
+ _fdinfo[f].flags |= FD_CLOEXEC;
+ d = (DIR *)malloc(sizeof(DIR) + DBLOCKSIZE*sizeof(struct dirent));
+ if(!d){
+ errno = ENOMEM;
+ return NULL;
+ }
+ d->dd_buf = (char *)d + sizeof(DIR);
+ d->dd_fd = f;
+ d->dd_loc = 0;
+ d->dd_size = 0;
+ d->dirs = nil;
+ d->dirsize = 0;
+ d->dirloc = 0;
+ return d;
+}
+
+int
+closedir(DIR *d)
+{
+ if(!d){
+ errno = EBADF;
+ return -1;
+ }
+ if(close(d->dd_fd) < 0)
+ return -1;
+ free(d->dirs);
+ free(d);
+ return 0;
+}
+
+void
+rewinddir(DIR *d)
+{
+ if(!d)
+ return;
+ d->dd_loc = 0;
+ d->dd_size = 0;
+ d->dirsize = 0;
+ d->dirloc = 0;
+ free(d->dirs);
+ d->dirs = nil;
+ if(_SEEK(d->dd_fd, 0, 0) < 0){
+ _syserrno();
+ return;
+ }
+}
+
+struct dirent *
+readdir(DIR *d)
+{
+ int i, n;
+ struct dirent *dr;
+ Dir *dirs;
+
+ if(!d){
+ errno = EBADF;
+ return NULL;
+ }
+ if(d->dd_loc >= d->dd_size){
+ if(d->dirloc >= d->dirsize){
+ free(d->dirs);
+ d->dirs = NULL;
+ d->dirsize = _dirread(d->dd_fd, &d->dirs);
+ d->dirloc = 0;
+ }
+ if(d->dirsize < 0) { /* malloc or read failed in _dirread? */
+ free(d->dirs);
+ d->dirs = NULL;
+ }
+ if(d->dirs == NULL)
+ return NULL;
+
+ dr = (struct dirent *)d->dd_buf;
+ dirs = d->dirs;
+ for(i=0; i<DBLOCKSIZE && d->dirloc < d->dirsize; i++){
+ strncpy(dr[i].d_name, dirs[d->dirloc++].name, MAXNAMLEN);
+ dr[i].d_name[MAXNAMLEN] = 0;
+ }
+ d->dd_loc = 0;
+ d->dd_size = i*sizeof(struct dirent);
+ }
+ dr = (struct dirent*)(d->dd_buf+d->dd_loc);
+ d->dd_loc += sizeof(struct dirent);
+ return dr;
+}
diff --git a/sys/src/ape/lib/ap/plan9/pause.c b/sys/src/ape/lib/ap/plan9/pause.c
new file mode 100755
index 000000000..38fd96162
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/pause.c
@@ -0,0 +1,11 @@
+#include "lib.h"
+#include <unistd.h>
+#include "sys9.h"
+
+int
+pause(void)
+{
+ for(;;)
+ if(_SLEEP(1000*1000) < 0)
+ return;
+}
diff --git a/sys/src/ape/lib/ap/plan9/pipe.c b/sys/src/ape/lib/ap/plan9/pipe.c
new file mode 100755
index 000000000..edc2372e8
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/pipe.c
@@ -0,0 +1,31 @@
+#include <errno.h>
+#include "lib.h"
+#include "sys9.h"
+
+int
+pipe(int fildes[2])
+{
+ Fdinfo *fi;
+ int i;
+
+ if(!fildes){
+ errno = EFAULT;
+ return -1;
+ }
+ if(_PIPE(fildes) < 0)
+ _syserrno();
+ else
+ if(fildes[0] < 0 || fildes[0]>=OPEN_MAX ||
+ fildes[1] < 0 || fildes[1]>=OPEN_MAX) {
+ errno = EMFILE;
+ return -1;
+ }
+ for(i = 0; i <=1; i++) {
+ fi = &_fdinfo[fildes[i]];
+ fi->flags = FD_ISOPEN;
+ fi->oflags = O_RDWR;
+ fi->uid = 0; /* none */
+ fi->gid = 0;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/profile.c b/sys/src/ape/lib/ap/plan9/profile.c
new file mode 100755
index 000000000..a69e65f2b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/profile.c
@@ -0,0 +1,324 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include "sys9.h"
+
+enum {
+ Profoff, /* No profiling */
+ Profuser, /* Measure user time only (default) */
+ Profkernel, /* Measure user + kernel time */
+ Proftime, /* Measure total time */
+ Profsample, /* Use clock interrupt to sample (default when there is no cycle counter) */
+}; /* what */
+
+typedef long long vlong;
+typedef unsigned long ulong;
+typedef unsigned long long uvlong;
+
+#include "/sys/include/tos.h"
+
+extern void* sbrk(ulong);
+extern long _callpc(void**);
+extern long _savearg(void);
+extern void _cycles(uvlong*); /* 64-bit value of the cycle counter if there is one, 0 if there isn't */
+
+static ulong khz;
+static ulong perr;
+static int havecycles;
+
+typedef struct Plink Plink;
+struct Plink
+{
+ Plink *old;
+ Plink *down;
+ Plink *link;
+ long pc;
+ long count;
+ vlong time;
+};
+
+#pragma profile off
+
+ulong
+_profin(void)
+{
+ void *dummy;
+ long pc;
+ Plink *pp, *p;
+ ulong arg;
+ vlong t;
+
+ arg = _savearg();
+ pc = _callpc(&dummy);
+ pp = _tos->prof.pp;
+ if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid))
+ return arg;
+
+ for(p=pp->down; p; p=p->link)
+ if(p->pc == pc)
+ goto out;
+ p = _tos->prof.next + 1;
+ if(p >= _tos->prof.last){
+ _tos->prof.pp = 0;
+ perr++;
+ return arg;
+ }
+ _tos->prof.next = p;
+ p->link = pp->down;
+ pp->down = p;
+ p->pc = pc;
+ p->old = pp;
+ p->down = 0;
+ p->count = 0;
+ p->time = 0LL;
+
+out:
+ _tos->prof.pp = p;
+ p->count++;
+ switch(_tos->prof.what){
+ case Profkernel:
+ p->time = p->time - _tos->pcycles;
+ goto proftime;
+ case Profuser:
+ /* Add kernel cycles on proc entry */
+ p->time = p->time + _tos->kcycles;
+ /* fall through */
+ case Proftime:
+ proftime: /* Subtract cycle counter on proc entry */
+ _cycles((uvlong*)&t);
+ p->time = p->time - t;
+ break;
+ case Profsample:
+ p->time = p->time - _tos->clock;
+ break;
+ }
+ return arg; /* disgusting linkage */
+}
+
+ulong
+_profout(void)
+{
+ Plink *p;
+ ulong arg;
+ vlong t;
+
+ arg = _savearg();
+ p = _tos->prof.pp;
+ if (p == NULL || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid))
+ return arg; /* Not our process */
+ switch(_tos->prof.what){
+ case Profkernel: /* Add proc cycles on proc entry */
+ p->time = p->time + _tos->pcycles;
+ goto proftime;
+ case Profuser: /* Subtract kernel cycles on proc entry */
+ p->time = p->time - _tos->kcycles;
+ /* fall through */
+ case Proftime:
+ proftime: /* Add cycle counter on proc entry */
+ _cycles((uvlong*)&t);
+ p->time = p->time + t;
+ break;
+ case Profsample:
+ p->time = p->time + _tos->clock;
+ break;
+ }
+ _tos->prof.pp = p->old;
+ return arg;
+}
+
+/* stdio may not be ready for us yet */
+static void
+err(char *fmt, ...)
+{
+ int fd;
+ va_list arg;
+ char buf[128];
+
+ if((fd = open("/dev/cons", OWRITE)) == -1)
+ return;
+ va_start(arg, fmt);
+ /*
+ * C99 now requires *snprintf to return the number of characters
+ * that *would* have been emitted, had there been room for them,
+ * or a negative value on an `encoding error'. Arrgh!
+ */
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+ write(fd, buf, strlen(buf));
+ close(fd);
+}
+
+void
+_profdump(void)
+{
+ int f;
+ long n;
+ Plink *p;
+ char *vp;
+ char filename[64];
+
+ if (_tos->prof.what == 0)
+ return; /* No profiling */
+ if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)
+ return; /* Not our process */
+ if(perr)
+ err("%lud Prof errors\n", perr);
+ _tos->prof.pp = NULL;
+ if (_tos->prof.pid)
+ snprintf(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid);
+ else
+ snprintf(filename, sizeof filename - 1, "prof.out");
+ f = creat(filename, 0666);
+ if(f < 0) {
+ err("%s: cannot create - %s\n", filename, strerror(errno));
+ return;
+ }
+ _tos->prof.pid = ~0; /* make sure data gets dumped once */
+ switch(_tos->prof.what){
+ case Profkernel:
+ _cycles((uvlong*)&_tos->prof.first->time);
+ _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles;
+ break;
+ case Profuser:
+ _cycles((uvlong*)&_tos->prof.first->time);
+ _tos->prof.first->time = _tos->prof.first->time - _tos->kcycles;
+ break;
+ case Proftime:
+ _cycles((uvlong*)&_tos->prof.first->time);
+ break;
+ case Profsample:
+ _tos->prof.first->time = _tos->clock;
+ break;
+ }
+ vp = (char*)_tos->prof.first;
+
+ for(p = _tos->prof.first; p <= _tos->prof.next; p++) {
+
+ /*
+ * short down
+ */
+ n = 0xffff;
+ if(p->down)
+ n = p->down - _tos->prof.first;
+ vp[0] = n>>8;
+ vp[1] = n;
+
+ /*
+ * short right
+ */
+ n = 0xffff;
+ if(p->link)
+ n = p->link - _tos->prof.first;
+ vp[2] = n>>8;
+ vp[3] = n;
+ vp += 4;
+
+ /*
+ * long pc
+ */
+ n = p->pc;
+ vp[0] = n>>24;
+ vp[1] = n>>16;
+ vp[2] = n>>8;
+ vp[3] = n;
+ vp += 4;
+
+ /*
+ * long count
+ */
+ n = p->count;
+ vp[0] = n>>24;
+ vp[1] = n>>16;
+ vp[2] = n>>8;
+ vp[3] = n;
+ vp += 4;
+
+ /*
+ * vlong time
+ */
+ if (havecycles){
+ n = (vlong)(p->time / (vlong)khz);
+ }else
+ n = p->time;
+
+ vp[0] = n>>24;
+ vp[1] = n>>16;
+ vp[2] = n>>8;
+ vp[3] = n;
+ vp += 4;
+ }
+ write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first);
+ close(f);
+
+}
+
+void
+_profinit(int entries, int what)
+{
+ if (_tos->prof.what == 0)
+ return; /* Profiling not linked in */
+ _tos->prof.pp = NULL;
+ _tos->prof.first = calloc(entries*sizeof(Plink),1);
+ _tos->prof.last = _tos->prof.first + entries;
+ _tos->prof.next = _tos->prof.first;
+ _tos->prof.pid = _tos->pid;
+ _tos->prof.what = what;
+ _tos->clock = 1;
+}
+
+void
+_profmain(void)
+{
+ char ename[50];
+ int n, f;
+
+ n = 2000;
+ if (_tos->cyclefreq != 0LL){
+ khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */
+ havecycles = 1;
+ }
+ f = open("/env/profsize", OREAD);
+ if(f >= 0) {
+ memset(ename, 0, sizeof(ename));
+ read(f, ename, sizeof(ename)-1);
+ close(f);
+ n = atol(ename);
+ }
+ _tos->prof.what = Profuser;
+ f = open("/env/proftype", OREAD);
+ if(f >= 0) {
+ memset(ename, 0, sizeof(ename));
+ read(f, ename, sizeof(ename)-1);
+ close(f);
+ if (strcmp(ename, "user") == 0)
+ _tos->prof.what = Profuser;
+ else if (strcmp(ename, "kernel") == 0)
+ _tos->prof.what = Profkernel;
+ else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0)
+ _tos->prof.what = Proftime;
+ else if (strcmp(ename, "sample") == 0)
+ _tos->prof.what = Profsample;
+ }
+ _tos->prof.first = sbrk(n*sizeof(Plink));
+ _tos->prof.last = sbrk(0);
+ _tos->prof.next = _tos->prof.first;
+ _tos->prof.pp = NULL;
+ _tos->prof.pid = _tos->pid;
+ atexit(_profdump);
+ _tos->clock = 1;
+}
+
+void prof(void (*fn)(void*), void *arg, int entries, int what)
+{
+ _profinit(entries, what);
+ _tos->prof.pp = _tos->prof.next;
+ fn(arg);
+ _profdump();
+}
+
+#pragma profile on
+
diff --git a/sys/src/ape/lib/ap/plan9/qlock.c b/sys/src/ape/lib/ap/plan9/qlock.c
new file mode 100755
index 000000000..b0882f789
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/qlock.c
@@ -0,0 +1,365 @@
+#define _LOCK_EXTENSION
+#define _QLOCK_EXTENSION
+#define _RESEARCH_SOURCE
+#include <u.h>
+#include <lock.h>
+#include <qlock.h>
+#include <stdlib.h>
+#include "sys9.h"
+
+#define rendezvous _RENDEZVOUS
+#define _rendezvousp rendezvous
+#define _tas tas
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+static struct {
+ QLp *p;
+ QLp x[1024];
+} ql = {
+ ql.x
+};
+
+enum
+{
+ Queuing,
+ QueuingR,
+ QueuingW,
+ Sleeping,
+};
+
+/* find a free shared memory location to queue ourselves in */
+static QLp*
+getqlp(void)
+{
+ QLp *p, *op;
+
+ op = ql.p;
+ for(p = op+1; ; p++){
+ if(p == &ql.x[nelem(ql.x)])
+ p = ql.x;
+ if(p == op)
+ abort();
+ if(_tas(&(p->inuse)) == 0){
+ ql.p = p;
+ p->next = nil;
+ break;
+ }
+ }
+ return p;
+}
+
+void
+qlock(QLock *q)
+{
+ QLp *p, *mp;
+
+ lock(&q->lock);
+ if(!q->locked){
+ q->locked = 1;
+ unlock(&q->lock);
+ return;
+ }
+
+
+ /* chain into waiting list */
+ mp = getqlp();
+ p = q->tail;
+ if(p == nil)
+ q->head = mp;
+ else
+ p->next = mp;
+ q->tail = mp;
+ mp->state = Queuing;
+ unlock(&q->lock);
+
+ /* wait */
+ while((*_rendezvousp)((ulong)mp, 1) == ~0)
+ ;
+ mp->inuse = 0;
+}
+
+void
+qunlock(QLock *q)
+{
+ QLp *p;
+
+ lock(&q->lock);
+ p = q->head;
+ if(p != nil){
+ /* wakeup head waiting process */
+ q->head = p->next;
+ if(q->head == nil)
+ q->tail = nil;
+ unlock(&q->lock);
+ while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
+ ;
+ return;
+ }
+ q->locked = 0;
+ unlock(&q->lock);
+}
+
+int
+canqlock(QLock *q)
+{
+ if(!canlock(&q->lock))
+ return 0;
+ if(!q->locked){
+ q->locked = 1;
+ unlock(&q->lock);
+ return 1;
+ }
+ unlock(&q->lock);
+ return 0;
+}
+
+#if 0
+
+void
+rlock(RWLock *q)
+{
+ QLp *p, *mp;
+
+ lock(&q->lock);
+ if(q->writer == 0 && q->head == nil){
+ /* no writer, go for it */
+ q->readers++;
+ unlock(&q->lock);
+ return;
+ }
+
+ mp = getqlp();
+ p = q->tail;
+ if(p == 0)
+ q->head = mp;
+ else
+ p->next = mp;
+ q->tail = mp;
+ mp->next = nil;
+ mp->state = QueuingR;
+ unlock(&q->lock);
+
+ /* wait in kernel */
+ while((*_rendezvousp)((ulong)mp, 1) == ~0)
+ ;
+ mp->inuse = 0;
+}
+
+int
+canrlock(RWLock *q)
+{
+ lock(&q->lock);
+ if (q->writer == 0 && q->head == nil) {
+ /* no writer; go for it */
+ q->readers++;
+ unlock(&q->lock);
+ return 1;
+ }
+ unlock(&q->lock);
+ return 0;
+}
+
+void
+runlock(RWLock *q)
+{
+ QLp *p;
+
+ lock(&q->lock);
+ if(q->readers <= 0)
+ abort();
+ p = q->head;
+ if(--(q->readers) > 0 || p == nil){
+ unlock(&q->lock);
+ return;
+ }
+
+ /* start waiting writer */
+ if(p->state != QueuingW)
+ abort();
+ q->head = p->next;
+ if(q->head == 0)
+ q->tail = 0;
+ q->writer = 1;
+ unlock(&q->lock);
+
+ /* wakeup waiter */
+ while((*_rendezvousp)((ulong)p, 0) == ~0)
+ ;
+}
+
+void
+wlock(RWLock *q)
+{
+ QLp *p, *mp;
+
+ lock(&q->lock);
+ if(q->readers == 0 && q->writer == 0){
+ /* noone waiting, go for it */
+ q->writer = 1;
+ unlock(&q->lock);
+ return;
+ }
+
+ /* wait */
+ p = q->tail;
+ mp = getqlp();
+ if(p == nil)
+ q->head = mp;
+ else
+ p->next = mp;
+ q->tail = mp;
+ mp->next = nil;
+ mp->state = QueuingW;
+ unlock(&q->lock);
+
+ /* wait in kernel */
+ while((*_rendezvousp)((ulong)mp, 1) == ~0)
+ ;
+ mp->inuse = 0;
+}
+
+int
+canwlock(RWLock *q)
+{
+ lock(&q->lock);
+ if (q->readers == 0 && q->writer == 0) {
+ /* no one waiting; go for it */
+ q->writer = 1;
+ unlock(&q->lock);
+ return 1;
+ }
+ unlock(&q->lock);
+ return 0;
+}
+
+void
+wunlock(RWLock *q)
+{
+ QLp *p;
+
+ lock(&q->lock);
+ if(q->writer == 0)
+ abort();
+ p = q->head;
+ if(p == nil){
+ q->writer = 0;
+ unlock(&q->lock);
+ return;
+ }
+ if(p->state == QueuingW){
+ /* start waiting writer */
+ q->head = p->next;
+ if(q->head == nil)
+ q->tail = nil;
+ unlock(&q->lock);
+ while((*_rendezvousp)((ulong)p, 0) == ~0)
+ ;
+ return;
+ }
+
+ if(p->state != QueuingR)
+ abort();
+
+ /* wake waiting readers */
+ while(q->head != nil && q->head->state == QueuingR){
+ p = q->head;
+ q->head = p->next;
+ q->readers++;
+ while((*_rendezvousp)((ulong)p, 0) == ~0)
+ ;
+ }
+ if(q->head == nil)
+ q->tail = nil;
+ q->writer = 0;
+ unlock(&q->lock);
+}
+
+void
+rsleep(Rendez *r)
+{
+ QLp *t, *me;
+
+ if(!r->l)
+ abort();
+ lock(&r->l->lock);
+ /* we should hold the qlock */
+ if(!r->l->locked)
+ abort();
+
+ /* add ourselves to the wait list */
+ me = getqlp();
+ me->state = Sleeping;
+ if(r->head == nil)
+ r->head = me;
+ else
+ r->tail->next = me;
+ me->next = nil;
+ r->tail = me;
+
+ /* pass the qlock to the next guy */
+ t = r->l->head;
+ if(t){
+ r->l->head = t->next;
+ if(r->l->head == nil)
+ r->l->tail = nil;
+ unlock(&r->l->lock);
+ while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
+ ;
+ }else{
+ r->l->locked = 0;
+ unlock(&r->l->lock);
+ }
+
+ /* wait for a wakeup */
+ while((*_rendezvousp)((ulong)me, 1) == ~0)
+ ;
+ me->inuse = 0;
+}
+
+int
+rwakeup(Rendez *r)
+{
+ QLp *t;
+
+ /*
+ * take off wait and put on front of queue
+ * put on front so guys that have been waiting will not get starved
+ */
+
+ if(!r->l)
+ abort();
+ lock(&r->l->lock);
+ if(!r->l->locked)
+ abort();
+
+ t = r->head;
+ if(t == nil){
+ unlock(&r->l->lock);
+ return 0;
+ }
+
+ r->head = t->next;
+ if(r->head == nil)
+ r->tail = nil;
+
+ t->next = r->l->head;
+ r->l->head = t;
+ if(r->l->tail == nil)
+ r->l->tail = t;
+
+ t->state = Queuing;
+ unlock(&r->l->lock);
+ return 1;
+}
+
+int
+rwakeupall(Rendez *r)
+{
+ int i;
+
+ for(i=0; rwakeup(r); i++)
+ ;
+ return i;
+}
+
+#endif
diff --git a/sys/src/ape/lib/ap/plan9/read.c b/sys/src/ape/lib/ap/plan9/read.c
new file mode 100755
index 000000000..471ab7e33
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/read.c
@@ -0,0 +1,46 @@
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include "lib.h"
+#include "sys9.h"
+
+#include <stdio.h>
+
+ssize_t
+read(int d, void *buf, size_t nbytes)
+{
+ int n, noblock, isbuf;
+ Fdinfo *f;
+
+ if(d<0 || d>=OPEN_MAX || !((f = &_fdinfo[d])->flags&FD_ISOPEN)){
+ errno = EBADF;
+ return -1;
+ }
+ if(nbytes <= 0)
+ return 0;
+ if(buf == 0){
+ errno = EFAULT;
+ return -1;
+ }
+ f = &_fdinfo[d];
+ noblock = f->oflags&O_NONBLOCK;
+ isbuf = f->flags&(FD_BUFFERED|FD_BUFFEREDX);
+ if(noblock || isbuf){
+ if(f->flags&FD_BUFFEREDX) {
+ errno = EIO;
+ return -1;
+ }
+ if(!isbuf) {
+ if(_startbuf(d) != 0) {
+ errno = EIO;
+ return -1;
+ }
+ }
+ n = _readbuf(d, buf, nbytes, noblock);
+ }else{
+ n = _READ(d, buf, nbytes);
+ if(n < 0)
+ _syserrno();
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/rename.c b/sys/src/ape/lib/ap/plan9/rename.c
new file mode 100755
index 000000000..dddfea328
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/rename.c
@@ -0,0 +1,76 @@
+#include "lib.h"
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+int
+rename(const char *from, const char *to)
+{
+ int n, i;
+ char *f, *t;
+ Dir *d, nd;
+ long mode;
+
+ if(access(to, 0) >= 0){
+ if(_REMOVE(to) < 0){
+ _syserrno();
+ return -1;
+ }
+ }
+ if((d = _dirstat(to)) != nil){
+ free(d);
+ errno = EEXIST;
+ return -1;
+ }
+ if((d = _dirstat(from)) == nil){
+ _syserrno();
+ return -1;
+ }
+ f = strrchr(from, '/');
+ t = strrchr(to, '/');
+ f = f? f+1 : from;
+ t = t? t+1 : to;
+ n = 0;
+ if(f-from==t-to && strncmp(from, to, f-from)==0){
+ /* from and to are in same directory (we miss some cases) */
+ i = strlen(t);
+ _nulldir(&nd);
+ nd.name = t;
+ if(_dirwstat(from, &nd) < 0){
+ _syserrno();
+ n = -1;
+ }
+ }else{
+ /* different directories: have to copy */
+ int ffd, tfd;
+ char buf[8192];
+
+ if((ffd = _OPEN(from, 0)) < 0 ||
+ (tfd = _CREATE(to, 1, d->mode)) < 0){
+ _CLOSE(ffd);
+ _syserrno();
+ n = -1;
+ }
+ while(n>=0 && (n = _READ(ffd, buf, 8192)) > 0)
+ if(_WRITE(tfd, buf, n) != n){
+ _syserrno();
+ n = -1;
+ }
+ _CLOSE(ffd);
+ _CLOSE(tfd);
+ if(n>0)
+ n = 0;
+ if(n == 0) {
+ if(_REMOVE(from) < 0){
+ _syserrno();
+ return -1;
+ }
+ }
+ }
+ free(d);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/rmdir.c b/sys/src/ape/lib/ap/plan9/rmdir.c
new file mode 100755
index 000000000..a799bc00b
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/rmdir.c
@@ -0,0 +1,17 @@
+#include "lib.h"
+#include <errno.h>
+#include <unistd.h>
+#include "sys9.h"
+
+int
+rmdir(const char *path)
+{
+ int n;
+
+ n = 0;
+ if(_REMOVE(path) < 0) {
+ _syserrno();
+ n = -1;
+ }
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/setgid.c b/sys/src/ape/lib/ap/plan9/setgid.c
new file mode 100755
index 000000000..7c9075c3f
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/setgid.c
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+/*
+ * BUG: never works
+ */
+
+int
+setgid(gid_t gid)
+{
+ errno = EPERM;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/setpgid.c b/sys/src/ape/lib/ap/plan9/setpgid.c
new file mode 100755
index 000000000..dd5445085
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/setpgid.c
@@ -0,0 +1,31 @@
+#include "lib.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include "sys9.h"
+
+int
+setpgid(pid_t pid, pid_t pgid)
+{
+ int n, f;
+ char buf[50], fname[30];
+
+ if(pid == 0)
+ pid = getpid();
+ if(pgid == 0)
+ pgid = getpgrp();
+ sprintf(fname, "/proc/%d/noteid", pid);
+ f = open(fname, 1);
+ if(f < 0) {
+ errno = ESRCH;
+ return -1;
+ }
+ n = sprintf(buf, "%d", pgid);
+ n = write(f, buf, n);
+ if(n < 0)
+ _syserrno();
+ else
+ n = 0;
+ close(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/setsid.c b/sys/src/ape/lib/ap/plan9/setsid.c
new file mode 100755
index 000000000..f53f8f2f3
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/setsid.c
@@ -0,0 +1,14 @@
+#include "lib.h"
+#include <unistd.h>
+#include "sys9.h"
+
+pid_t
+setsid(void)
+{
+ if(_RFORK(RFNAMEG|RFNOTEG) < 0){
+ _syserrno();
+ return -1;
+ }
+ _sessleader = 1;
+ return getpgrp();
+}
diff --git a/sys/src/ape/lib/ap/plan9/setuid.c b/sys/src/ape/lib/ap/plan9/setuid.c
new file mode 100755
index 000000000..a34f2de6f
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/setuid.c
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+/*
+ * BUG: never works
+ */
+
+int
+setuid(uid_t uid)
+{
+ errno = EPERM;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/signal.c b/sys/src/ape/lib/ap/plan9/signal.c
new file mode 100755
index 000000000..cf8a823ef
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/signal.c
@@ -0,0 +1,136 @@
+#include "lib.h"
+#include "sys9.h"
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <setjmp.h>
+
+extern sigset_t _psigblocked;
+
+static struct {
+ char *msg; /* just check prefix */
+ int num;
+} sigtab[] = {
+ {"hangup", SIGHUP},
+ {"interrupt", SIGINT},
+ {"quit", SIGQUIT},
+ {"alarm", SIGALRM},
+ {"sys: trap: illegal instruction", SIGILL},
+ {"sys: trap: reserved instruction", SIGILL},
+ {"sys: trap: reserved", SIGILL},
+ {"sys: trap: arithmetic overflow", SIGFPE},
+ {"abort", SIGABRT},
+ {"sys: fp:", SIGFPE},
+ {"exit", SIGKILL},
+ {"die", SIGKILL},
+ {"kill", SIGKILL},
+ {"sys: trap: bus error", SIGSEGV},
+ {"sys: trap: address error", SIGSEGV},
+ {"sys: trap: TLB", SIGSEGV},
+ {"sys: write on closed pipe", SIGPIPE},
+ {"alarm", SIGALRM},
+ {"term", SIGTERM},
+ {"usr1", SIGUSR1},
+ {"usr2", SIGUSR2},
+};
+#define NSIGTAB ((sizeof sigtab)/(sizeof (sigtab[0])))
+
+void (*_sighdlr[MAXSIG+1])(int, char*, Ureg*); /* 0 initialized: SIG_DFL */
+
+void
+(*signal(int sig, void (*func)(int, char*, Ureg*)))(int, char*, Ureg*)
+{
+ void(*oldf)(int, char*, Ureg*);
+
+ if(sig <= 0 || sig > MAXSIG){
+ errno = EINVAL;
+ return SIG_ERR;
+ }
+ oldf = _sighdlr[sig];
+ if(sig == SIGKILL)
+ return oldf; /* can't catch or ignore SIGKILL */
+ _sighdlr[sig] = func;
+ return oldf;
+}
+
+/* BAD CODE - see /sys/src/ape/lib/ap/$objtype/setjmp.s for real code
+int
+sigsetjmp(sigjmp_buf buf, int savemask)
+{
+ int r;
+
+ buf[0] = savemask;
+ buf[1] = _psigblocked;
+ return setjmp(&buf[2]);
+}
+*/
+
+/*
+ * BUG: improper handling of process signal mask
+ */
+int
+sigaction(int sig, struct sigaction *act, struct sigaction *oact)
+{
+ if(sig <= 0 || sig > MAXSIG || sig == SIGKILL){
+ errno = EINVAL;
+ return -1;
+ }
+ if(oact){
+ oact->sa_handler = _sighdlr[sig];
+ oact->sa_mask = _psigblocked;
+ oact->sa_flags = 0;
+ }
+ if(act){
+ _sighdlr[sig] = act->sa_handler;
+ }
+ return 0;
+}
+
+/* this is registered in _envsetup */
+int
+_notehandler(Ureg *u, char *msg)
+{
+ int i;
+ void(*f)(int, char*, Ureg*);
+ extern void _doatexits(void); /* in stdio/exit.c */
+
+ if(_finishing)
+ _finish(0, 0);
+ for(i = 0; i<NSIGTAB; i++){
+ if(strncmp(msg, sigtab[i].msg, strlen(sigtab[i].msg)) == 0){
+ f = _sighdlr[sigtab[i].num];
+ if(f == SIG_DFL || f == SIG_ERR)
+ break;
+ if(f != SIG_IGN) {
+ _notetramp(sigtab[i].num, f, u);
+ /* notetramp is machine-dependent; doesn't return to here */
+ }
+ _NOTED(0); /* NCONT */
+ return;
+ }
+ }
+ _doatexits();
+ _NOTED(1); /* NDFLT */
+}
+
+int
+_stringsig(char *nam)
+{
+ int i;
+
+ for(i = 0; i<NSIGTAB; i++)
+ if(strncmp(nam, sigtab[i].msg, strlen(sigtab[i].msg)) == 0)
+ return sigtab[i].num;
+ return 0;
+}
+
+char *
+_sigstring(int sig)
+{
+ int i;
+
+ for(i=0; i<NSIGTAB; i++)
+ if(sigtab[i].num == sig)
+ return sigtab[i].msg;
+ return "unknown signal";
+}
diff --git a/sys/src/ape/lib/ap/plan9/sigpending.c b/sys/src/ape/lib/ap/plan9/sigpending.c
new file mode 100755
index 000000000..8b5eb2eda
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/sigpending.c
@@ -0,0 +1,11 @@
+#include <signal.h>
+
+/*
+ * BUG: don't keep track of these
+ */
+int
+sigpending(sigset_t *set)
+{
+ *set = 0;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/sigprocmask.c b/sys/src/ape/lib/ap/plan9/sigprocmask.c
new file mode 100755
index 000000000..84b94f987
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/sigprocmask.c
@@ -0,0 +1,23 @@
+#include "lib.h"
+#include <signal.h>
+#include <errno.h>
+
+sigset_t _psigblocked;
+
+int
+sigprocmask(int how, sigset_t *set, sigset_t *oset)
+{
+ if(oset)
+ *oset = _psigblocked;
+ if(how==SIG_BLOCK)
+ _psigblocked |= *set;
+ else if(how==SIG_UNBLOCK)
+ _psigblocked &= ~*set;
+ else if(how==SIG_SETMASK)
+ _psigblocked = *set;
+ else{
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/sigsuspend.c b/sys/src/ape/lib/ap/plan9/sigsuspend.c
new file mode 100755
index 000000000..290c15d0f
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/sigsuspend.c
@@ -0,0 +1,13 @@
+#include <signal.h>
+#include <errno.h>
+
+/*
+ * BUG: doesn't work
+ */
+
+int
+sigsuspend(sigset_t *set)
+{
+ errno = EINVAL;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/sleep.c b/sys/src/ape/lib/ap/plan9/sleep.c
new file mode 100755
index 000000000..a6fcf19a9
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/sleep.c
@@ -0,0 +1,17 @@
+#include "lib.h"
+#include <unistd.h>
+#include <time.h>
+#include "sys9.h"
+
+unsigned int
+sleep(unsigned int secs)
+{
+ time_t t0, t1;
+
+ t0 = time(0);
+ if(_SLEEP(secs*1000) < 0){
+ t1 = time(0);
+ return t1-t0;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/sqrt.c b/sys/src/ape/lib/ap/plan9/sqrt.c
new file mode 100755
index 000000000..98974360d
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/sqrt.c
@@ -0,0 +1,56 @@
+/*
+ sqrt returns the square root of its floating
+ point argument. Newton's method.
+
+ calls frexp
+*/
+
+#include <math.h>
+#include <errno.h>
+#define _RESEARCH_SOURCE
+#include <float.h>
+
+double
+sqrt(double arg)
+{
+ double x, temp;
+ int exp, i;
+
+ if(isInf(arg, 1))
+ return arg;
+ if(arg <= 0) {
+ if(arg < 0)
+ errno = EDOM;
+ return 0;
+ }
+ x = frexp(arg, &exp);
+ while(x < 0.5) {
+ x *= 2;
+ exp--;
+ }
+ /*
+ * NOTE
+ * this wont work on 1's comp
+ */
+ if(exp & 1) {
+ x *= 2;
+ exp--;
+ }
+ temp = 0.5 * (1.0+x);
+
+ while(exp > 60) {
+ temp *= (1L<<30);
+ exp -= 60;
+ }
+ while(exp < -60) {
+ temp /= (1L<<30);
+ exp += 60;
+ }
+ if(exp >= 0)
+ temp *= 1L << (exp/2);
+ else
+ temp /= 1L << (-exp/2);
+ for(i=0; i<=4; i++)
+ temp = 0.5*(temp + arg/temp);
+ return temp;
+}
diff --git a/sys/src/ape/lib/ap/plan9/stat.c b/sys/src/ape/lib/ap/plan9/stat.c
new file mode 100755
index 000000000..be0d7c484
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/stat.c
@@ -0,0 +1,21 @@
+#include "lib.h"
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+int
+stat(const char *path, struct stat *buf)
+{
+ Dir *d;
+
+ if((d = _dirstat(path)) == nil){
+ _syserrno();
+ return -1;
+ }
+ _dirtostat(buf, d, 0);
+ free(d);
+
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/sys9.h b/sys/src/ape/lib/ap/plan9/sys9.h
new file mode 100755
index 000000000..b289273cb
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/sys9.h
@@ -0,0 +1,121 @@
+typedef
+struct Waitmsg
+{
+ int pid; /* of loved one */
+ unsigned long time[3]; /* of loved one & descendants */
+ char *msg;
+} Waitmsg;
+
+#define STATMAX 65535U /* max length of machine-independent stat structure */
+#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */
+#define ERRMAX 128 /* max length of error string */
+
+#define MORDER 0x0003 /* mask for bits defining order of mounting */
+#define MREPL 0x0000 /* mount replaces object */
+#define MBEFORE 0x0001 /* mount goes before others in union directory */
+#define MAFTER 0x0002 /* mount goes after others in union directory */
+#define MCREATE 0x0004 /* permit creation in mounted directory */
+#define MCACHE 0x0010 /* cache some data */
+#define MMASK 0x0007 /* all bits on */
+
+#define OREAD 0 /* open for read */
+#define OWRITE 1 /* write */
+#define ORDWR 2 /* read and write */
+#define OEXEC 3 /* execute, == read but check execute permission */
+#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
+#define OCEXEC 32 /* or'ed in, close on exec */
+#define ORCLOSE 64 /* or'ed in, remove on close */
+#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
+
+#define AEXIST 0 /* accessible: exists */
+#define AEXEC 1 /* execute access */
+#define AWRITE 2 /* write access */
+#define AREAD 4 /* read access */
+
+/* Segattch */
+#define SG_RONLY 0040 /* read only */
+#define SG_CEXEC 0100 /* detach on exec */
+
+#define NCONT 0 /* continue after note */
+#define NDFLT 1 /* terminate after note */
+#define NSAVE 2 /* clear note but hold state */
+#define NRSTR 3 /* restore saved state */
+
+/* bits in Qid.type */
+#define QTDIR 0x80 /* type bit for directories */
+#define QTAPPEND 0x40 /* type bit for append only files */
+#define QTEXCL 0x20 /* type bit for exclusive use files */
+#define QTMOUNT 0x10 /* type bit for mounted channel */
+#define QTFILE 0x00 /* plain file */
+
+/* bits in Dir.mode */
+#define DMDIR 0x80000000 /* mode bit for directories */
+#define DMAPPEND 0x40000000 /* mode bit for append only files */
+#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
+#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
+#define DMREAD 0x4 /* mode bit for read permission */
+#define DMWRITE 0x2 /* mode bit for write permission */
+#define DMEXEC 0x1 /* mode bit for execute permission */
+
+/* rfork */
+enum
+{
+ RFNAMEG = (1<<0),
+ RFENVG = (1<<1),
+ RFFDG = (1<<2),
+ RFNOTEG = (1<<3),
+ RFPROC = (1<<4),
+ RFMEM = (1<<5),
+ RFNOWAIT = (1<<6),
+ RFCNAMEG = (1<<10),
+ RFCENVG = (1<<11),
+ RFCFDG = (1<<12),
+ RFREND = (1<<13),
+ RFNOMNT = (1<<14)
+};
+
+extern int _AWAIT(char*, int);
+extern int _ALARM(unsigned long);
+extern int _BIND(const char*, const char*, int);
+extern int _CHDIR(const char*);
+extern int _CLOSE(int);
+extern int _CREATE(char*, int, unsigned long);
+extern int _DUP(int, int);
+extern int _ERRSTR(char*, unsigned int);
+extern int _EXEC(char*, char*[]);
+extern void _EXITS(char *);
+extern int _FD2PATH(int, char*, int);
+extern int _FAUTH(int, char*);
+extern int _FSESSION(int, char*, int);
+extern int _FSTAT(int, unsigned char*, int);
+extern int _FWSTAT(int, unsigned char*, int);
+extern int _MOUNT(int, int, const char*, int, const char*);
+extern int _NOTED(int);
+extern int _NOTIFY(int(*)(void*, char*));
+extern int _OPEN(const char*, int);
+extern int _PIPE(int*);
+extern long _PREAD(int, void*, long, long long);
+extern long _PWRITE(int, void*, long, long long);
+extern long _READ(int, void*, long);
+extern int _REMOVE(const char*);
+extern int _RENDEZVOUS(unsigned long, unsigned long);
+extern int _RFORK(int);
+extern int _SEGATTACH(int, char*, void*, unsigned long);
+extern int _SEGBRK(void*, void*);
+extern int _SEGDETACH(void*);
+extern int _SEGFLUSH(void*, unsigned long);
+extern int _SEGFREE(void*, unsigned long);
+extern long long _SEEK(int, long long, int);
+extern int _SLEEP(long);
+extern int _STAT(const char*, unsigned char*, int);
+extern Waitmsg* _WAIT(void);
+extern long _WRITE(int, const void*, long);
+extern int _WSTAT(const char*, unsigned char*, int);
+
+extern int __open(char *, int, ...);
+extern int __access(char *, int);
+extern int __chdir(char *);
+extern int __creat(char *, int);
+extern int __link(char *, int);
+extern int __stat(char *, struct stat *);
+extern int __unlink(char *);
diff --git a/sys/src/ape/lib/ap/plan9/system.c b/sys/src/ape/lib/ap/plan9/system.c
new file mode 100755
index 000000000..497b0e1f1
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/system.c
@@ -0,0 +1,40 @@
+#include "lib.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int
+system(const char *s)
+{
+ int w, status;
+ pid_t pid;
+ char cmd[30], *oty;
+
+ oty = getenv("cputype");
+ if(!oty)
+ return -1;
+ if(!s)
+ return 1; /* a command interpreter is available */
+ pid = fork();
+ snprintf(cmd, sizeof cmd, "/%s/bin/ape/sh", oty);
+ if(pid == 0) {
+ execl(cmd, "sh", "-c", s, NULL);
+ _exit(1);
+ }
+ if(pid < 0){
+ _syserrno();
+ return -1;
+ }
+ for(;;) {
+ w = wait(&status);
+ if(w == -1 || w == pid)
+ break;
+ }
+
+ if(w == -1){
+ _syserrno();
+ return w;
+ }
+ return status;
+}
diff --git a/sys/src/ape/lib/ap/plan9/tcgetattr.c b/sys/src/ape/lib/ap/plan9/tcgetattr.c
new file mode 100755
index 000000000..8a7d3e608
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/tcgetattr.c
@@ -0,0 +1,201 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "sys9.h"
+#include "lib.h"
+#include "dir.h"
+
+#define CESC '\\'
+#define CINTR 0177 /* DEL */
+#define CQUIT 034 /* FS, cntl | */
+#define CERASE 010 /* BS */
+#define CKILL 025 /* cntl u */
+#define CEOF 04 /* cntl d */
+#define CSTART 021 /* cntl q */
+#define CSTOP 023 /* cntl s */
+#define CSWTCH 032 /* cntl z */
+#define CEOL 000
+#define CNSWTCH 0
+
+static int
+isptty(int fd)
+{
+ Dir *d;
+ int rv;
+
+ if((d = _dirfstat(fd)) == nil)
+ return 0;
+ rv = (strncmp(d->name, "ptty", 4) == 0);
+ free(d);
+ return rv;
+}
+
+int
+tcgetattr(int fd, struct termios *t)
+{
+ int n;
+ char buf[60];
+
+ if(!isptty(fd)) {
+ if(isatty(fd)) {
+ /* If there is no emulation return sensible defaults */
+ t->c_iflag = ISTRIP|ICRNL|IXON|IXOFF;
+ t->c_oflag = OPOST|TAB3|ONLCR;
+ t->c_cflag = B9600;
+ t->c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
+ t->c_cc[VINTR] = CINTR;
+ t->c_cc[VQUIT] = CQUIT;
+ t->c_cc[VERASE] = CERASE;
+ t->c_cc[VKILL] = CKILL;
+ t->c_cc[VEOF] = CEOF;
+ t->c_cc[VEOL] = CEOL;
+ t->c_cc[VSTART] = CSTART;
+ t->c_cc[VSTOP] = CSTOP;
+ return 0;
+ } else {
+ errno = ENOTTY;
+ return -1;
+ }
+ }
+ if(_SEEK(fd, -2, 0) != -2) {
+ _syserrno();
+ return -1;
+ }
+
+ n = _READ(fd, buf, 57);
+ if(n < 0) {
+ _syserrno();
+ return -1;
+ }
+
+ t->c_iflag = strtoul(buf+4, 0, 16);
+ t->c_oflag = strtoul(buf+9, 0, 16);
+ t->c_cflag = strtoul(buf+14, 0, 16);
+ t->c_lflag = strtoul(buf+19, 0, 16);
+
+ for(n = 0; n < NCCS; n++)
+ t->c_cc[n] = strtoul(buf+24+(n*3), 0, 16);
+
+ return 0;
+}
+
+/* BUG: ignores optional actions */
+
+int
+tcsetattr(int fd, int optactions, const struct termios *t)
+{
+ int n, i;
+ char buf[100];
+
+ if(!isptty(fd)) {
+ if(!isatty(fd)) {
+ errno = ENOTTY;
+ return -1;
+ } else
+ return 0;
+ }
+ n = sprintf(buf, "IOW %4.4x %4.4x %4.4x %4.4x ",
+ t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag);
+
+ for(i = 0; i < NCCS; i++)
+ n += sprintf(buf+n, "%2.2x ", t->c_cc[i]);
+
+ if(_SEEK(fd, -2, 0) != -2) {
+ _syserrno();
+ return -1;
+ }
+
+ n = _WRITE(fd, buf, n);
+ if(n < 0) {
+ _syserrno();
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+tcsetpgrp(int fd, pid_t pgrpid)
+{
+ int n;
+ char buf[30];
+
+ if(!isptty(fd)) {
+ if(!isatty(fd)) {
+ errno = ENOTTY;
+ return -1;
+ } else
+ return 0;
+ }
+ n = sprintf(buf, "IOW note %d", pgrpid);
+
+ if(_SEEK(fd, -2, 0) != -2) {
+ _syserrno();
+ return -1;
+ }
+
+ n = _WRITE(fd, buf, n);
+ if(n < 0) {
+ _syserrno();
+ return -1;
+ }
+}
+
+pid_t
+tcgetpgrp(int fd)
+{
+ int n;
+ pid_t pgrp;
+ char buf[100];
+
+ if(!isptty(fd)) {
+ errno = ENOTTY;
+ return -1;
+ }
+ if(_SEEK(fd, -2, 0) != -2) {
+ _syserrno();
+ return -1;
+ }
+ n = _READ(fd, buf, sizeof(buf));
+ if(n < 0) {
+ _syserrno();
+ return -1;
+ }
+ pgrp = atoi(buf+24+(NCCS*3));
+ return pgrp;
+}
+
+/* should do a better job here */
+
+int
+tcdrain(int)
+{
+ errno = ENOTTY;
+ return -1;
+}
+
+int
+tcflush(int, int)
+{
+ errno = ENOTTY;
+ return -1;
+}
+
+int
+tcflow(int, int)
+{
+ errno = ENOTTY;
+ return -1;
+}
+
+int
+tcsendbreak(int)
+{
+ errno = ENOTTY;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/plan9/time.c b/sys/src/ape/lib/ap/plan9/time.c
new file mode 100755
index 000000000..85a1e72b2
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/time.c
@@ -0,0 +1,27 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "sys9.h"
+
+time_t
+time(time_t *tp)
+{
+ char b[20];
+ int f;
+ time_t t;
+
+ memset(b, 0, sizeof(b));
+ f = _OPEN("/dev/time", 0);
+ if(f >= 0) {
+ _PREAD(f, b, sizeof(b), 0);
+ _CLOSE(f);
+ }
+ t = atol(b);
+ if(tp)
+ *tp = t;
+ return t;
+}
diff --git a/sys/src/ape/lib/ap/plan9/times.c b/sys/src/ape/lib/ap/plan9/times.c
new file mode 100755
index 000000000..2d1e95c8c
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/times.c
@@ -0,0 +1,51 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/times.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+static
+char*
+skip(char *p)
+{
+
+ while(*p == ' ')
+ p++;
+ while(*p != ' ' && *p != 0)
+ p++;
+ return p;
+}
+
+clock_t
+times(struct tms *buf)
+{
+ char b[200], *p;
+ int f;
+ unsigned long r;
+
+ memset(b, 0, sizeof(b));
+ f = open("/dev/cputime", O_RDONLY);
+ if(f >= 0) {
+ lseek(f, SEEK_SET, 0);
+ read(f, b, sizeof(b));
+ close(f);
+ }
+ p = b;
+ if(buf)
+ buf->tms_utime = atol(p);
+ p = skip(p);
+ if(buf)
+ buf->tms_stime = atol(p);
+ p = skip(p);
+ r = atol(p);
+ if(buf){
+ p = skip(p);
+ buf->tms_cutime = atol(p);
+ p = skip(p);
+ buf->tms_cstime = atol(p);
+ }
+ return r;
+}
diff --git a/sys/src/ape/lib/ap/plan9/tmpfile.c b/sys/src/ape/lib/ap/plan9/tmpfile.c
new file mode 100755
index 000000000..c3ab5fd88
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/tmpfile.c
@@ -0,0 +1,44 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "sys9.h"
+#undef OPEN
+#include "../stdio/iolib.h"
+#include "lib.h"
+#include "dir.h"
+
+FILE *
+tmpfile(void){
+ FILE *f;
+ static char name[]="/tmp/tf0000000000000";
+ char *p;
+ int n;
+ for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++)
+ if(f->state==CLOSED)
+ break;
+ if(f==&_IO_stream[FOPEN_MAX])
+ return NULL;
+ while(access(name, 0) >= 0){
+ p = name+7;
+ while(*p == '9')
+ *p++ = '0';
+ if(*p == '\0')
+ return NULL;
+ ++*p;
+ }
+ n = _CREATE(name, 64|2, 0777); /* remove-on-close */
+ if(n==-1){
+ _syserrno();
+ return NULL;
+ }
+ _fdinfo[n].flags = FD_ISOPEN;
+ _fdinfo[n].oflags = 2;
+ f->fd=n;
+ f->flags=0;
+ f->state=OPEN;
+ f->buf=0;
+ f->rp=0;
+ f->wp=0;
+ f->lp=0;
+ return f;
+}
diff --git a/sys/src/ape/lib/ap/plan9/ttyname.c b/sys/src/ape/lib/ap/plan9/ttyname.c
new file mode 100755
index 000000000..980186a81
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/ttyname.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <stdio.h>
+
+char *
+ttyname(int fd)
+{
+ static char buf[100];
+
+ sprintf(buf, "/fd/%d", fd);
+ return buf;
+}
diff --git a/sys/src/ape/lib/ap/plan9/umask.c b/sys/src/ape/lib/ap/plan9/umask.c
new file mode 100755
index 000000000..b45b7576c
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/umask.c
@@ -0,0 +1,13 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+/*
+ * No such concept in plan9, but supposed to be always successful
+ */
+
+mode_t
+umask(mode_t numask)
+{
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/uname.c b/sys/src/ape/lib/ap/plan9/uname.c
new file mode 100755
index 000000000..1df2a941f
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/uname.c
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+int
+uname(struct utsname *n)
+{
+ n->sysname = getenv("osname");
+ if(!n->sysname)
+ n->sysname = "Plan9";
+ n->nodename = getenv("sysname");
+ if(!n->nodename){
+ n->nodename = getenv("site");
+ if(!n->nodename)
+ n->nodename = "?";
+ }
+ n->release = "4"; /* edition */
+ n->version = "0";
+ n->machine = getenv("cputype");
+ if(!n->machine)
+ n->machine = "?";
+ if(strcmp(n->machine, "386") == 0)
+ n->machine = "i386"; /* for gnu configure */
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/plan9/unlink.c b/sys/src/ape/lib/ap/plan9/unlink.c
new file mode 100755
index 000000000..a015c782f
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/unlink.c
@@ -0,0 +1,75 @@
+#include "lib.h"
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+
+/*
+ * BUG: errno mapping
+ */
+
+int
+unlink(const char *path)
+{
+ int n, i, fd;
+ long long nn;
+ Dir *db1, *db2, nd;
+ Fdinfo *f;
+ char *p, newname[PATH_MAX], newelem[32];
+
+ /* if the file is already open, make it close-on-exec (and rename to qid) */
+ if((db1 = _dirstat(path)) == nil) {
+ _syserrno();
+ return -1;
+ }
+ fd = -1;
+ for(i=0, f = _fdinfo;i < OPEN_MAX; i++, f++) {
+ if((f->flags&FD_ISOPEN) && (db2=_dirfstat(i)) != nil) {
+ if(db1->qid.path == db2->qid.path &&
+ db1->qid.vers == db2->qid.vers &&
+ db1->type == db2->type &&
+ db1->dev == db2->dev) {
+ sprintf(newelem, "%8.8lx%8.8lx", (ulong)(db2->qid.path>>32), (ulong)db2->qid.path);
+ _nulldir(&nd);
+ nd.name = newelem;
+ if(_dirfwstat(i, &nd) < 0)
+ p = (char*)path;
+ else {
+ p = strrchr(path, '/');
+ if(p == 0)
+ p = newelem;
+ else {
+ memmove(newname, path, p-path);
+ newname[p-path] = '/';
+ strcpy(newname+(p-path)+1, newelem);
+ p = newname;
+ }
+ }
+ /* reopen remove on close */
+ fd = _OPEN(p, 64|(f->oflags));
+ if(fd < 0){
+ free(db2);
+ continue;
+ }
+ nn = _SEEK(i, 0, 1);
+ if(nn < 0)
+ nn = 0;
+ _SEEK(fd, nn, 0);
+ _DUP(fd, i);
+ _CLOSE(fd);
+ free(db1);
+ return 0;
+ }
+ free(db2);
+ }
+ }
+ if(fd == -1)
+ if((n=_REMOVE(path)) < 0)
+ _syserrno();
+ free(db1);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/utime.c b/sys/src/ape/lib/ap/plan9/utime.c
new file mode 100755
index 000000000..52eeb34e2
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/utime.c
@@ -0,0 +1,30 @@
+#include "lib.h"
+#include <sys/types.h>
+#include <time.h>
+#include <utime.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "sys9.h"
+#include "dir.h"
+
+int
+utime(const char *path, const struct utimbuf *times)
+{
+ int n;
+ Dir nd;
+ time_t curt;
+
+ _nulldir(&nd);
+ if(times == 0) {
+ curt = time(0);
+ nd.atime = curt;
+ nd.mtime = curt;
+ } else {
+ nd.atime = times->actime;
+ nd.mtime = times->modtime;
+ }
+ n = _dirwstat(path, &nd);
+ if(n < 0)
+ _syserrno();
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/plan9/wait.c b/sys/src/ape/lib/ap/plan9/wait.c
new file mode 100755
index 000000000..ac1ab13da
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/wait.c
@@ -0,0 +1,150 @@
+#include "lib.h"
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "sys9.h"
+#include "dir.h"
+
+/*
+ * status not yet collected for processes that have exited
+ */
+typedef struct Waited Waited;
+struct Waited {
+ Waitmsg* msg;
+ Waited* next;
+};
+static Waited *wd;
+
+static Waitmsg *
+lookpid(int pid)
+{
+ Waited **wl, *w;
+ Waitmsg *msg;
+
+ for(wl = &wd; (w = *wl) != nil; wl = &w->next)
+ if(pid <= 0 || w->msg->pid == pid){
+ msg = w->msg;
+ *wl = w->next;
+ free(w);
+ return msg;
+ }
+ return 0;
+}
+
+static void
+addpid(Waitmsg *msg)
+{
+ Waited *w;
+
+ w = malloc(sizeof(*w));
+ if(w == nil){
+ /* lost it; what can we do? */
+ free(msg);
+ return;
+ }
+ w->msg = msg;
+ w->next = wd;
+ wd = w;
+}
+
+static int
+waitstatus(Waitmsg *w)
+{
+ int r, t;
+ char *bp, *ep;
+
+ r = 0;
+ t = 0;
+ if(w->msg[0]){
+ /* message is 'prog pid:string' */
+ bp = w->msg;
+ while(*bp){
+ if(*bp++ == ':')
+ break;
+ }
+ if(*bp == 0)
+ bp = w->msg;
+ r = strtol(bp, &ep, 10);
+ if(*ep == 0){
+ if(r < 0 || r >= 256)
+ r = 1;
+ }else{
+ t = _stringsig(bp);
+ if(t == 0)
+ r = 1;
+ }
+ }
+ return (r<<8) | t;
+}
+
+static void
+waitresource(struct rusage *ru, Waitmsg *w)
+{
+ memset(ru, 0, sizeof(*ru));
+ ru->ru_utime.tv_sec = w->time[0]/1000;
+ ru->ru_utime.tv_usec = (w->time[0]%1000)*1000;
+ ru->ru_stime.tv_sec = w->time[1]/1000;
+ ru->ru_stime.tv_usec = (w->time[1]%1000)*1000;
+}
+
+pid_t
+wait(int *status)
+{
+ return wait4(-1, status, 0, nil);
+}
+
+pid_t
+waitpid(pid_t wpid, int *status, int options)
+{
+ return wait4(wpid, status, options, nil);
+}
+
+pid_t
+wait3(int *status, int options, struct rusage *res)
+{
+ return wait4(-1, status, options, res);
+}
+
+pid_t
+wait4(pid_t wpid, int *status, int options, struct rusage *res)
+{
+ char pname[50];
+ Dir *d;
+ Waitmsg *w;
+
+ w = lookpid(wpid);
+ if(w == nil){
+ if(options & WNOHANG){
+ snprintf(pname, sizeof(pname), "/proc/%d/wait", getpid());
+ d = _dirstat(pname);
+ if(d != nil && d->length == 0){
+ free(d);
+ return 0;
+ }
+ free(d);
+ }
+ for(;;){
+ w = _WAIT();
+ if(w == nil){
+ _syserrno();
+ return -1;
+ }
+ if(wpid <= 0 || w->pid == wpid)
+ break;
+ addpid(w);
+ }
+ }
+ if(res != nil)
+ waitresource(res, w);
+ if(status != nil)
+ *status = waitstatus(w);
+ wpid = w->pid;
+ free(w);
+ return wpid;
+}
diff --git a/sys/src/ape/lib/ap/plan9/write.c b/sys/src/ape/lib/ap/plan9/write.c
new file mode 100755
index 000000000..6795bbc92
--- /dev/null
+++ b/sys/src/ape/lib/ap/plan9/write.c
@@ -0,0 +1,21 @@
+#include <errno.h>
+#include <unistd.h>
+#include "lib.h"
+#include "sys9.h"
+
+ssize_t
+write(int d, const void *buf, size_t nbytes)
+{
+ int n;
+
+ if(d<0 || d>=OPEN_MAX || !(_fdinfo[d].flags&FD_ISOPEN)){
+ errno = EBADF;
+ return -1;
+ }
+ if(_fdinfo[d].oflags&O_APPEND)
+ _SEEK(d, 0, 2);
+ n = _WRITE(d, buf, nbytes);
+ if(n < 0)
+ _syserrno();
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/posix/getgrent.c b/sys/src/ape/lib/ap/posix/getgrent.c
new file mode 100755
index 000000000..345ec2ed5
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/getgrent.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <grp.h>
+#include <stdlib.h>
+
+#define CL ':'
+#define CM ','
+#define NL '\n'
+#define MAXGRP 100
+
+static char GROUP[] = "/etc/group";
+static FILE *grf = NULL;
+static char line[BUFSIZ+1];
+static struct group group;
+static char *gr_mem[MAXGRP];
+
+setgrent()
+{
+ if( !grf )
+ grf = fopen( GROUP, "r" );
+ else
+ rewind( grf );
+}
+
+endgrent()
+{
+ if( grf ){
+ fclose( grf );
+ grf = NULL;
+ }
+}
+
+static char *
+grskip(register char *p, register c)
+{
+ while( *p && *p != c ) ++p;
+ if( *p ) *p++ = 0;
+ return( p );
+}
+
+struct group *
+getgrent()
+{
+ register char *p, **q;
+
+ if( !grf && !(grf = fopen( GROUP, "r" )) )
+ return(NULL);
+ if( !(p = fgets( line, BUFSIZ, grf )) )
+ return(NULL);
+ group.gr_name = p;
+ p = grskip(p,CL); /* passwd */
+ group.gr_gid = atoi(p = grskip(p,CL));
+ group.gr_mem = gr_mem;
+ p = grskip(p,CL);
+ grskip(p,NL);
+ q = gr_mem;
+ while( *p ){
+ *q++ = p;
+ p = grskip(p,CM);
+ }
+ *q = NULL;
+ return( &group );
+}
diff --git a/sys/src/ape/lib/ap/posix/getpwent.c b/sys/src/ape/lib/ap/posix/getpwent.c
new file mode 100755
index 000000000..779ae3a54
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/getpwent.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <pwd.h>
+#include <stdlib.h>
+
+static char PASSWD[] = "/etc/passwd";
+static FILE *pwf = NULL;
+static char line[BUFSIZ+2];
+static struct passwd passwd;
+
+void
+setpwent(void)
+{
+ if( pwf == NULL )
+ pwf = fopen( PASSWD, "r" );
+ else
+ rewind( pwf );
+}
+
+void
+endpwent(void)
+{
+ if( pwf != NULL ){
+ fclose( pwf );
+ pwf = NULL;
+ }
+}
+
+static char *
+pwskip(char *p)
+{
+ while( *p && *p != ':' && *p != '\n' )
+ ++p;
+ if( *p ) *p++ = 0;
+ else p[1] = 0;
+ return(p);
+}
+
+struct passwd *
+pwdecode(char *p)
+{
+ passwd.pw_name = p;
+ p = pwskip(p);
+ p = pwskip(p); /* passwd */
+ passwd.pw_uid = atoi(p);
+ p = pwskip(p);
+ passwd.pw_gid = atoi(p);
+ p = pwskip(p); /* comment */
+ p = pwskip(p); /* gecos */
+ passwd.pw_dir = p;
+ p = pwskip(p);
+ passwd.pw_shell = p;
+ p = pwskip(p);
+ return(&passwd);
+}
+
+struct passwd *
+getpwent(void)
+{
+ register char *p;
+
+ if (pwf == NULL) {
+ if( (pwf = fopen( PASSWD, "r" )) == NULL )
+ return(0);
+ }
+ p = fgets(line, BUFSIZ, pwf);
+ if (p==NULL)
+ return(0);
+ return pwdecode (p);
+}
diff --git a/sys/src/ape/lib/ap/posix/locale.c b/sys/src/ape/lib/ap/posix/locale.c
new file mode 100755
index 000000000..2468a3510
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/locale.c
@@ -0,0 +1,62 @@
+#include <locale.h>
+#include <limits.h>
+#include <string.h>
+
+static struct lconv Clocale = {
+ ".", /* decimal_point */
+ "", /* thousands_sep */
+ "", /* grouping */
+ "", /* int_curr_symbol */
+ "", /* currency_symbol */
+ "", /* mon_decimal_point */
+ "", /* mon_thousands_sep */
+ "", /* mon_grouping */
+ "", /* positive_sign */
+ "", /* negative_sign */
+ CHAR_MAX, /* int_frac_digits */
+ CHAR_MAX, /* frac_digits */
+ CHAR_MAX, /* p_cs_precedes */
+ CHAR_MAX, /* p_sep_by_space */
+ CHAR_MAX, /* n_cs_precedes */
+ CHAR_MAX, /* n_sep_by_space */
+ CHAR_MAX, /* p_sign_posn */
+ CHAR_MAX, /* n_sign_posn */
+};
+
+static char *localename[2] = {"C", ""};
+static short catlocale[6] = {0, 0, 0, 0, 0, 0};
+ /* indices into localename for categories LC_ALL, LC_COLLATE, etc. */
+
+#define ASIZE(a) (sizeof(a)/sizeof(a[0]))
+
+char *
+setlocale(int category, const char *locale)
+{
+ int c, i;
+
+ if(category < 0 || category >= ASIZE(catlocale))
+ return 0;
+ if(!locale)
+ return localename[catlocale[category]];
+ for(c=0; c<ASIZE(localename); c++)
+ if(strcmp(locale, localename[c]) == 0)
+ break;
+ if(c >= ASIZE(localename))
+ return 0;
+ catlocale[category] = c;
+ if(category == LC_ALL)
+ for(i=0; i<ASIZE(catlocale); i++)
+ catlocale[i] = c;
+ return localename[c];
+}
+
+struct lconv *
+localeconv(void)
+{
+ /* BUG: posix says look at environment variables
+ * to set locale "", but we just make it the same
+ * as C, always.
+ */
+ return &Clocale;
+}
+
diff --git a/sys/src/ape/lib/ap/posix/mkfifo.c b/sys/src/ape/lib/ap/posix/mkfifo.c
new file mode 100755
index 000000000..7dbc8f5b6
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/mkfifo.c
@@ -0,0 +1,12 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+int
+mkfifo(char *path, mode_t mode)
+{
+#pragma ref path
+#pragma ref mode
+ errno = 0;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/posix/mkfile b/sys/src/ape/lib/ap/posix/mkfile
new file mode 100755
index 000000000..268a991d0
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/mkfile
@@ -0,0 +1,16 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ getgrent.$O\
+ getpwent.$O\
+ locale.$O\
+ mkfifo.$O\
+ pathconf.$O\
+ sigset.$O\
+ sysconf.$O\
+ tzset.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE
diff --git a/sys/src/ape/lib/ap/posix/pathconf.c b/sys/src/ape/lib/ap/posix/pathconf.c
new file mode 100755
index 000000000..9fdf47684
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/pathconf.c
@@ -0,0 +1,55 @@
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/limits.h>
+
+long
+pathconf(const char *path, int name)
+{
+#pragma ref path
+
+ switch(name)
+ {
+ case _PC_LINK_MAX:
+ return LINK_MAX;
+ case _PC_MAX_CANON:
+ return MAX_CANON;
+ case _PC_MAX_INPUT:
+ return MAX_INPUT;
+ case _PC_NAME_MAX:
+ return NAME_MAX;
+ case _PC_PATH_MAX:
+ return PATH_MAX;
+ case _PC_PIPE_BUF:
+ return PIPE_BUF;
+ case _PC_CHOWN_RESTRICTED:
+#ifdef _POSIX_CHOWN_RESTRICTED
+ return _POSIX_CHOWN_RESTRICTED;
+#else
+ return -1;
+#endif
+ case _PC_NO_TRUNC:
+#ifdef _POSIX_NO_TRUNC
+ return _POSIX_NO_TRUNC;
+#else
+ return -1;
+#endif
+ case _PC_VDISABLE:
+#ifdef _POSIX_VDISABLE
+ return _POSIX_VDISABLE;
+#else
+ return -1;
+#endif
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+long
+fpathconf(int fd, int name)
+{
+#pragma ref fd
+
+ return pathconf(0, name);
+}
+
diff --git a/sys/src/ape/lib/ap/posix/sigset.c b/sys/src/ape/lib/ap/posix/sigset.c
new file mode 100755
index 000000000..1a9ef12aa
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/sigset.c
@@ -0,0 +1,67 @@
+#include <signal.h>
+#include <errno.h>
+
+/*
+ * sigsets are 32-bit longs. if the 2<<(i-1) bit is on,
+ * the signal #define'd as i in signal.h is inluded.
+ */
+
+static sigset_t stdsigs = SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGABRT|SIGFPE|SIGKILL|
+ SIGSEGV|SIGPIPE|SIGALRM|SIGTERM|SIGUSR1|SIGUSR2;
+
+#define BITSIG(s) (2<<(s))
+
+int
+sigemptyset(sigset_t *set)
+{
+ *set = 0;
+ return 0;
+}
+
+int
+sigfillset(sigset_t *set)
+{
+ *set = stdsigs;
+ return 0;
+}
+
+int
+sigaddset(sigset_t *set, int signo)
+{
+ int b;
+
+ b = BITSIG(signo);
+ if(!(b&stdsigs)){
+ errno = EINVAL;
+ return -1;
+ }
+ *set |= b;
+ return 0;
+}
+
+int
+sigdelset(sigset_t *set, int signo)
+{
+ int b;
+
+ b = BITSIG(signo);
+ if(!(b&stdsigs)){
+ errno = EINVAL;
+ return -1;
+ }
+ *set &= ~b;
+ return 0;
+}
+
+int
+sigismember(sigset_t *set, int signo)
+{
+ int b;
+
+ b = BITSIG(signo);
+ if(!(b&stdsigs)){
+ errno = EINVAL;
+ return -1;
+ }
+ return (b&*set)? 1 : 0;
+}
diff --git a/sys/src/ape/lib/ap/posix/sysconf.c b/sys/src/ape/lib/ap/posix/sysconf.c
new file mode 100755
index 000000000..cd7adaaab
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/sysconf.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/limits.h>
+
+long
+sysconf(int name)
+{
+ switch(name)
+ {
+ case _SC_ARG_MAX:
+ return ARG_MAX;
+ case _SC_CHILD_MAX:
+ return CHILD_MAX;
+ case _SC_CLK_TCK:
+ return CLOCKS_PER_SEC;
+ case _SC_NGROUPS_MAX:
+ return NGROUPS_MAX;
+ case _SC_OPEN_MAX:
+ return OPEN_MAX;
+ case _SC_JOB_CONTROL:
+#ifdef _POSIX_JOB_CONTROL
+ return _POSIX_JOB_CONTROL;
+#else
+ return -1;
+#endif
+ case _SC_SAVED_IDS:
+#ifdef _POSIX_SAVED_IDS
+ return _POSIX_SAVED_IDS;
+#else
+ return -1;
+#endif
+ case _SC_VERSION:
+ return _POSIX_VERSION;
+ case _SC_LOGIN_NAME_MAX:
+ return L_cuserid;
+ }
+ errno = EINVAL;
+ return -1;
+}
diff --git a/sys/src/ape/lib/ap/posix/tzset.c b/sys/src/ape/lib/ap/posix/tzset.c
new file mode 100755
index 000000000..8502c6d66
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/tzset.c
@@ -0,0 +1,141 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+#define TZFILE "/etc/TZ"
+
+static char TZ[128];
+static char std[32] = "GMT0";
+static char dst[32];
+char *tzname[2] = {
+ std, dst
+};
+time_t tzoffset, tzdstoffset;
+int tzdst = 0;
+
+static int
+offset(char *env, time_t *off)
+{
+ int n, sign;
+ size_t len, retlen;
+
+ retlen = 0;
+ sign = 1;
+ /*
+ * strictly, no sign is allowed in the 'time' part of the
+ * dst start/stop rules, but who cares?
+ */
+ if (*env == '-' || *env == '+') {
+ if (*env++ == '-')
+ sign = -1;
+ retlen++;
+ }
+ if ((len = strspn(env, ":0123456789")) == 0)
+ return 0;
+ retlen += len;
+ for (*off = 0; len && isdigit(*env); len--) /* hours */
+ *off = *off*10 + (*env++ - '0')*60*60;
+ if (len) {
+ if (*env++ != ':')
+ return 0;
+ len--;
+ }
+ for (n = 0; len && isdigit(*env); len--) /* minutes */
+ n = n*10 + (*env++ - '0')*60;
+ *off += n;
+ if (len) {
+ if (*env++ != ':')
+ return 0;
+ len--;
+ }
+ for (n = 0; len && isdigit(*env); len--) /* seconds */
+ n = n*10 + (*env++ - '0');
+ *off = (*off + n)*sign;
+ return retlen;
+}
+
+/*
+ * TZ=stdoffset[dst[offset][,start[/time],end[/time]]]
+ */
+void
+tzset(void)
+{
+ char *env, *p, envbuf[128];
+ int fd, i;
+ size_t len, retlen;
+ time_t off;
+
+ /*
+ * get the TZ environment variable and check for validity.
+ * the implementation-defined manner for dealing with the
+ * leading ':' format is to reject it.
+ * if it's ok, stash a copy away for quick comparison next time.
+ */
+ if ((env = getenv("TZ")) == 0) {
+ if ((fd = open(TZFILE, O_RDONLY)) == -1)
+ return;
+ if (read(fd, envbuf, sizeof(envbuf)-1) == -1) {
+ close(fd);
+ return;
+ }
+ close(fd);
+ for (i = 0; i < sizeof(envbuf); i++) {
+ if (envbuf[i] != '\n')
+ continue;
+ envbuf[i] = '\0';
+ break;
+ }
+ env = envbuf;
+ }
+ if (strcmp(env, TZ) == 0)
+ return;
+ if (*env == 0 || *env == ':')
+ return;
+ strncpy(TZ, env, sizeof(TZ)-1);
+ TZ[sizeof(TZ)-1] = 0;
+ /*
+ * get the 'std' string.
+ * before committing, check there is a valid offset.
+ */
+ if ((len = strcspn(env, ":0123456789,-+")) == 0)
+ return;
+ if ((retlen = offset(env+len, &off)) == 0)
+ return;
+ for (p = std, i = len+retlen; i; i--)
+ *p++ = *env++;
+ *p = 0;
+ tzoffset = -off;
+ /*
+ * get the 'dst' string (if any).
+ */
+ if (*env == 0 || (len = strcspn(env, ":0123456789,-+")) == 0)
+ return;
+ for (p = dst; len; len--)
+ *p++ = *env++;
+ *p = 0;
+ /*
+ * optional dst offset.
+ * default is one hour.
+ */
+ tzdst = 1;
+ if (retlen = offset(env+len, &off)) {
+ tzdstoffset = -off;
+ env += retlen;
+ }
+ else
+ tzdstoffset = tzoffset + 60*60;
+ /*
+ * optional rule(s) for start/end of dst.
+ */
+ if (*env == 0 || *env != ',' || *(env+1) == 0)
+ return;
+ env++;
+ /*
+ * we could go on...
+ * but why bother?
+ */
+}
diff --git a/sys/src/ape/lib/ap/power/cycles.s b/sys/src/ape/lib/ap/power/cycles.s
new file mode 100755
index 000000000..b4ad52367
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/cycles.s
@@ -0,0 +1,17 @@
+#define TBRL 268
+#define TBRU 269 /* Time base Upper/Lower (Reading) */
+
+/*
+ * time stamp counter; _cycles since power up
+ * Runs at fasthz/4 cycles per second (m->clkin>>3)
+ */
+TEXT _cycles(SB),1,$0
+loop:
+ MOVW SPR(TBRU),R7
+ MOVW SPR(TBRL),R8
+ MOVW SPR(TBRU),R5
+ CMP R5,R7
+ BNE loop
+ MOVW R7,0(R3)
+ MOVW R8,4(R3)
+ RETURN
diff --git a/sys/src/ape/lib/ap/power/getfcr.s b/sys/src/ape/lib/ap/power/getfcr.s
new file mode 100755
index 000000000..b61d52e68
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/getfcr.s
@@ -0,0 +1,28 @@
+TEXT getfcr(SB), $8
+ MOVFL FPSCR, F3
+ FMOVD F3, f-8(SP)
+ MOVW -4(SP), R3
+ RETURN
+
+TEXT getfsr(SB), $8
+ MOVFL FPSCR, F3
+ FMOVD F3, f-8(SP)
+ MOVW -4(SP), R3
+ RETURN
+
+TEXT setfcr(SB), $8
+ SYNC
+ MOVW R3, -4(SP)
+ FMOVD -8(SP), F3
+ MOVFL F3, FPSCR
+ ISYNC
+ RETURN
+
+TEXT setfsr(SB), $8
+ SYNC
+ MOVW R3, -4(SP)
+ FMOVD -8(SP), F3
+ MOVFL F3, FPSCR
+ ISYNC
+ RETURN
+
diff --git a/sys/src/ape/lib/ap/power/lock.c b/sys/src/ape/lib/ap/power/lock.c
new file mode 100755
index 000000000..0d17c34d5
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/lock.c
@@ -0,0 +1,45 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#define _LOCK_EXTENSION
+#include <lock.h>
+
+int tas(int*);
+
+void
+lock(Lock *lk)
+{
+ int i;
+
+ /* once fast */
+ if(!tas(&lk->val))
+ return;
+ /* a thousand times pretty fast */
+ for(i=0; i<1000; i++){
+ if(!tas(&lk->val))
+ return;
+ _SLEEP(0);
+ }
+ /* now nice and slow */
+ for(i=0; i<1000; i++){
+ if(!tas(&lk->val))
+ return;
+ _SLEEP(100);
+ }
+ /* take your time */
+ while(tas(&lk->val))
+ _SLEEP(1000);
+}
+
+int
+canlock(Lock *lk)
+{
+ if(tas(&lk->val))
+ return 0;
+ return 1;
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
diff --git a/sys/src/ape/lib/ap/power/main9.s b/sys/src/ape/lib/ap/power/main9.s
new file mode 100755
index 000000000..ee493f5a8
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/main9.s
@@ -0,0 +1,14 @@
+TEXT _main(SB), 1, $16
+
+ MOVW $setSB(SB), R2
+
+ BL _envsetup(SB)
+ MOVW inargc-4(FP), R3
+ MOVW $inargv+0(FP), R4
+ MOVW R3, 4(R1)
+ MOVW R4, 8(R1)
+ BL main(SB)
+loop:
+ MOVW R3, 4(R1)
+ BL exit(SB)
+ BR loop
diff --git a/sys/src/ape/lib/ap/power/main9p.s b/sys/src/ape/lib/ap/power/main9p.s
new file mode 100755
index 000000000..865616980
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/main9p.s
@@ -0,0 +1,46 @@
+#define NPRIVATES 16
+
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
+
+TEXT _mainp(SB), 1, $(3*4+NPRIVATES*4)
+
+ MOVW $setSB(SB), R2
+
+ /* _tos = arg */
+ MOVW R3, _tos(SB)
+ MOVW $8(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ /* _profmain(); */
+ BL _envsetup(SB)
+
+ /* _tos->prof.pp = _tos->prof.next; */
+ MOVW _tos+0(SB),R1
+ MOVW 4(R1),R2
+ MOVW R2,(R1)
+
+ /* main(argc, argv, environ); */
+ MOVW inargc-4(FP), R3
+ MOVW $inargv+0(FP), R4
+ MOVW environ(SB), R5
+ MOVW R3, 4(R1)
+ MOVW R4, 8(R1)
+ MOVW R5, 12(R1)
+ BL main(SB)
+loop:
+ MOVW R3, 4(R1)
+ BL exit(SB)
+ MOVW $_profin(SB), R4 /* force loading of profile */
+ BR loop
+
+TEXT _savearg(SB), 1, $0
+ RETURN
+
+TEXT _callpc(SB), 1, $0
+ MOVW argp+0(FP), R3
+ MOVW 4(R3), R3
+ RETURN
diff --git a/sys/src/ape/lib/ap/power/memcmp.s b/sys/src/ape/lib/ap/power/memcmp.s
new file mode 100755
index 000000000..f524fa9d3
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/memcmp.s
@@ -0,0 +1,110 @@
+ TEXT memcmp(SB), $0
+#define BDNZ BC 16,0,
+ MOVW R3, s1+0(FP) /* R3 is pointer1 */
+
+/*
+ * performance:
+ * 67mb/sec aligned; 16mb/sec unaligned
+ */
+
+ MOVW n+8(FP), R4 /* R4 is count */
+ MOVW s2+4(FP), R5 /* R5 is pointer2 */
+
+/*
+ * let LSW do the work for 4 characters or less; aligned and unaligned
+ */
+ CMP R4, $0
+ BLE eq
+ CMP R4, $4
+ BLE out
+
+ XOR R3, R5, R9
+ ANDCC $3, R9
+ BNE l4 /* pointers misaligned; use LSW loop */
+
+/*
+ * do enough bytes to align pointers
+ */
+ ANDCC $3,R3, R9
+ BEQ l2
+ SUBC R9, $4, R9
+ MOVW R9, XER
+ LSW (R3), R10
+ ADD R9, R3
+ LSW (R5), R14
+ ADD R9, R5
+ SUB R9, R4
+ CMPU R10, R14
+ BNE ne
+
+/*
+ * compare 16 at a time
+ */
+l2:
+ SRAWCC $4, R4, R9
+ BLE l4
+ MOVW R9, CTR
+ SUB $4, R3
+ SUB $4, R5
+l3:
+ MOVWU 4(R3), R10
+ MOVWU 4(R5), R12
+ MOVWU 4(R3), R11
+ MOVWU 4(R5), R13
+ CMPU R10, R12
+ BNE ne
+ MOVWU 4(R3), R10
+ MOVWU 4(R5), R12
+ CMPU R11, R13
+ BNE ne
+ MOVWU 4(R3), R11
+ MOVWU 4(R5), R13
+ CMPU R10, R12
+ BNE ne
+ CMPU R11, R13
+ BNE ne
+ BDNZ l3
+ ADD $4, R3
+ ADD $4, R5
+ RLWNMCC $0, R4, $15, R4 /* residue */
+ BEQ eq
+
+/*
+ * do remaining words with LSW; also does unaligned case
+ */
+l4:
+ SRAWCC $2, R4, R9
+ BLE out
+ MOVW R9, CTR
+l5:
+ LSW (R3), $4, R10
+ ADD $4, R3
+ LSW (R5), $4, R11
+ ADD $4, R5
+ CMPU R10, R11
+ BNE ne
+ BDNZ l5
+ RLWNMCC $0, R4, $3, R4 /* residue */
+ BEQ eq
+
+/*
+ * do remaining bytes with final LSW
+ */
+out:
+ MOVW R4, XER
+ LSW (R3), R10
+ LSW (R5), R11
+ CMPU R10, R11
+ BNE ne
+
+eq:
+ MOVW $0, R3
+ RETURN
+
+ne:
+ MOVW $1, R3
+ BGE ret
+ MOVW $-1,R3
+ret:
+ RETURN
+ END
diff --git a/sys/src/ape/lib/ap/power/memmove.s b/sys/src/ape/lib/ap/power/memmove.s
new file mode 100755
index 000000000..dd6167d7d
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/memmove.s
@@ -0,0 +1,170 @@
+#define BDNZ BC 16,0,
+ TEXT memmove(SB), $0
+ BR move
+
+ TEXT memcpy(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+ MOVW R3, s1+0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW R3, R10 /* R10 is to-pointer */
+ CMP R9, $0
+ BEQ ret
+ BLT trap
+ MOVW s2+4(FP), R11 /* R11 is from-pointer */
+
+/*
+ * if no more than 16 bytes, just use one lsw/stsw
+ */
+ CMP R9, $16
+ BLE fout
+
+ ADD R9,R11, R13 /* R13 is end from-pointer */
+ ADD R9,R10, R12 /* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ CMPU R10, R11
+ BGT back
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R10,R11, R7
+ ANDCC $3,R7
+ BNE fbad
+
+/*
+ * move a few bytes to align pointers
+ */
+ ANDCC $3,R10,R7
+ BEQ f2
+ SUBC R7, $4, R7
+ SUB R7, R9
+ MOVW R7, XER
+ LSW (R11), R16
+ ADD R7, R11
+ STSW R16, (R10)
+ ADD R7, R10
+
+/*
+ * turn R14 into doubleword count
+ * copy 16 bytes at a time while there's room.
+ */
+f2:
+ SRAWCC $4, R9, R14
+ BLE fout
+ MOVW R14, CTR
+ SUB $4, R11
+ SUB $4, R10
+f3:
+ MOVWU 4(R11), R16
+ MOVWU R16, 4(R10)
+ MOVWU 4(R11), R17
+ MOVWU R17, 4(R10)
+ MOVWU 4(R11), R16
+ MOVWU R16, 4(R10)
+ MOVWU 4(R11), R17
+ MOVWU R17, 4(R10)
+ BDNZ f3
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+ ADD $4, R11
+ ADD $4, R10
+
+/*
+ * move up to 16 bytes through R16 .. R19; aligned and unaligned
+ */
+fout:
+ MOVW R9, XER
+ LSW (R11), R16
+ STSW R16, (R10)
+ BR ret
+
+/*
+ * loop for unaligned copy, then copy up to 15 remaining bytes
+ */
+fbad:
+ SRAWCC $4, R9, R14
+ BLE f6
+ MOVW R14, CTR
+f5:
+ LSW (R11), $16, R16
+ ADD $16, R11
+ STSW R16, $16, (R10)
+ ADD $16, R10
+ BDNZ f5
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+f6:
+ MOVW R9, XER
+ LSW (R11), R16
+ STSW R16, (R10)
+ BR ret
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ CMP R9, $4
+ BLT bout
+
+ XOR R12,R13, R7
+ ANDCC $3,R7
+ BNE bout
+b1:
+ ANDCC $3,R13, R7
+ BEQ b2
+ MOVBZU -1(R13), R16
+ MOVBZU R16, -1(R12)
+ SUB $1, R9
+ BR b1
+b2:
+ SRAWCC $4, R9, R14
+ BLE b4
+ MOVW R14, CTR
+b3:
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ MOVWU -4(R13), R17
+ MOVWU R17, -4(R12)
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ MOVWU -4(R13), R17
+ MOVWU R17, -4(R12)
+ BDNZ b3
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+b4:
+ SRAWCC $2, R9, R14
+ BLE bout
+ MOVW R14, CTR
+b5:
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ BDNZ b5
+ RLWNMCC $0, R9, $3, R9 /* residue */
+ BEQ ret
+
+bout:
+ CMPU R13, R11
+ BLE ret
+ MOVBZU -1(R13), R16
+ MOVBZU R16, -1(R12)
+ BR bout
+
+trap:
+ MOVW $0, R0
+ MOVW 0(R0), R0
+
+ret:
+ MOVW s1+0(FP), R3
+ RETURN
diff --git a/sys/src/ape/lib/ap/power/memset.s b/sys/src/ape/lib/ap/power/memset.s
new file mode 100755
index 000000000..fa6e8d920
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/memset.s
@@ -0,0 +1,73 @@
+ TEXT memset(SB),$0
+#define BDNZ BC 16,0,
+ MOVW R3, p+0(FP) /* R3 is pointer */
+
+/*
+ * performance:
+ * about 100mbytes/sec (8k blocks) on a 603/105 without L2 cache
+ * drops to 40mbytes/sec (10k blocks) and 28mbytes/sec with 32k blocks
+ */
+
+ MOVW n+8(FP), R4 /* R4 is count */
+ CMP R4, $0
+ BLE ret
+ MOVW c+4(FP), R5 /* R5 is char */
+
+/*
+ * create 16 copies of c in R5 .. R8
+ */
+ RLWNM $0, R5, $0xff, R5
+ RLWMI $8, R5, $0xff00, R5
+ RLWMI $16, R5, $0xffff0000, R5
+ MOVW R5, R6
+ MOVW R5, R7
+ MOVW R5, R8
+
+/*
+ * let STSW do the work for 16 characters or less; aligned and unaligned
+ */
+ CMP R4, $16
+ BLE out
+
+/*
+ * store enough bytes to align pointer
+ */
+ ANDCC $7,R3, R9
+ BEQ l2
+ SUBC R9, $8, R9
+ MOVW R9, XER
+ STSW R5, (R3)
+ ADD R9, R3
+ SUB R9, R4
+
+/*
+ * store 16 at a time while there's room
+ * STSW was used here originally, but it's `completion serialised'
+ */
+l2:
+ SRAWCC $4, R4, R9
+ BLE out
+ MOVW R9, CTR
+l3:
+ MOVW R5, 0(R3)
+ ADD $8, R3, R10
+ MOVW R6, 4(R3)
+ MOVW R7, 0(R10)
+ ADD $8, R10, R3
+ MOVW R8, 4(R10)
+ BDNZ l3
+ RLWNMCC $0, R4, $15, R4 /* residue */
+ BEQ ret
+
+/*
+ * store up to 16 bytes from R5 .. R8; aligned and unaligned
+ */
+
+out:
+ MOVW R4, XER
+ STSW R5, (R3)
+
+ret:
+ MOVW 0(FP), R3
+ RETURN
+ END
diff --git a/sys/src/ape/lib/ap/power/mkfile b/sys/src/ape/lib/ap/power/mkfile
new file mode 100755
index 000000000..cc546cd84
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/mkfile
@@ -0,0 +1,23 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ cycles.$O\
+ getfcr.$O\
+ lock.$O\
+ main9.$O\
+ main9p.$O\
+ memcmp.$O\
+ memmove.$O\
+ memset.$O\
+ notetramp.$O\
+ setjmp.$O\
+ strcmp.$O\
+ tas.$O\
+ vlop.$O\
+ vlrt.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE
+
diff --git a/sys/src/ape/lib/ap/power/notetramp.c b/sys/src/ape/lib/ap/power/notetramp.c
new file mode 100755
index 000000000..6477e1b14
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/notetramp.c
@@ -0,0 +1,72 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#include <signal.h>
+#include <setjmp.h>
+
+/* A stack to hold pcs when signals nest */
+#define MAXSIGSTACK 20
+typedef struct Pcstack Pcstack;
+static struct Pcstack {
+ int sig;
+ void (*hdlr)(int, char*, Ureg*);
+ unsigned long restorepc;
+ Ureg *u;
+} pcstack[MAXSIGSTACK];
+static int nstack = 0;
+
+static void notecont(Ureg*, char*);
+
+void
+_notetramp(int sig, void (*hdlr)(int, char*, Ureg*), Ureg *u)
+{
+ Pcstack *p;
+
+ if(nstack >= MAXSIGSTACK)
+ _NOTED(1); /* nesting too deep; just do system default */
+ p = &pcstack[nstack];
+ p->restorepc = u->pc;
+ p->sig = sig;
+ p->hdlr = hdlr;
+ p->u = u;
+ nstack++;
+ u->pc = (unsigned long) notecont;
+ _NOTED(2); /* NSAVE: clear note but hold state */
+}
+
+static void
+notecont(Ureg *u, char *s)
+{
+ Pcstack *p;
+ void(*f)(int, char*, Ureg*);
+
+ p = &pcstack[nstack-1];
+ f = p->hdlr;
+ u->pc = p->restorepc;
+ nstack--;
+ (*f)(p->sig, s, u);
+ _NOTED(3); /* NRSTR */
+}
+
+#define JMPBUFPC 1
+#define JMPBUFSP 0
+
+extern sigset_t _psigblocked;
+
+void
+siglongjmp(sigjmp_buf j, int ret)
+{
+ struct Ureg *u;
+
+ if(j[0])
+ _psigblocked = j[1];
+ if(nstack == 0 || pcstack[nstack-1].u->sp > j[2+JMPBUFSP])
+ longjmp(j+2, ret);
+ u = pcstack[nstack-1].u;
+ nstack--;
+ u->r3 = ret;
+ if(ret == 0)
+ u->r3 = 1;
+ u->pc = j[2+JMPBUFPC];
+ u->sp = j[2+JMPBUFSP];
+ _NOTED(3); /* NRSTR */
+}
diff --git a/sys/src/ape/lib/ap/power/setjmp.s b/sys/src/ape/lib/ap/power/setjmp.s
new file mode 100755
index 000000000..0023afcf2
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/setjmp.s
@@ -0,0 +1,37 @@
+TEXT setjmp(SB), 1, $-4
+ MOVW LR, R4
+ MOVW R1, (R3)
+ MOVW R4, 4(R3)
+ MOVW $0, R3
+ RETURN
+
+TEXT sigsetjmp(SB), 1, $-4
+ MOVW savemask+4(FP), R4
+ MOVW R4, 0(R3)
+ MOVW $_psigblocked(SB), R4
+ MOVW R4, 4(R3)
+ MOVW LR, R4
+ MOVW R1, 8(R3)
+ MOVW R4, 12(R3)
+ MOVW $0, R3
+ RETURN
+
+TEXT longjmp(SB), 1, $-4
+ MOVW R3, R4
+ MOVW r+4(FP), R3
+ CMP R3, $0
+ BNE ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVW $1, R3 /* bless their pointed heads */
+ok: MOVW (R4), R1
+ MOVW 4(R4), R4
+ MOVW R4, LR
+ BR (LR)
+
+/*
+ * trampoline functions because the kernel smashes r1
+ * in the uregs given to notejmp
+ */
+TEXT __noterestore(SB), 1, $-4
+ MOVW R4, R3
+ MOVW R5, LR
+ BR (LR)
diff --git a/sys/src/ape/lib/ap/power/strcmp.s b/sys/src/ape/lib/ap/power/strcmp.s
new file mode 100755
index 000000000..0aef5b29c
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/strcmp.s
@@ -0,0 +1,21 @@
+TEXT strcmp(SB), $0
+
+ MOVW s2+4(FP), R4
+
+ SUB $1, R3
+ SUB $1, R4
+l1:
+ MOVBZU 1(R3), R5
+ MOVBZU 1(R4), R6
+ CMP R5, R6
+ BNE ne
+ CMP R5, $0
+ BNE l1
+ MOVW $0, R3
+ RETURN
+ne:
+ MOVW $1, R3
+ BGT ret
+ MOVW $-1, R3
+ret:
+ RETURN
diff --git a/sys/src/ape/lib/ap/power/tas.s b/sys/src/ape/lib/ap/power/tas.s
new file mode 100755
index 000000000..09fb0c492
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/tas.s
@@ -0,0 +1,16 @@
+TEXT tas(SB), $0
+ SYNC
+ MOVW R3, R4
+ MOVW $0xdeaddead,R5
+tas1:
+ DCBF (R4) /* fix for 603x bug */
+ LWAR (R4), R3
+ CMP R3, $0
+ BNE tas0
+ DCBT (R4) /* fix 405 errata cpu_210 */
+ STWCCC R5, (R4)
+ BNE tas1
+tas0:
+ SYNC
+ ISYNC
+ RETURN
diff --git a/sys/src/ape/lib/ap/power/vlop.s b/sys/src/ape/lib/ap/power/vlop.s
new file mode 100755
index 000000000..9085da247
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/vlop.s
@@ -0,0 +1,132 @@
+#define BDNZ BC 16,0,
+
+/*
+ * 64/64 division adapted from powerpc compiler writer's handbook
+ *
+ * (R3:R4) = (R3:R4) / (R5:R6) (64b) = (64b / 64b)
+ * quo dvd dvs
+ *
+ * Remainder is left in R7:R8
+ *
+ * Code comment notation:
+ * msw = most-significant (high-order) word, i.e. bits 0..31
+ * lsw = least-significant (low-order) word, i.e. bits 32..63
+ * LZ = Leading Zeroes
+ * SD = Significant Digits
+ *
+ * R3:R4 = dvd (input dividend); quo (output quotient)
+ * R5:R6 = dvs (input divisor)
+ *
+ * R7:R8 = tmp; rem (output remainder)
+ */
+
+TEXT _divu64(SB), $0
+ MOVW a+0(FP), R3
+ MOVW a+4(FP), R4
+ MOVW b+8(FP), R5
+ MOVW b+12(FP), R6
+
+ /* count the number of leading 0s in the dividend */
+ CMP R3, $0 /* dvd.msw == 0? R3, */
+ CNTLZW R3, R11 /* R11 = dvd.msw.LZ */
+ CNTLZW R4, R9 /* R9 = dvd.lsw.LZ */
+ BNE lab1 /* if(dvd.msw != 0) dvd.LZ = dvd.msw.LZ */
+ ADD $32, R9, R11 /* dvd.LZ = dvd.lsw.LZ + 32 */
+
+lab1:
+ /* count the number of leading 0s in the divisor */
+ CMP R5, $0 /* dvd.msw == 0? */
+ CNTLZW R5, R9 /* R9 = dvs.msw.LZ */
+ CNTLZW R6, R10 /* R10 = dvs.lsw.LZ */
+ BNE lab2 /* if(dvs.msw != 0) dvs.LZ = dvs.msw.LZ */
+ ADD $32, R10, R9 /* dvs.LZ = dvs.lsw.LZ + 32 */
+
+lab2:
+ /* determine shift amounts to minimize the number of iterations */
+ CMP R11, R9 /* compare dvd.LZ to dvs.LZ */
+ SUBC R11, $64, R10 /* R10 = dvd.SD */
+ BGT lab9 /* if(dvs > dvd) quotient = 0 */
+ ADD $1, R9 /* ++dvs.LZ (or --dvs.SD) */
+ SUBC R9, $64, R9 /* R9 = dvs.SD */
+ ADD R9, R11 /* (dvd.LZ + dvs.SD) = left shift of dvd for */
+ /* initial dvd */
+ SUB R9, R10, R9 /* (dvd.SD - dvs.SD) = right shift of dvd for */
+ /* initial tmp */
+ MOVW R9, CTR /* number of iterations = dvd.SD - dvs.SD */
+
+ /* R7:R8 = R3:R4 >> R9 */
+ CMP R9, $32
+ ADD $-32, R9, R7
+ BLT lab3 /* if(R9 < 32) jump to lab3 */
+ SRW R7, R3, R8 /* tmp.lsw = dvd.msw >> (R9 - 32) */
+ MOVW $0, R7 /* tmp.msw = 0 */
+ BR lab4
+lab3:
+ SRW R9, R4, R8 /* R8 = dvd.lsw >> R9 */
+ SUBC R9, $32, R7
+ SLW R7, R3, R7 /* R7 = dvd.msw << 32 - R9 */
+ OR R7, R8 /* tmp.lsw = R8 | R7 */
+ SRW R9, R3, R7 /* tmp.msw = dvd.msw >> R9 */
+
+lab4:
+ /* R3:R4 = R3:R4 << R11 */
+ CMP R11,$32
+ ADDC $-32, R11, R9
+ BLT lab5 /* (R11 < 32)? */
+ SLW R9, R4, R3 /* dvd.msw = dvs.lsw << R9 */
+ MOVW $0, R4 /* dvd.lsw = 0 */
+ BR lab6
+
+lab5:
+ SLW R11, R3 /* R3 = dvd.msw << R11 */
+ SUBC R11, $32, R9
+ SRW R9, R4, R9 /* R9 = dvd.lsw >> 32 - R11 */
+ OR R9, R3 /* dvd.msw = R3 | R9 */
+ SLW R11, R4 /* dvd.lsw = dvd.lsw << R11 */
+
+lab6:
+ /* restoring division shift and subtract loop */
+ MOVW $-1, R10
+ ADDC $0, R7 /* clear carry bit before loop starts */
+lab7:
+ /* tmp:dvd is considered one large register */
+ /* each portion is shifted left 1 bit by adding it to itself */
+ /* adde sums the carry from the previous and creates a new carry */
+ ADDE R4,R4 /* shift dvd.lsw left 1 bit */
+ ADDE R3,R3 /* shift dvd.msw to left 1 bit */
+ ADDE R8,R8 /* shift tmp.lsw to left 1 bit */
+ ADDE R7,R7 /* shift tmp.msw to left 1 bit */
+ SUBC R6, R8, R11 /* tmp.lsw - dvs.lsw */
+ SUBECC R5, R7, R9 /* tmp.msw - dvs.msw */
+ BLT lab8 /* if(result < 0) clear carry bit */
+ MOVW R11, R8 /* move lsw */
+ MOVW R9, R7 /* move msw */
+ ADDC $1, R10, R11 /* set carry bit */
+lab8:
+ BDNZ lab7
+
+ ADDE R4,R4 /* quo.lsw (lsb = CA) */
+ ADDE R3,R3 /* quo.msw (lsb from lsw) */
+
+lab10:
+ MOVW qp+16(FP), R9
+ MOVW rp+20(FP), R10
+ CMP R9, $0
+ BEQ lab11
+ MOVW R3, 0(R9)
+ MOVW R4, 4(R9)
+lab11:
+ CMP R10, $0
+ BEQ lab12
+ MOVW R7, 0(R10)
+ MOVW R8, 4(R10)
+lab12:
+ RETURN
+
+lab9:
+ /* Quotient is 0 (dvs > dvd) */
+ MOVW R4, R8 /* rmd.lsw = dvd.lsw */
+ MOVW R3, R7 /* rmd.msw = dvd.msw */
+ MOVW $0, R4 /* dvd.lsw = 0 */
+ MOVW $0, R3 /* dvd.msw = 0 */
+ BR lab10
diff --git a/sys/src/ape/lib/ap/power/vlrt.c b/sys/src/ape/lib/ap/power/vlrt.c
new file mode 100755
index 000000000..681a3b49b
--- /dev/null
+++ b/sys/src/ape/lib/ap/power/vlrt.c
@@ -0,0 +1,254 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ ulong hi;
+ ulong lo;
+};
+
+void abort(void);
+void _divu64(Vlong, Vlong, Vlong*, Vlong*);
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ _divu64(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ _divu64(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ _divu64(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ _divu64(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
diff --git a/sys/src/ape/lib/ap/sparc/cycles.c b/sys/src/ape/lib/ap/sparc/cycles.c
new file mode 100755
index 000000000..1c32bc732
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/cycles.c
@@ -0,0 +1,5 @@
+void
+_cycles(unsigned long long *u)
+{
+ *u = 0;
+}
diff --git a/sys/src/ape/lib/ap/sparc/lock.c b/sys/src/ape/lib/ap/sparc/lock.c
new file mode 100755
index 000000000..91c0ba233
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/lock.c
@@ -0,0 +1,26 @@
+#define _LOCK_EXTENSION
+#include "../plan9/sys9.h"
+#include <lock.h>
+
+int tas(int*);
+
+void
+lock(Lock *lk)
+{
+ while(tas(&lk->val))
+ _SLEEP(0);
+}
+
+int
+canlock(Lock *lk)
+{
+ if(tas(&lk->val))
+ return 0;
+ return 1;
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
diff --git a/sys/src/ape/lib/ap/sparc/main9.s b/sys/src/ape/lib/ap/sparc/main9.s
new file mode 100755
index 000000000..24a9f6f53
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/main9.s
@@ -0,0 +1,14 @@
+ TEXT _main(SB), $16
+ MOVW $setSB(SB), R2
+ JMPL _envsetup(SB)
+ MOVW inargc-4(FP), R7
+ MOVW $inargv+0(FP), R8
+ MOVW R7, 4(R1)
+ MOVW R8, 8(R1)
+ JMPL main(SB)
+
+loop:
+ MOVW R7, 4(R1)
+ JMPL exit(SB)
+ MOVW $_mul(SB),R7
+ JMP loop
diff --git a/sys/src/ape/lib/ap/sparc/main9p.s b/sys/src/ape/lib/ap/sparc/main9p.s
new file mode 100755
index 000000000..17cc3e2af
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/main9p.s
@@ -0,0 +1,53 @@
+#define NPRIVATES 16
+
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
+
+TEXT _mainp(SB), 1, $(3*4+NPRIVATES*4)
+ MOVW $setSB(SB), R2
+
+ /* _tos = arg */
+ MOVW R7, _tos(SB)
+/*
+ MOVW _fpsr+0(SB), FSR
+ FMOVD $0.5, F26
+ FSUBD F26, F26, F24
+ FADDD F26, F26, F28
+ FADDD F28, F28, F30
+*/
+ MOVW $8(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ /* _profmain(); */
+ JMPL _profmain(SB)
+
+ /* _tos->prof.pp = _tos->prof.next; */
+ MOVW _tos+0(SB),R7
+ MOVW 4(R7),R8
+ MOVW R8,(R7)
+
+ JMPL _envsetup(SB)
+
+ /* main(argc, argv, environ); */
+ MOVW inargc-4(FP), R7
+ MOVW $inargv+0(FP), R8
+ MOVW environ(SB), R9
+ MOVW R8, 8(R1)
+ MOVW R9, 12(R1)
+ JMPL main(SB)
+
+loop:
+ JMPL exit(SB)
+ MOVW $_mul(SB), R0 /* force loading of muldiv */
+ MOVW $_profin(SB), R0 /* force loading of profile */
+ JMP loop
+
+TEXT _savearg(SB), 1, $0
+ RETURN
+
+TEXT _callpc(SB), 1, $0
+ MOVW argp-4(FP), R7
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/memchr.s b/sys/src/ape/lib/ap/sparc/memchr.s
new file mode 100755
index 000000000..81e67f6f2
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/memchr.s
@@ -0,0 +1,26 @@
+ TEXT memchr(SB), $0
+
+MOVW R7, 0(FP)
+ MOVW n+8(FP), R7
+ SUBCC R0,R7, R0
+ BE ret
+ MOVW s1+0(FP), R8
+ MOVBU c+7(FP), R9
+ ADD R7,R8, R11
+
+l1:
+ MOVBU (R8), R10
+ SUBCC R9,R10, R0
+ ADD $1, R8
+ BE eq
+ SUBCC R8,R11, R0
+ BNE l1
+
+ MOVW R0, R7
+ RETURN
+
+eq:
+ SUB $1,R8, R7
+
+ret:
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/memcmp.s b/sys/src/ape/lib/ap/sparc/memcmp.s
new file mode 100755
index 000000000..2b470d549
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/memcmp.s
@@ -0,0 +1,122 @@
+#define Bxx BE
+
+ TEXT memcmp(SB), $0
+
+/*
+ * performance:
+ * (tba)
+ */
+
+MOVW R7, 0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW s1+0(FP), R10 /* R10 is pointer1 */
+ MOVW s2+4(FP), R11 /* R11 is pointer2 */
+ ADD R9,R10, R12 /* R12 is end pointer1 */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word cmp.
+ */
+ SUBCC $4,R9, R0
+ BL out
+
+/*
+ * test if both pointers
+ * are similarly word alligned
+ */
+ XOR R10,R11, R7
+ ANDCC $3,R7, R0
+ BNE out
+
+/*
+ * byte at a time to word allign
+ */
+l1:
+ ANDCC $3,R10, R0
+ BE l2
+ MOVB 0(R10), R16
+ MOVB 0(R11), R17
+ ADD $1, R10
+ SUBCC R16,R17, R0
+ BNE ne
+ ADD $1, R11
+ JMP l1
+
+/*
+ * turn R9 into end pointer1-15
+ * cmp 16 at a time while theres room
+ */
+l2:
+ SUB $15,R12, R9
+l3:
+ SUBCC R10,R9, R0
+ BLEU l4
+ MOVW 0(R10), R16
+ MOVW 0(R11), R17
+ MOVW 4(R10), R18
+ SUBCC R16,R17, R0
+ BNE ne
+ MOVW 4(R11), R19
+ MOVW 8(R10), R16
+ SUBCC R18,R19, R0
+ BNE ne
+ MOVW 8(R11), R17
+ MOVW 12(R10), R18
+ SUBCC R16,R17, R0
+ BNE ne
+ MOVW 12(R11), R19
+ ADD $16, R10
+ SUBCC R18,R19, R0
+ BNE ne
+ SUBCC R16,R17, R0
+ BNE ne
+ ADD $16, R11
+ JMP l3
+
+/*
+ * turn R9 into end pointer1-3
+ * cmp 4 at a time while theres room
+ */
+l4:
+ SUB $3,R12, R9
+l5:
+ SUBCC R10,R9, R0
+ BLEU out
+ MOVW 0(R10), R16
+ MOVW 0(R11), R17
+ ADD $4, R10
+ SUBCC R16,R17, R0 /* only works because big endian */
+ BNE ne
+ ADD $4, R11
+ JMP l5
+
+/*
+ * last loop, cmp byte at a time
+ */
+out:
+ SUBCC R10,R12, R0
+ BE zero
+ MOVB 0(R10), R16
+ MOVB 0(R11), R17
+ ADD $1, R10
+ SUBCC R16,R17, R0
+ BNE ne
+ ADD $1, R11
+ JMP out
+
+ne:
+ BG plus
+ MOVW $1, R7
+ RETURN
+plus:
+ MOVW $-1, R7
+ RETURN
+
+zero:
+ MOVW R0, R7
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/memmove.s b/sys/src/ape/lib/ap/sparc/memmove.s
new file mode 100755
index 000000000..8879a74e8
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/memmove.s
@@ -0,0 +1,169 @@
+ TEXT memmove(SB), $0
+ JMP move
+
+ TEXT memcpy(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+ MOVW R7, s1+0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW R7, R10 /* R10 is to-pointer */
+ SUBCC R0,R9, R0
+ BGE ok
+ MOVW 0(R0), R0
+
+ok:
+ MOVW s2+4(FP), R11 /* R11 is from-pointer */
+ ADD R9,R11, R13 /* R13 is end from-pointer */
+ ADD R9,R10, R12 /* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ SUBCC R11,R10, R0
+ BGU back
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SUBCC $4,R9, R0
+ BL fout
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R10,R11, R7
+ ANDCC $3,R7, R0
+ BNE fout
+
+/*
+ * byte at a time to word align
+ */
+f1:
+ ANDCC $3,R10, R0
+ BE f2
+ MOVB 0(R11), R16
+ ADD $1, R11
+ MOVB R16, 0(R10)
+ ADD $1, R10
+ JMP f1
+
+/*
+ * turn R9 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R12 is smaller than R13 --
+ * there are problems if R13 is 0.
+ */
+f2:
+ SUB $15,R12, R9
+f3:
+ SUBCC R10,R9, R0
+ BLEU f4
+ MOVW 0(R11), R16
+ MOVW 4(R11), R17
+ MOVW R16, 0(R10)
+ MOVW 8(R11), R16
+ MOVW R17, 4(R10)
+ MOVW 12(R11), R17
+ ADD $16, R11
+ MOVW R16, 8(R10)
+ MOVW R17, 12(R10)
+ ADD $16, R10
+ JMP f3
+
+/*
+ * turn R9 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+ SUB $3,R12, R9
+f5:
+ SUBCC R10,R9, R0
+ BLEU fout
+ MOVW 0(R11), R16
+ ADD $4, R11
+ MOVW R16, 0(R10)
+ ADD $4, R10
+ JMP f5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+ SUBCC R11,R13, R0
+ BLEU ret
+ MOVB 0(R11), R16
+ ADD $1, R11
+ MOVB R16, 0(R10)
+ ADD $1, R10
+ JMP fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ SUBCC $4,R9, R0
+ BL bout
+
+ XOR R12,R13, R7
+ ANDCC $3,R7, R0
+ BNE bout
+b1:
+ ANDCC $3,R13, R0
+ BE b2
+ MOVB -1(R13), R16
+ SUB $1, R13
+ MOVB R16, -1(R12)
+ SUB $1, R12
+ JMP b1
+b2:
+ ADD $15,R11, R9
+b3:
+ SUBCC R9,R13, R0
+ BLEU b4
+ MOVW -4(R13), R16
+ MOVW -8(R13), R17
+ MOVW R16, -4(R12)
+ MOVW -12(R13), R16
+ MOVW R17, -8(R12)
+ MOVW -16(R13), R17
+ SUB $16, R13
+ MOVW R16, -12(R12)
+ MOVW R17, -16(R12)
+ SUB $16, R12
+ JMP b3
+b4:
+ ADD $3,R11, R9
+b5:
+ SUBCC R9,R13, R0
+ BLEU bout
+ MOVW -4(R13), R16
+ SUB $4, R13
+ MOVW R16, -4(R12)
+ SUB $4, R12
+ JMP b5
+
+bout:
+ SUBCC R11,R13, R0
+ BLEU ret
+ MOVB -1(R13), R16
+ SUB $1, R13
+ MOVB R16, -1(R12)
+ SUB $1, R12
+ JMP bout
+
+ret:
+ MOVW s1+0(FP), R7
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/memset.s b/sys/src/ape/lib/ap/sparc/memset.s
new file mode 100755
index 000000000..8c7b26c86
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/memset.s
@@ -0,0 +1,88 @@
+ TEXT memset(SB),$0
+
+/*
+ * performance:
+ * (tba)
+ */
+
+MOVW R7, 0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW p+0(FP), R10 /* R10 is pointer */
+ MOVW c+4(FP), R11 /* R11 is char */
+ ADD R9,R10, R12 /* R12 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SUBCC $4,R9, R0
+ BL out
+
+/*
+ * turn R11 into a word of characters
+ */
+ AND $0xff, R11
+ SLL $8,R11, R7
+ OR R7, R11
+ SLL $16,R11, R7
+ OR R7, R11
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+ ANDCC $3,R10, R0
+ BE l2
+ MOVB R11, 0(R10)
+ ADD $1, R10
+ JMP l1
+
+/*
+ * turn R9 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+ ADD $-15,R12, R9
+ SUBCC R10,R9, R0
+ BLEU l4
+l3:
+ MOVW R11, 0(R10)
+ MOVW R11, 4(R10)
+ ADD $16, R10
+ SUBCC R10,R9, R0
+ MOVW R11, -8(R10)
+ MOVW R11, -4(R10)
+ BGU l3
+
+/*
+ * turn R9 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+ ADD $-3,R12, R9
+l5:
+ SUBCC R10,R9, R0
+ BLEU out
+ MOVW R11, 0(R10)
+ ADD $4, R10
+ JMP l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+ SUBCC R10,R12, R0
+ BLEU ret
+ MOVB R11, 0(R10)
+ ADD $1, R10
+ JMP out
+
+ret:
+ MOVW s1+0(FP), R7
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/mkfile b/sys/src/ape/lib/ap/sparc/mkfile
new file mode 100755
index 000000000..9723ec2c3
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/mkfile
@@ -0,0 +1,26 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ cycles.$O\
+ lock.$O\
+ main9.$O\
+ main9p.$O\
+ memchr.$O\
+ memcmp.$O\
+ memmove.$O\
+ memset.$O\
+ muldiv.$O\
+ notetramp.$O\
+ setjmp.$O\
+ strchr.$O\
+ strcmp.$O\
+ strcpy.$O\
+ tas.$O\
+ vlop.$O\
+ vlrt.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE -D_PLAN9_SOURCE
+
diff --git a/sys/src/ape/lib/ap/sparc/muldiv.s b/sys/src/ape/lib/ap/sparc/muldiv.s
new file mode 100755
index 000000000..ac811629f
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/muldiv.s
@@ -0,0 +1,310 @@
+/*
+ * ulong
+ * _udiv(ulong num, ulong den)
+ * {
+ * int i;
+ * ulong quo;
+ *
+ * if(den == 0)
+ * *(ulong*)-1 = 0;
+ * quo = num;
+ * if(quo > 1<<(32-1))
+ * quo = 1<<(32-1);
+ * for(i=0; den<quo; i++)
+ * den <<= 1;
+ * quo = 0;
+ * for(; i>=0; i--) {
+ * quo <<= 1;
+ * if(num >= den) {
+ * num -= den;
+ * quo |= 1;
+ * }
+ * den >>= 1;
+ * }
+ * return quo::num;
+ * }
+ */
+
+#define NOPROF 1
+
+/*
+ * calling sequence:
+ * num: 4(R1)
+ * den: 8(R1)
+ * returns
+ * quo: 4(R1)
+ * rem: 8(R1)
+ */
+TEXT _udivmod(SB), NOPROF, $-4
+
+ MOVW $(1<<31), R11
+ MOVW 4(R1), R13 /* numerator */
+ MOVW 8(R1), R10 /* denominator */
+ CMP R10, R0
+ BNE udm20
+ MOVW R0, -1(R0) /* fault -- divide by zero */
+udm20:
+ MOVW R13, R12
+ CMP R13, R11
+ BLEU udm34
+ MOVW R11, R12
+udm34:
+ MOVW R0, R11
+udm38:
+ CMP R10, R12
+ BCC udm54
+ SLL $1, R10
+ ADD $1, R11
+ BA udm38
+udm54:
+ MOVW R0, R12
+udm58:
+ CMP R11, R0
+ BL udm8c
+ SLL $1, R12
+ CMP R13, R10
+ BCS udm7c
+ SUB R10, R13
+ OR $1, R12
+udm7c:
+ SRL $1, R10
+ SUB $1, R11
+ BA udm58
+udm8c:
+ MOVW R12, 4(R1) /* quotent */
+ MOVW R13, 8(R1) /* remainder */
+ JMPL 8(R15)
+
+/*
+ * save working registers
+ * and bring in num/den parameters
+ */
+TEXT _unsarg(SB), NOPROF, $-4
+ MOVW R10, 12(R1)
+ MOVW R11, 16(R1)
+ MOVW R12, 20(R1)
+ MOVW R13, 24(R1)
+
+ MOVW R14, 4(R1)
+ MOVW 32(R1), R14
+ MOVW R14, 8(R1)
+
+ JMPL 8(R15)
+
+/*
+ * save working registers
+ * and bring in absolute value
+ * of num/den parameters
+ */
+TEXT _absarg(SB), NOPROF, $-4
+ MOVW R10, 12(R1)
+ MOVW R11, 16(R1)
+ MOVW R12, 20(R1)
+ MOVW R13, 24(R1)
+
+ MOVW R14, 28(R1)
+ CMP R14, R0
+ BGE ab1
+ SUB R14, R0, R14
+ab1:
+ MOVW R14, 4(R1) /* numerator */
+
+ MOVW 32(R1), R14
+ CMP R14, R0
+ BGE ab2
+ SUB R14, R0, R14
+ab2:
+ MOVW R14, 8(R1) /* denominator */
+ JMPL 8(R15)
+
+/*
+ * restore registers and
+ * return to original caller
+ * answer is in R14
+ */
+TEXT _retarg(SB), NOPROF, $-4
+ MOVW 12(R1), R10
+ MOVW 16(R1), R11
+ MOVW 20(R1), R12
+ MOVW 24(R1), R13
+ MOVW 0(R1), R15
+
+ ADD $28, R1
+ JMP 8(R15) /* back to main sequence */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * quo: R14
+ */
+TEXT _div(SB), NOPROF, $-4
+ SUB $28, R1 /* 4 reg save, 2 parameters, link */
+ MOVW R15, 0(R1)
+
+ JMPL _absarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 4(R1), R14
+
+ MOVW 28(R1), R10 /* clean up the sign */
+ MOVW 32(R1), R11
+ XORCC R11, R10, R0
+ BGE div1
+ SUB R14, R0, R14
+div1:
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * quo: R14
+ */
+TEXT _divl(SB), NOPROF, $-4
+ SUB $((4+2+1)*4), R1 /* 4 reg save, 2 parameters, link */
+ MOVW R15, 0(R1)
+
+ JMPL _unsarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 4(R1), R14
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * rem: R14
+ */
+TEXT _mod(SB), NOPROF, $-4
+ SUB $28, R1 /* 4 reg save, 2 parameters, link */
+
+ MOVW R15, 0(R1)
+ JMPL _absarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 8(R1), R14
+
+ MOVW 28(R1), R10 /* clean up the sign */
+ CMP R10, R0
+ BGE mod1
+ SUB R14, R0, R14
+mod1:
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * rem: R14
+ */
+TEXT _modl(SB), NOPROF, $-4
+ SUB $28, R1 /* 4 reg save, 2 parameters, link */
+
+
+ MOVW R15, 0(R1)
+ JMPL _unsarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 8(R1), R14
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * special calling sequence:
+ * arg1 in R14
+ * arg2 in 4(R1), will save R9
+ * nothing in 0(R1), will save R8
+ * result in R14
+ */
+TEXT _mul+0(SB), NOPROF, $-4
+
+ /*
+ * exchange stack and registers
+ */
+ MOVW R8, 0(R1)
+ MOVW 4(R1), R8
+ MOVW R9, 4(R1)
+
+ CMP R14, R8
+ BLE mul1
+ MOVW R14, R9
+ MOVW R8, R14
+ MOVW R9, R8
+mul1:
+ MOVW R14, Y
+ ANDNCC $0xFFF, R14, R0
+ BE mul_shortway
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+
+ /* long multiply */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R8, R9, R9 /* 12 */
+ MULSCC R8, R9, R9 /* 13 */
+ MULSCC R8, R9, R9 /* 14 */
+ MULSCC R8, R9, R9 /* 15 */
+ MULSCC R8, R9, R9 /* 16 */
+ MULSCC R8, R9, R9 /* 17 */
+ MULSCC R8, R9, R9 /* 18 */
+ MULSCC R8, R9, R9 /* 19 */
+ MULSCC R8, R9, R9 /* 20 */
+ MULSCC R8, R9, R9 /* 21 */
+ MULSCC R8, R9, R9 /* 22 */
+ MULSCC R8, R9, R9 /* 23 */
+ MULSCC R8, R9, R9 /* 24 */
+ MULSCC R8, R9, R9 /* 25 */
+ MULSCC R8, R9, R9 /* 26 */
+ MULSCC R8, R9, R9 /* 27 */
+ MULSCC R8, R9, R9 /* 28 */
+ MULSCC R8, R9, R9 /* 29 */
+ MULSCC R8, R9, R9 /* 30 */
+ MULSCC R8, R9, R9 /* 31 */
+ MULSCC R0, R9, R9 /* 32; shift only */
+
+ MOVW Y, R14 /* get low part */
+ BA mul_return
+
+mul_shortway:
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R0, R9, R9 /* 12; shift only */
+
+ MOVW Y, R8
+ SLL $12, R9
+ SRL $20, R8
+ OR R8, R9, R14
+
+mul_return:
+ MOVW 0(R1), R8
+ MOVW 4(R1), R9
+ JMP 8(R15)
diff --git a/sys/src/ape/lib/ap/sparc/notetramp.c b/sys/src/ape/lib/ap/sparc/notetramp.c
new file mode 100755
index 000000000..c033d62cb
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/notetramp.c
@@ -0,0 +1,81 @@
+#include "../plan9/lib.h"
+#include "../plan9/sys9.h"
+#include <signal.h>
+#include <setjmp.h>
+
+/* A stack to hold pcs when signals nest */
+#define MAXSIGSTACK 20
+typedef struct Pcstack Pcstack;
+static struct Pcstack {
+ int sig;
+ void (*hdlr)(int, char*, Ureg*);
+ unsigned long restorepc;
+ unsigned long restorenpc;
+ Ureg *u;
+} pcstack[MAXSIGSTACK];
+static int nstack = 0;
+
+static void notecont(Ureg*, char*);
+
+void
+_notetramp(int sig, void (*hdlr)(int, char*, Ureg*), Ureg *u)
+{
+ Pcstack *p;
+
+ if(nstack >= MAXSIGSTACK)
+ _NOTED(1); /* nesting too deep; just do system default */
+ p = &pcstack[nstack];
+ p->restorepc = u->pc;
+ p->restorenpc = u->npc;
+ p->sig = sig;
+ p->hdlr = hdlr;
+ p->u = u;
+ nstack++;
+ u->pc = (unsigned long) notecont;
+ u->npc = u->pc+4;
+ _NOTED(2); /* NSAVE: clear note but hold state */
+}
+
+static void
+notecont(Ureg *u, char *s)
+{
+ Pcstack *p;
+ void(*f)(int, char*, Ureg*);
+
+ p = &pcstack[nstack-1];
+ f = p->hdlr;
+ u->pc = p->restorepc;
+ u->npc = p->restorenpc;
+ nstack--;
+ (*f)(p->sig, s, u);
+ _NOTED(3); /* NRSTR */
+}
+
+int __noterestore(void);
+
+#define JMPBUFPC 1
+#define JMPBUFSP 0
+#define JMPBUFDPC (-8)
+
+extern sigset_t _psigblocked;
+
+void
+siglongjmp(sigjmp_buf j, int ret)
+{
+ struct Ureg *u;
+
+ if(j[0])
+ _psigblocked = j[1];
+ if(nstack == 0 || pcstack[nstack-1].u->sp > j[2+JMPBUFSP])
+ longjmp(j+2, ret);
+ u = pcstack[nstack-1].u;
+ nstack--;
+ u->r8 = ret;
+ if(ret == 0)
+ u->r8 = 1;
+ u->r9 = j[JMPBUFPC] - JMPBUFDPC;
+ u->pc = (unsigned long)__noterestore;
+ u->npc = (unsigned long)__noterestore + 4;
+ u->sp = j[JMPBUFSP];
+ _NOTED(3); /* NRSTR */
+}
diff --git a/sys/src/ape/lib/ap/sparc/setjmp.s b/sys/src/ape/lib/ap/sparc/setjmp.s
new file mode 100755
index 000000000..8194a1d20
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/setjmp.s
@@ -0,0 +1,36 @@
+TEXT setjmp(SB), 1, $0
+
+ MOVW R1, (R7)
+ MOVW R15, 4(R7)
+ MOVW $0, R7
+ RETURN
+
+TEXT sigsetjmp(SB), 1, $0
+
+ MOVW savemask+4(FP), R8
+ MOVW R8, 0(R7)
+ MOVW $_psigblocked(SB), R8
+ MOVW R8, 4(R7)
+ MOVW R1, 8(R7)
+ MOVW R15, 12(R7)
+ MOVW $0, R7
+ RETURN
+
+TEXT longjmp(SB), 1, $0
+
+ MOVW R7, R8
+ MOVW r+4(FP), R7
+ CMP R7, R0
+ BNE ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVW $1, R7 /* bless their pointed heads */
+ok: MOVW (R8), R1
+ MOVW 4(R8), R15
+ RETURN
+
+/*
+ * trampoline functions because the kernel smashes r7
+ * in the uregs given to notejmp
+ */
+TEXT __noterestore(SB), 1, $-4
+ MOVW R8, R7
+ JMP (R9)
diff --git a/sys/src/ape/lib/ap/sparc/strchr.s b/sys/src/ape/lib/ap/sparc/strchr.s
new file mode 100755
index 000000000..192beab13
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/strchr.s
@@ -0,0 +1,73 @@
+ TEXT strchr(SB), $0
+
+MOVW R7, 0(FP)
+ MOVB c+7(FP), R10
+ MOVW s+0(FP), R9
+
+ SUBCC R0,R10, R0
+ BE l2
+
+/*
+ * char is not null
+ */
+l1:
+ MOVB (R9), R7
+ ADD $1, R9
+ SUBCC R0,R7, R0
+ BE ret
+ SUBCC R7,R10, R0
+ BNE l1
+ JMP rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+ ANDCC $3,R9, R0
+ BE l3
+ MOVB (R9), R7
+ ADD $1, R9
+ SUBCC R0,R7, R0
+ BNE l2
+ JMP rm1
+
+/*
+ * develop byte masks
+ */
+l3:
+ MOVW $0xff, R17
+ SLL $8,R17, R16
+ SLL $16,R17, R13
+ SLL $24,R17, R12
+
+l4:
+ MOVW (R9), R11
+ ADD $4, R9
+ ANDCC R12,R11, R0
+ BE b0
+ ANDCC R13,R11, R0
+ BE b1
+ ANDCC R16,R11, R0
+ BE b2
+ ANDCC R17,R11, R0
+ BNE l4
+
+rm1:
+ SUB $1,R9, R7
+ JMP ret
+
+b2:
+ SUB $2,R9, R7
+ JMP ret
+
+b1:
+ SUB $3,R9, R7
+ JMP ret
+
+b0:
+ SUB $4,R9, R7
+ JMP ret
+
+ret:
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/strcmp.s b/sys/src/ape/lib/ap/sparc/strcmp.s
new file mode 100755
index 000000000..e9539ebf8
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/strcmp.s
@@ -0,0 +1,27 @@
+TEXT strcmp(SB), $0
+
+ MOVW s2+4(FP), R10
+
+l1:
+ MOVB 0(R7), R8
+ MOVB 0(R10), R9
+ ADD $1, R7
+ ADD $1, R10
+
+ CMP R8, R9
+ BNE l2
+
+ CMP R8, $0
+ BNE l1
+
+ MOVW R0, R7
+ RETURN
+
+l2:
+ BLEU l3
+ MOVW $1, R7
+ RETURN
+
+l3:
+ MOVW $-1, R7
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/strcpy.s b/sys/src/ape/lib/ap/sparc/strcpy.s
new file mode 100755
index 000000000..6fd6aef05
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/strcpy.s
@@ -0,0 +1,84 @@
+ TEXT strcpy(SB), $0
+
+MOVW R7, 0(FP)
+ MOVW s1+0(FP), R9 /* R9 is to pointer */
+ MOVW s2+4(FP), R10 /* R10 is from pointer */
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R9,R10, R7
+ ANDCC $3,R7, R0
+ BNE una
+
+/*
+ * make byte masks
+ */
+ MOVW $0xff, R17
+ SLL $8,R17, R16
+ SLL $16,R17, R13
+ SLL $24,R17, R12
+
+/*
+ * byte at a time to word align
+ */
+al1:
+ ANDCC $3,R10, R0
+ BE al2
+ MOVB (R10), R11
+ ADD $1, R10
+ MOVB R11, (R9)
+ ADD $1, R9
+ SUBCC R0,R11, R0
+ BNE al1
+ JMP out
+
+/*
+ * word at a time
+ */
+al2:
+ ADD $4, R9
+ MOVW (R10), R11 /* fetch */
+ ADD $4, R10
+ ANDCC R12,R11, R0 /* is it byte 0 */
+ BE b0
+ ANDCC R13,R11, R0 /* is it byte 1 */
+ BE b1
+ ANDCC R16,R11, R0 /* is it byte 2 */
+ BE b2
+ MOVW R11, -4(R9) /* store */
+ ANDCC R17,R11, R0 /* is it byte 3 */
+ BNE al2
+
+ JMP out
+
+b0:
+ MOVB R0, -4(R9)
+ JMP out
+
+b1:
+ SRL $24, R11
+ MOVB R11, -4(R9)
+ MOVB R0, -3(R9)
+ JMP out
+
+b2:
+ SRL $24,R11, R7
+ MOVB R7, -4(R9)
+ SRL $16, R11
+ MOVB R11, -3(R9)
+ MOVB R0, -2(R9)
+ JMP out
+
+una:
+ MOVB (R10), R11
+ ADD $1, R10
+ MOVB R11, (R9)
+ ADD $1, R9
+ SUBCC R0,R11, R0
+ BNE una
+
+out:
+ MOVW s1+0(FP),R7
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/tas.s b/sys/src/ape/lib/ap/sparc/tas.s
new file mode 100755
index 000000000..70cce835d
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/tas.s
@@ -0,0 +1,7 @@
+/*
+ * tas uses LDSTUB
+ */
+ TEXT tas(SB),$-4
+
+ TAS (R7),R7
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/vlop.s b/sys/src/ape/lib/ap/sparc/vlop.s
new file mode 100755
index 000000000..ac36b4143
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/vlop.s
@@ -0,0 +1,112 @@
+TEXT _mulv(SB), $0
+ MOVW u1+8(FP), R8
+ MOVW u2+16(FP), R13
+
+ MOVW R13, R16 /* save low parts for later */
+ MOVW R8, R12
+
+ /*
+ * unsigned 32x32 => 64 multiply
+ */
+ CMP R13, R8
+ BLE mul1
+ MOVW R12, R13
+ MOVW R16, R8
+mul1:
+ MOVW R13, Y
+ ANDNCC $0xFFF, R13, R0
+ BE mul_shortway
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+
+ /* long multiply */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R8, R9, R9 /* 12 */
+ MULSCC R8, R9, R9 /* 13 */
+ MULSCC R8, R9, R9 /* 14 */
+ MULSCC R8, R9, R9 /* 15 */
+ MULSCC R8, R9, R9 /* 16 */
+ MULSCC R8, R9, R9 /* 17 */
+ MULSCC R8, R9, R9 /* 18 */
+ MULSCC R8, R9, R9 /* 19 */
+ MULSCC R8, R9, R9 /* 20 */
+ MULSCC R8, R9, R9 /* 21 */
+ MULSCC R8, R9, R9 /* 22 */
+ MULSCC R8, R9, R9 /* 23 */
+ MULSCC R8, R9, R9 /* 24 */
+ MULSCC R8, R9, R9 /* 25 */
+ MULSCC R8, R9, R9 /* 26 */
+ MULSCC R8, R9, R9 /* 27 */
+ MULSCC R8, R9, R9 /* 28 */
+ MULSCC R8, R9, R9 /* 29 */
+ MULSCC R8, R9, R9 /* 30 */
+ MULSCC R8, R9, R9 /* 31 */
+ MULSCC R0, R9, R9 /* 32; shift only; r9 is high part */
+
+ /*
+ * need to correct top word if top bit set
+ */
+ CMP R8, R0
+ BGE mul_tstlow
+ ADD R13, R9 /* adjust the high parts */
+
+mul_tstlow:
+ MOVW Y, R13 /* get low part */
+ BA mul_done
+
+mul_shortway:
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R0, R9, R9 /* 12; shift only; r9 is high part */
+
+ MOVW Y, R8 /* make low part of partial low part & high part */
+ SLL $12, R9, R13
+ SRL $20, R8
+ OR R8, R13
+
+ SRA $20, R9 /* high part */
+
+mul_done:
+
+ /*
+ * mul by high halves if needed
+ */
+ MOVW R13, 4(R7)
+ MOVW u2+12(FP), R11
+ CMP R11, R0
+ BE nomul1
+ MUL R11, R12
+ ADD R12, R9
+
+nomul1:
+ MOVW u1+4(FP), R11
+ CMP R11, R0
+ BE nomul2
+ MUL R11, R16
+ ADD R16, R9
+
+nomul2:
+
+ MOVW R9, 0(R7)
+ RETURN
diff --git a/sys/src/ape/lib/ap/sparc/vlrt.c b/sys/src/ape/lib/ap/sparc/vlrt.c
new file mode 100755
index 000000000..6fbd83ca8
--- /dev/null
+++ b/sys/src/ape/lib/ap/sparc/vlrt.c
@@ -0,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/sys/src/ape/lib/ap/stdio/_IO_getc.c b/sys/src/ape/lib/ap/stdio/_IO_getc.c
new file mode 100755
index 000000000..3f99922c2
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/_IO_getc.c
@@ -0,0 +1,30 @@
+/*
+ * pANS stdio -- _IO_getc
+ */
+#include "iolib.h"
+int _IO_getc(FILE *f){
+ int cnt, n;
+ switch(f->state){
+ default: /* CLOSED, WR, ERR, EOF */
+ return EOF;
+ case OPEN:
+ _IO_setvbuf(f);
+ case RDWR:
+ case RD:
+ if(f->flags&STRING) return EOF;
+ if(f->buf == f->unbuf)
+ n = 1;
+ else
+ n = f->bufl;
+ cnt=read(f->fd, f->buf, n);
+ switch(cnt){
+ case -1: f->state=ERR; return EOF;
+ case 0: f->state=END; return EOF;
+ default:
+ f->state=RD;
+ f->rp=f->buf;
+ f->wp=f->buf+cnt;
+ return (*f->rp++)&_IO_CHMASK;
+ }
+ }
+}
diff --git a/sys/src/ape/lib/ap/stdio/_IO_putc.c b/sys/src/ape/lib/ap/stdio/_IO_putc.c
new file mode 100755
index 000000000..8cef77fd3
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/_IO_putc.c
@@ -0,0 +1,106 @@
+/*
+ * pANS stdio -- _IO_putc, _IO_cleanup
+ */
+#include "iolib.h"
+
+void _IO_cleanup(void){
+ fflush(NULL);
+}
+/*
+ * Look this over for simplification
+ */
+int _IO_putc(int c, FILE *f){
+ int cnt;
+ static int first=1;
+ switch(f->state){
+ case RD:
+ f->state=ERR;
+ case ERR:
+ case CLOSED:
+ return EOF;
+ case OPEN:
+ _IO_setvbuf(f);
+ /* fall through */
+ case RDWR:
+ case END:
+ f->rp=f->buf+f->bufl;
+ if(f->flags&LINEBUF){
+ f->wp=f->rp;
+ f->lp=f->buf;
+ }
+ else
+ f->wp=f->buf;
+ break;
+ }
+ if(first){
+ atexit(_IO_cleanup);
+ first=0;
+ }
+ if(f->flags&STRING){
+ f->rp=f->buf+f->bufl;
+ if(f->wp==f->rp){
+ if(f->flags&BALLOC)
+ f->buf=realloc(f->buf, f->bufl+BUFSIZ);
+ else{
+ f->state=ERR;
+ return EOF;
+ }
+ if(f->buf==NULL){
+ f->state=ERR;
+ return EOF;
+ }
+ f->rp=f->buf+f->bufl;
+ f->bufl+=BUFSIZ;
+ }
+ *f->wp++=c;
+ }
+ else if(f->flags&LINEBUF){
+ if(f->lp==f->rp){
+ cnt=f->lp-f->buf;
+ if(f->flags&APPEND) lseek(f->fd, 0L, SEEK_END);
+ if(cnt!=0 && write(f->fd, f->buf, cnt)!=cnt){
+ f->state=ERR;
+ return EOF;
+ }
+ f->lp=f->buf;
+ }
+ *f->lp++=c;
+ if(c=='\n'){
+ cnt=f->lp-f->buf;
+ if(f->flags&APPEND) lseek(f->fd, 0L, SEEK_END);
+ if(cnt!=0 && write(f->fd, f->buf, cnt)!=cnt){
+ f->state=ERR;
+ return EOF;
+ }
+ f->lp=f->buf;
+ }
+ }
+ else if(f->buf==f->unbuf){
+ f->unbuf[0]=c;
+ if(f->flags&APPEND) lseek(f->fd, 0L, SEEK_END);
+ if(write(f->fd, f->buf, 1)!=1){
+ f->state=ERR;
+ return EOF;
+ }
+ }
+ else{
+ if(f->wp==f->rp){
+ cnt=f->wp-f->buf;
+ if(f->flags&APPEND) lseek(f->fd, 0L, SEEK_END);
+ if(cnt!=0 && write(f->fd, f->buf, cnt)!=cnt){
+ f->state=ERR;
+ return EOF;
+ }
+ f->wp=f->buf;
+ f->rp=f->buf+f->bufl;
+ }
+ *f->wp++=c;
+ }
+ f->state=WR;
+ /*
+ * Make sure EOF looks different from putc(-1)
+ * Should be able to cast to unsigned char, but
+ * there's a vc bug preventing that from working
+ */
+ return c&0xff;
+}
diff --git a/sys/src/ape/lib/ap/stdio/_dtoa.c b/sys/src/ape/lib/ap/stdio/_dtoa.c
new file mode 100755
index 000000000..fe147789b
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/_dtoa.c
@@ -0,0 +1,744 @@
+#include "fconv.h"
+
+static int quorem(Bigint *, Bigint *);
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the long
+ * calculation.
+ */
+
+ char *
+_dtoa(double darg, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4-9 should give the same return values as 2-3, i.e.,
+ 4 <= mode <= 9 ==> same return as mode
+ 2 + (mode & 1). These modes are mainly for
+ debugging; often they run slower but sometimes
+ faster than modes 2-3.
+ 4,5,8,9 ==> left-to-right digit generation.
+ 6-9 ==> don't try fast floating-point estimate
+ (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick;
+ long L;
+#ifndef Sudden_Underflow
+ int denorm;
+ unsigned long x;
+#endif
+ Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+ double ds;
+ Dul d2, eps;
+ char *s, *s0;
+ static Bigint *result;
+ static int result_k;
+ Dul d;
+
+ d.d = darg;
+ if (result) {
+ result->k = result_k;
+ result->maxwds = 1 << result_k;
+ Bfree(result);
+ result = 0;
+ }
+
+ if (word0(d) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(d) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+ if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+ if (word0(d) == 0x8000)
+#endif
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+ s =
+#ifdef IEEE_Arith
+ !word1(d) && !(word0(d) & 0xfffff) ? "Infinity" :
+#endif
+ "NaN";
+ if (rve)
+ *rve =
+#ifdef IEEE_Arith
+ s[3] ? s + 8 :
+#endif
+ s + 3;
+ return s;
+ }
+#endif
+#ifdef IBM
+ d.d += 0; /* normalize */
+#endif
+ if (!d.d) {
+ *decpt = 1;
+ s = "0";
+ if (rve)
+ *rve = s + 1;
+ return s;
+ }
+
+ b = d2b(d.d, &be, &bbits);
+#ifdef Sudden_Underflow
+ i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+ if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) {
+#endif
+ d2.d = d.d;
+ word0(d2) &= Frac_mask1;
+ word0(d2) |= Exp_11;
+#ifdef IBM
+ if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+ d2.d /= 1 << j;
+#endif
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifdef IBM
+ i <<= 2;
+ i += j;
+#endif
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P-1) - 1);
+ x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32
+ : word1(d) << 32 - i;
+ d2.d = x;
+ word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (d2.d-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+ k = floor(ds);
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (d.d < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+ try_quick = 1;
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ switch(mode) {
+ case 0:
+ case 1:
+ ilim = ilim1 = -1;
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ j = sizeof(unsigned long);
+ for(result_k = 0; sizeof(Bigint) - sizeof(unsigned long) + j <= i;
+ j <<= 1) result_k++;
+ result = Balloc(result_k);
+ s = s0 = (char *)result;
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ d2.d = d.d;
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ d.d /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for(; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ d.d /= ds;
+ }
+ else if (j1 = -k) {
+ d.d *= tens[j1 & 0xf];
+ for(j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ d.d *= bigtens[i];
+ }
+ }
+ if (k_check && d.d < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ d.d *= 10.;
+ ieps++;
+ }
+ eps.d = ieps*d.d + 7.;
+ word0(eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ d.d -= 5.;
+ if (d.d > eps.d)
+ goto one_digit;
+ if (d.d < -eps.d)
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ eps.d = 0.5/tens[ilim-1] - eps.d;
+ for(i = 0;;) {
+ L = floor(d.d);
+ d.d -= L;
+ *s++ = '0' + (int)L;
+ if (d.d < eps.d)
+ goto ret1;
+ if (1. - d.d < eps.d)
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ eps.d *= 10.;
+ d.d *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ eps.d *= tens[ilim-1];
+ for(i = 1;; i++, d.d *= 10.) {
+ L = floor(d.d);
+ d.d -= L;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (d.d > 0.5 + eps.d)
+ goto bump_up;
+ else if (d.d < 0.5 - eps.d) {
+ while(*--s == '0');
+ s++;
+ goto ret1;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+ fast_failed:
+ s = s0;
+ d.d = d2.d;
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || d.d <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for(i = 1;; i++) {
+ L = floor(d.d / ds);
+ d.d -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (d.d < 0) {
+ L--;
+ d.d += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ d.d += d.d;
+ if (d.d > ds || d.d == ds && L & 1) {
+ bump_up:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ d.d *= 10.;
+ if (d.d == 0.)
+ break;
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ mhi = mlo = 0;
+ if (leftright) {
+ if (mode < 2) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+ 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+ 1 + P - bbits;
+#endif
+ }
+ else {
+ j = ilim - 1;
+ if (m5 >= j)
+ m5 -= j;
+ else {
+ s5 += j -= m5;
+ b5 += j;
+ m5 = 0;
+ }
+ if ((i = ilim) < 0) {
+ m2 -= i;
+ i = 0;
+ }
+ }
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ }
+ if (j = b5 - m5)
+ b = pow5mult(b, j);
+ }
+ else
+ b = pow5mult(b, b5);
+ }
+ S = i2b(1);
+ if (s5 > 0)
+ S = pow5mult(S, s5);
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ if (mode < 2) {
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & Exp_mask
+#endif
+ ) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ else
+ spec_case = 0;
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+#ifdef Pack_32
+ if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)
+ i = 32 - i;
+#else
+ if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+ i = 16 - i;
+#endif
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0)
+ b = lshift(b, b2);
+ if (s2 > 0)
+ S = lshift(S, s2);
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0);
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && mode > 2) {
+ if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+ /* no digits, fcvt style */
+ no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+ one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0)
+ mhi = lshift(mhi, m2);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ }
+
+ for(i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+#ifndef ROUND_BIASED
+ if (j1 == 0 && !mode && !(word1(d) & 1)) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+ *s++ = dig;
+ goto ret;
+ }
+#endif
+ if (j < 0 || j == 0 && !mode
+#ifndef ROUND_BIASED
+ && !(word1(d) & 1)
+#endif
+ ) {
+ if (j1 > 0) {
+ b = lshift(b, 1);
+ j1 = cmp(b, S);
+ if ((j1 > 0 || j1 == 0 && dig & 1)
+ && dig++ == '9')
+ goto round_9_up;
+ }
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+ if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0);
+ else {
+ mlo = multadd(mlo, 10, 0);
+ mhi = multadd(mhi, 10, 0);
+ }
+ }
+ }
+ else
+ for(i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+ b = lshift(b, 1);
+ j = cmp(b, S);
+ if (j > 0 || j == 0 && dig & 1) {
+ roundoff:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ else {
+ while(*--s == '0');
+ s++;
+ }
+ ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ ret1:
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ return s0;
+ }
+
+ static int
+quorem(Bigint *b, Bigint *S)
+{
+ int n;
+ long borrow, y;
+ unsigned long carry, q, ys;
+ unsigned long *bx, *bxe, *sx, *sxe;
+#ifdef Pack_32
+ long z;
+ unsigned long si, zs;
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+ /*debug*/ if (q > 9)
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*bx >> 16) - (zs & 0xffff) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ * q + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ *bx++ = y & 0xffff;
+#endif
+ }
+ while(sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*bx >> 16) - (zs & 0xffff) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ *bx++ = y & 0xffff;
+#endif
+ }
+ while(sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+ }
diff --git a/sys/src/ape/lib/ap/stdio/_fconv.c b/sys/src/ape/lib/ap/stdio/_fconv.c
new file mode 100755
index 000000000..fc72d4731
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/_fconv.c
@@ -0,0 +1,593 @@
+/* Common routines for _dtoa and strtod */
+
+#include "fconv.h"
+
+#ifdef DEBUG
+#include <stdio.h>
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+ double
+_tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+#ifdef VAX
+ , 1e23, 1e24
+#endif
+ };
+
+
+#ifdef IEEE_Arith
+double _bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+double _tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
+#else
+#ifdef IBM
+double _bigtens[] = { 1e16, 1e32, 1e64 };
+double _tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#else
+double _bigtens[] = { 1e16, 1e32 };
+double _tinytens[] = { 1e-16, 1e-32 };
+#endif
+#endif
+
+ static Bigint *freelist[Kmax+1];
+
+ Bigint *
+_Balloc(int k)
+{
+ int x;
+ Bigint *rv;
+
+ if (rv = freelist[k]) {
+ freelist[k] = rv->next;
+ }
+ else {
+ x = 1 << k;
+ rv = (Bigint *)malloc(sizeof(Bigint) + (x-1)*sizeof(long));
+ rv->k = k;
+ rv->maxwds = x;
+ }
+ rv->sign = rv->wds = 0;
+ return rv;
+ }
+
+ void
+_Bfree(Bigint *v)
+{
+ if (v) {
+ v->next = freelist[v->k];
+ freelist[v->k] = v;
+ }
+ }
+
+
+ Bigint *
+_multadd(Bigint *b, int m, int a) /* multiply by m and add a */
+{
+ int i, wds;
+ unsigned long *x, y;
+#ifdef Pack_32
+ unsigned long xi, z;
+#endif
+ Bigint *b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ do {
+#ifdef Pack_32
+ xi = *x;
+ y = (xi & 0xffff) * m + a;
+ z = (xi >> 16) * m + (y >> 16);
+ a = (int)(z >> 16);
+ *x++ = (z << 16) + (y & 0xffff);
+#else
+ y = *x * m + a;
+ a = (int)(y >> 16);
+ *x++ = y & 0xffff;
+#endif
+ }
+ while(++i < wds);
+ if (a) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = a;
+ b->wds = wds;
+ }
+ return b;
+ }
+
+ int
+_hi0bits(register unsigned long x)
+{
+ register int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+ }
+
+ static int
+lo0bits(unsigned long *y)
+{
+ register int k;
+ register unsigned long x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x & 1)
+ return 32;
+ }
+ *y = x;
+ return k;
+ }
+
+ Bigint *
+_i2b(int i)
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+ }
+
+ Bigint *
+_mult(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int k, wa, wb, wc;
+ unsigned long carry, y, z;
+ unsigned long *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+#ifdef Pack_32
+ unsigned long z2;
+#endif
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ for(x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef Pack_32
+ for(; xb < xbe; xb++, xc0++) {
+ if (y = *xb & 0xffff) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ }
+ while(x < xae);
+ *xc = carry;
+ }
+ if (y = *xb >> 16) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ }
+ while(x < xae);
+ *xc = z2;
+ }
+ }
+#else
+ for(; xb < xbe; xc0++) {
+ if (y = *xb++) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * y + *xc + carry;
+ carry = z >> 16;
+ *xc++ = z & 0xffff;
+ }
+ while(x < xae);
+ *xc = carry;
+ }
+ }
+#endif
+ for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+ c->wds = wc;
+ return c;
+ }
+
+ static Bigint *p5s;
+
+ Bigint *
+_pow5mult(Bigint *b, int k)
+{
+ Bigint *b1, *p5, *p51;
+ int i;
+ static int p05[3] = { 5, 25, 125 };
+
+ if (i = k & 3)
+ b = multadd(b, p05[i-1], 0);
+
+ if (!(k >>= 2))
+ return b;
+ if (!(p5 = p5s)) {
+ /* first time */
+ p5 = p5s = i2b(625);
+ p5->next = 0;
+ }
+ for(;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+ if (!(p51 = p5->next)) {
+ p51 = p5->next = mult(p5,p5);
+ p51->next = 0;
+ }
+ p5 = p51;
+ }
+ return b;
+ }
+
+ Bigint *
+_lshift(Bigint *b, int k)
+{
+ int i, k1, n, n1;
+ Bigint *b1;
+ unsigned long *x, *x1, *xe, z;
+
+#ifdef Pack_32
+ n = k >> 5;
+#else
+ n = k >> 4;
+#endif
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for(i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ x1 = b1->x;
+ for(i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+#ifdef Pack_32
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ }
+ while(x < xe);
+ if (*x1 = z)
+ ++n1;
+ }
+#else
+ if (k &= 0xf) {
+ k1 = 16 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k & 0xffff | z;
+ z = *x++ >> k1;
+ }
+ while(x < xe);
+ if (*x1 = z)
+ ++n1;
+ }
+#endif
+ else do
+ *x1++ = *x++;
+ while(x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b);
+ return b1;
+ }
+
+ int
+_cmp(Bigint *a, Bigint *b)
+{
+ unsigned long *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i-1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j-1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for(;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+ }
+
+ Bigint *
+_diff(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int i, wa, wb;
+ long borrow, y; /* We need signed shifts here. */
+ unsigned long *xa, *xae, *xb, *xbe, *xc;
+#ifdef Pack_32
+ long z;
+#endif
+
+ i = cmp(a,b);
+ if (!i) {
+ c = Balloc(0);
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ }
+ else
+ i = 0;
+ c = Balloc(a->k);
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef Pack_32
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*xa++ >> 16) - (*xb++ >> 16) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(xc, z, y);
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = (*xa & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*xa++ >> 16) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ y = *xa++ - *xb++ + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ *xc++ = y & 0xffff;
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = *xa++ + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ *xc++ = y & 0xffff;
+ }
+#endif
+ while(!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+ }
+
+ Bigint *
+_d2b(double darg, int *e, int *bits)
+{
+ Bigint *b;
+ int de, i, k;
+ unsigned long *x, y, z;
+ Dul d;
+#ifdef VAX
+ unsigned long d0, d1;
+ d.d = darg;
+ d0 = word0(d) >> 16 | word0(d) << 16;
+ d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+ d.d = darg;
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+ b = Balloc(1);
+#else
+ b = Balloc(2);
+#endif
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+ z |= Exp_msk11;
+#endif
+#else
+ if (de = (int)(d0 >> Exp_shift))
+ z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+ if (y = d1) {
+ if (k = lo0bits(&y)) {
+ x[0] = y | z << 32 - k;
+ z >>= k;
+ }
+ else
+ x[0] = y;
+ i = b->wds = (x[1] = z) ? 2 : 1;
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ x[0] = z;
+ i = b->wds = 1;
+ k += 32;
+ }
+#else
+ if (y = d1) {
+ if (k = lo0bits(&y))
+ if (k >= 16) {
+ x[0] = y | z << 32 - k & 0xffff;
+ x[1] = z >> k - 16 & 0xffff;
+ x[2] = z >> k;
+ i = 2;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16 | z << 16 - k & 0xffff;
+ x[2] = z >> k & 0xffff;
+ x[3] = z >> k+16;
+ i = 3;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16;
+ x[2] = z & 0xffff;
+ x[3] = z >> 16;
+ i = 3;
+ }
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ if (k >= 16) {
+ x[0] = z;
+ i = 0;
+ }
+ else {
+ x[0] = z & 0xffff;
+ x[1] = z >> 16;
+ i = 1;
+ }
+ k += 32;
+ }
+ while(!x[i])
+ --i;
+ b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+#ifdef IBM
+ *e = (de - Bias - (P-1) << 2) + k;
+ *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+ *e = de - Bias - (P-1) + k;
+ *bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+ }
+ else {
+ *e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+ *bits = 32*i - hi0bits(x[i-1]);
+#else
+ *bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+ }
+#endif
+ return b;
+ }
+#undef d0
+#undef d1
diff --git a/sys/src/ape/lib/ap/stdio/atexit.c b/sys/src/ape/lib/ap/stdio/atexit.c
new file mode 100755
index 000000000..16043eb57
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/atexit.c
@@ -0,0 +1,15 @@
+#include <unistd.h>
+#define NONEXIT 34
+extern int (*_atexitfns[NONEXIT])(void);
+
+int
+atexit(int (*f)(void))
+{
+ int i;
+ for(i=0; i<NONEXIT; i++)
+ if(!_atexitfns[i]){
+ _atexitfns[i] = f;
+ return(0);
+ }
+ return(1);
+}
diff --git a/sys/src/ape/lib/ap/stdio/clearerr.c b/sys/src/ape/lib/ap/stdio/clearerr.c
new file mode 100755
index 000000000..904e33581
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/clearerr.c
@@ -0,0 +1,14 @@
+/*
+ * pANS stdio -- clearerr
+ */
+#include "iolib.h"
+void clearerr(FILE *f){
+ switch(f->state){
+ case ERR:
+ f->state=f->buf?RDWR:OPEN;
+ break;
+ case END:
+ f->state=RDWR;
+ break;
+ }
+}
diff --git a/sys/src/ape/lib/ap/stdio/exit.c b/sys/src/ape/lib/ap/stdio/exit.c
new file mode 100755
index 000000000..eaef6b304
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/exit.c
@@ -0,0 +1,17 @@
+#include <unistd.h>
+#define NONEXIT 34
+int (*_atexitfns[NONEXIT])(void);
+void _doatexits(void){
+ int i, (*f)(void);
+ for(i = NONEXIT-1; i >= 0; i--)
+ if(_atexitfns[i]){
+ f = _atexitfns[i];
+ _atexitfns[i] = 0; /* self defense against bozos */
+ (*f)();
+ }
+}
+void exit(int status)
+{
+ _doatexits();
+ _exit(status);
+}
diff --git a/sys/src/ape/lib/ap/stdio/fclose.c b/sys/src/ape/lib/ap/stdio/fclose.c
new file mode 100755
index 000000000..d14e83746
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fclose.c
@@ -0,0 +1,15 @@
+/*
+ * pANS stdio -- fclose
+ */
+#include "iolib.h"
+int fclose(FILE *f){
+ int error=0;
+ if(!f) return EOF;
+ if(f->state==CLOSED) return EOF;
+ if(fflush(f)==EOF) error=EOF;
+ if(f->flags&BALLOC) free(f->buf);
+ if(!(f->flags&STRING) && close(f->fd)<0) error=EOF;
+ f->state=CLOSED;
+ f->flags=0;
+ return error;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fconv.h b/sys/src/ape/lib/ap/stdio/fconv.h
new file mode 100755
index 000000000..ccc91e0cf
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fconv.h
@@ -0,0 +1,236 @@
+/****************************************************************
+
+ The author of this software (_dtoa, strtod) is David M. Gay.
+ Please send bug reports to
+ David M. Gay
+ Bell Laboratories, Room 2C-463
+ 600 Mountain Avenue
+ Murray Hill, NJ 07974-2070
+ U.S.A.
+ dmg@research.bell-labs.com
+ */
+#include <stdlib.h>
+#include <string.h>
+#define _RESEARCH_SOURCE
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+#define CONST const
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ * significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ * significant byte has the lowest address.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ * underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic.
+ * #define Unsigned_Shifts if >> does treats its left operand as unsigned.
+ * #define No_leftright to omit left-right logic in fast floating-point
+ * computation of dtoa.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ * that use extended-precision instructions to compute rounded
+ * products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define Just_16 to store 16 bits per 32-bit long when doing high-precision
+ * integer arithmetic. Whether this speeds things up or slows things
+ * down depends on the machine and the number being converted.
+ */
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union {
+ double d;
+ unsigned long ul[2];
+} Dul;
+
+#ifdef IEEE_8087
+#define word0(x) ((x).ul[1])
+#define word1(x) ((x).ul[0])
+#else
+#define word0(x) ((x).ul[0])
+#define word1(x) ((x).ul[1])
+#endif
+
+#ifdef Unsigned_Shifts
+#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000;
+#else
+#define Sign_Extend(a,b) /*no-op*/
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k)
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define IEEE_Arith
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#define Infinite(x) (word0(x) == 0x7ff00000) /* sufficient test for here */
+#else
+#undef Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#define Exp_shift 24
+#define Exp_shift1 24
+#define Exp_msk1 0x1000000
+#define Exp_msk11 0x1000000
+#define Exp_mask 0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1 0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask 0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask 0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#define Exp_shift 23
+#define Exp_shift1 7
+#define Exp_msk1 0x80
+#define Exp_msk11 0x800000
+#define Exp_mask 0x7f80
+#define P 56
+#define Bias 129
+#define Exp_1 0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask 0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask 0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif
+#endif
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Just_16
+/* When Pack_32 is not defined, we store 16 bits per 32-bit long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower. Hence the default is now to store 32 bits per long.
+ */
+#ifndef Pack_32
+#define Pack_32
+#endif
+#endif
+
+#define Kmax 15
+
+ struct
+Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ unsigned long x[1];
+ };
+
+ typedef struct Bigint Bigint;
+
+/* This routines shouldn't be visible externally */
+extern Bigint *_Balloc(int);
+extern void _Bfree(Bigint *);
+extern Bigint *_multadd(Bigint *, int, int);
+extern int _hi0bits(unsigned long);
+extern Bigint *_mult(Bigint *, Bigint *);
+extern Bigint *_pow5mult(Bigint *, int);
+extern Bigint *_lshift(Bigint *, int);
+extern int _cmp(Bigint *, Bigint *);
+extern Bigint *_diff(Bigint *, Bigint *);
+extern Bigint *_d2b(double, int *, int *);
+extern Bigint *_i2b(int);
+
+extern double _tens[], _bigtens[], _tinytens[];
+
+#ifdef IEEE_Arith
+#define n_bigtens 5
+#else
+#ifdef IBM
+#define n_bigtens 3
+#else
+#define n_bigtens 2
+#endif
+#endif
+
+#define Balloc(x) _Balloc(x)
+#define Bfree(x) _Bfree(x)
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(long) + 2*sizeof(int))
+#define multadd(x,y,z) _multadd(x,y,z)
+#define hi0bits(x) _hi0bits(x)
+#define i2b(x) _i2b(x)
+#define mult(x,y) _mult(x,y)
+#define pow5mult(x,y) _pow5mult(x,y)
+#define lshift(x,y) _lshift(x,y)
+#define cmp(x,y) _cmp(x,y)
+#define diff(x,y) _diff(x,y)
+#define d2b(x,y,z) _d2b(x,y,z)
+
+#define tens _tens
+#define bigtens _bigtens
+#define tinytens _tinytens
diff --git a/sys/src/ape/lib/ap/stdio/fdopen.c b/sys/src/ape/lib/ap/stdio/fdopen.c
new file mode 100755
index 000000000..0c585b965
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fdopen.c
@@ -0,0 +1,33 @@
+/*
+ * Posix stdio -- fdopen
+ */
+#include "iolib.h"
+/*
+ * Open the named file with the given mode, using the given FILE
+ * Legal modes are given below, `additional characters may follow these sequences':
+ * r rb open to read
+ * w wb open to write, truncating
+ * a ab open to write positioned at eof, creating if non-existant
+ * r+ r+b rb+ open to read and write, creating if non-existant
+ * w+ w+b wb+ open to read and write, truncating
+ * a+ a+b ab+ open to read and write, positioned at eof, creating if non-existant.
+ */
+FILE *fdopen(const int fd, const char *mode){
+ FILE *f;
+ for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++)
+ if(f->state==CLOSED)
+ break;
+ if(f==&_IO_stream[FOPEN_MAX])
+ return NULL;
+ f->fd=fd;
+ if(mode[0]=='a')
+ lseek(f->fd, 0L, 2);
+ if(f->fd==-1) return NULL;
+ f->flags=0;
+ f->state=OPEN;
+ f->buf=0;
+ f->rp=0;
+ f->wp=0;
+ f->lp=0;
+ return f;
+}
diff --git a/sys/src/ape/lib/ap/stdio/feof.c b/sys/src/ape/lib/ap/stdio/feof.c
new file mode 100755
index 000000000..9c2ce9077
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/feof.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- feof
+ */
+#include "iolib.h"
+int feof(FILE *f){
+ return f->state==END;
+}
diff --git a/sys/src/ape/lib/ap/stdio/ferror.c b/sys/src/ape/lib/ap/stdio/ferror.c
new file mode 100755
index 000000000..0c705c5d8
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/ferror.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- ferror
+ */
+#include "iolib.h"
+int ferror(FILE *f){
+ return f->state==ERR;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fflush.c b/sys/src/ape/lib/ap/stdio/fflush.c
new file mode 100755
index 000000000..50a9da28f
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fflush.c
@@ -0,0 +1,31 @@
+/*
+ * pANS stdio -- fflush
+ */
+#include "iolib.h"
+int fflush(FILE *f){
+ int error, cnt;
+ if(f==NULL){
+ error=0;
+ for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++)
+ if(f->state==WR && fflush(f)==EOF)
+ error=EOF;
+ return error;
+ }
+ if(f->flags&STRING) return EOF;
+ switch(f->state){
+ default: /* OPEN RDWR EOF RD */
+ return 0;
+ case CLOSED:
+ case ERR:
+ return EOF;
+ case WR:
+ cnt=(f->flags&LINEBUF?f->lp:f->wp)-f->buf;
+ if(cnt && write(f->fd, f->buf, cnt)!=cnt){
+ f->state=ERR;
+ return EOF;
+ }
+ f->rp=f->wp=f->buf;
+ f->state=RDWR;
+ return 0;
+ }
+}
diff --git a/sys/src/ape/lib/ap/stdio/fgetc.c b/sys/src/ape/lib/ap/stdio/fgetc.c
new file mode 100755
index 000000000..08c5ad03b
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fgetc.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- fgetc
+ */
+#include "iolib.h"
+int fgetc(FILE *f){
+ return getc(f);
+}
diff --git a/sys/src/ape/lib/ap/stdio/fgetpos.c b/sys/src/ape/lib/ap/stdio/fgetpos.c
new file mode 100755
index 000000000..c8edc57b1
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fgetpos.c
@@ -0,0 +1,8 @@
+/*
+ * pANS stdio -- fgetpos
+ */
+#include "iolib.h"
+int fgetpos(FILE *f, fpos_t *pos){
+ *pos=ftell(f);
+ return *pos==-1?-1:0;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fgets.c b/sys/src/ape/lib/ap/stdio/fgets.c
new file mode 100755
index 000000000..5032735e0
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fgets.c
@@ -0,0 +1,17 @@
+/*
+ * pANS stdio -- fgets
+ */
+#include "iolib.h"
+char *fgets(char *as, int n, FILE *f){
+ int c=0;
+ char *s=as;
+ while(n>1 && (c=getc(f))!=EOF){
+ *s++=c;
+ --n;
+ if(c=='\n') break;
+ }
+ if(c==EOF && s==as
+ || ferror(f)) return NULL;
+ if(n) *s='\0';
+ return as;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fileno.c b/sys/src/ape/lib/ap/stdio/fileno.c
new file mode 100755
index 000000000..2dd6fdb85
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fileno.c
@@ -0,0 +1,10 @@
+/*
+ * Posix stdio -- fileno
+ */
+#include "iolib.h"
+int fileno(FILE *f){
+ if(f==NULL)
+ return -1;
+ else
+ return f->fd;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fopen.c b/sys/src/ape/lib/ap/stdio/fopen.c
new file mode 100755
index 000000000..edf27172c
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fopen.c
@@ -0,0 +1,11 @@
+/*
+ * pANS stdio -- fopen
+ */
+#include "iolib.h"
+FILE *fopen(const char *name, const char *mode){
+ FILE *f;
+ for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++)
+ if(f->state==CLOSED)
+ return freopen(name, mode, f);
+ return NULL;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fprintf.c b/sys/src/ape/lib/ap/stdio/fprintf.c
new file mode 100755
index 000000000..9f3a861cc
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fprintf.c
@@ -0,0 +1,12 @@
+/*
+ * pANS stdio -- fprintf
+ */
+#include "iolib.h"
+int fprintf(FILE *f, const char *fmt, ...){
+ int n;
+ va_list args;
+ va_start(args, fmt);
+ n=vfprintf(f, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fputc.c b/sys/src/ape/lib/ap/stdio/fputc.c
new file mode 100755
index 000000000..0a482e20c
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fputc.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- fputc
+ */
+#include "iolib.h"
+int fputc(int c, FILE *f){
+ return putc(c, f); /* This can be made more fair to _IOLBF-mode streams */
+}
diff --git a/sys/src/ape/lib/ap/stdio/fputs.c b/sys/src/ape/lib/ap/stdio/fputs.c
new file mode 100755
index 000000000..d0406b0e5
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fputs.c
@@ -0,0 +1,8 @@
+/*
+ * pANS stdio -- fputs
+ */
+#include "iolib.h"
+int fputs(const char *s, FILE *f){
+ while(*s) putc(*s++, f);
+ return ferror(f)?EOF:0;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fread.c b/sys/src/ape/lib/ap/stdio/fread.c
new file mode 100755
index 000000000..3345011b6
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fread.c
@@ -0,0 +1,45 @@
+/*
+ * pANS stdio -- fread
+ */
+#include "iolib.h"
+#include <string.h>
+
+#define BIGN (BUFSIZ/2)
+
+size_t fread(void *p, size_t recl, size_t nrec, FILE *f){
+ char *s;
+ int n, d, c;
+
+ s=(char *)p;
+ n=recl*nrec;
+ while(n>0){
+ d=f->wp-f->rp;
+ if(d>0){
+ if(d>n)
+ d=n;
+ memcpy(s, f->rp, d);
+ f->rp+=d;
+ }else{
+ if(n >= BIGN && f->state==RD && !(f->flags&STRING) && f->buf!=f->unbuf){
+ d=read(f->fd, s, n);
+ if(d<=0){
+ f->state=(d==0)?END:ERR;
+ goto ret;
+ }
+ }else{
+ c=_IO_getc(f);
+ if(c==EOF)
+ goto ret;
+ *s=c;
+ d=1;
+ }
+ }
+ s+=d;
+ n-=d;
+ }
+ ret:
+ if(recl)
+ return (s-(char*)p)/recl;
+ else
+ return s-(char*)p;
+}
diff --git a/sys/src/ape/lib/ap/stdio/freopen.c b/sys/src/ape/lib/ap/stdio/freopen.c
new file mode 100755
index 000000000..ba586bbfc
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/freopen.c
@@ -0,0 +1,66 @@
+/*
+ * pANS stdio -- freopen
+ */
+#include "iolib.h"
+/*
+ * Open the named file with the given mode, using the given FILE
+ * Legal modes are given below, `additional characters may follow these sequences':
+ * r rb open to read
+ * w wb open to write, truncating
+ * a ab open to write positioned at eof, creating if non-existant
+ * r+ r+b rb+ open to read and write, creating if non-existant
+ * w+ w+b wb+ open to read and write, truncating
+ * a+ a+b ab+ open to read and write, positioned at eof, creating if non-existant.
+ */
+FILE *freopen(const char *name, const char *mode, FILE *f){
+ int m;
+
+ if(f->state!=CLOSED){
+ fclose(f);
+/* premature; fall through and see what happens */
+/* f->state=OPEN; */
+ }
+
+ m = *mode++;
+ if(m == 0)
+ return NULL;
+ if(*mode == 'b')
+ mode++;
+ switch(m){
+ default:
+ return NULL;
+ case 'r':
+ f->fd=open(name, (*mode == '+'? O_RDWR: O_RDONLY));
+ break;
+ case 'w':
+ f->fd=creat(name, 0666); /* implicitly O_WRONLY */
+ /* for O_RDWR, have to creat, close, open */
+ if(*mode == '+' && f->fd >= 0) {
+ close(f->fd);
+ f->fd=open(name, O_RDWR);
+ }
+ break;
+ case 'a':
+ f->fd=open(name, (*mode == '+'? O_RDWR: O_WRONLY));
+ if(f->fd<0) {
+ f->fd=creat(name, 0666);
+ /* for O_RDWR, have to creat, close, open */
+ if(*mode == '+' && f->fd >= 0) {
+ close(f->fd);
+ f->fd=open(name, O_RDWR);
+ }
+ }
+ lseek(f->fd, 0L, 2);
+ break;
+ }
+
+ if(f->fd==-1)
+ return NULL;
+ f->flags=(mode[0]=='a')? APPEND : 0;
+ f->state=OPEN;
+ f->buf=0;
+ f->rp=0;
+ f->wp=0;
+ f->lp=0;
+ return f;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fscanf.c b/sys/src/ape/lib/ap/stdio/fscanf.c
new file mode 100755
index 000000000..3d9d874e8
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fscanf.c
@@ -0,0 +1,12 @@
+/*
+ * pANS stdio -- fscanf
+ */
+#include "iolib.h"
+int fscanf(FILE *f, const char *fmt, ...){
+ int n;
+ va_list args;
+ va_start(args, fmt);
+ n=vfscanf(f, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fseek.c b/sys/src/ape/lib/ap/stdio/fseek.c
new file mode 100755
index 000000000..fba570d09
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fseek.c
@@ -0,0 +1,24 @@
+/*
+ * pANS stdio -- fseek
+ */
+#include "iolib.h"
+int fseek(FILE *f, long offs, int type){
+ switch(f->state){
+ case ERR:
+ case CLOSED:
+ return -1;
+ case WR:
+ fflush(f);
+ break;
+ case RD:
+ if(type==1 && f->buf!=f->unbuf)
+ offs-=f->wp-f->rp;
+ break;
+ }
+ if(f->flags&STRING || lseek(f->fd, offs, type)==-1)
+ return -1;
+ if(f->state==RD) f->rp=f->wp=f->buf;
+ if(f->state!=OPEN)
+ f->state=RDWR;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fseeko.c b/sys/src/ape/lib/ap/stdio/fseeko.c
new file mode 100755
index 000000000..469d04419
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fseeko.c
@@ -0,0 +1,24 @@
+/*
+ * pANS stdio -- fseeko
+ */
+#include "iolib.h"
+int fseeko(FILE *f, off_t offs, int type){
+ switch(f->state){
+ case ERR:
+ case CLOSED:
+ return -1;
+ case WR:
+ fflush(f);
+ break;
+ case RD:
+ if(type==1 && f->buf!=f->unbuf)
+ offs-=f->wp-f->rp;
+ break;
+ }
+ if(f->flags&STRING || lseek(f->fd, offs, type)==-1)
+ return -1;
+ if(f->state==RD) f->rp=f->wp=f->buf;
+ if(f->state!=OPEN)
+ f->state=RDWR;
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fsetpos.c b/sys/src/ape/lib/ap/stdio/fsetpos.c
new file mode 100755
index 000000000..540e83a7e
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fsetpos.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- fsetpos
+ */
+#include "iolib.h"
+int fsetpos(FILE *f, const fpos_t *pos){
+ return fseek(f, *pos, SEEK_SET);
+}
diff --git a/sys/src/ape/lib/ap/stdio/ftell.c b/sys/src/ape/lib/ap/stdio/ftell.c
new file mode 100755
index 000000000..3693589ea
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/ftell.c
@@ -0,0 +1,16 @@
+/*
+ * pANS stdio -- ftell
+ */
+#include "iolib.h"
+long ftell(FILE *f){
+ long seekp=lseek(f->fd, 0L, 1);
+ if(seekp<0) return -1; /* enter error state? */
+ switch(f->state){
+ default:
+ return seekp;
+ case RD:
+ return seekp-(f->wp-f->rp);
+ case WR:
+ return (f->flags&LINEBUF?f->lp:f->wp)-f->buf+seekp;
+ }
+}
diff --git a/sys/src/ape/lib/ap/stdio/ftello.c b/sys/src/ape/lib/ap/stdio/ftello.c
new file mode 100755
index 000000000..4ebb7b138
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/ftello.c
@@ -0,0 +1,16 @@
+/*
+ * pANS stdio -- ftello
+ */
+#include "iolib.h"
+off_t ftello(FILE *f){
+ off_t seekp=lseek(f->fd, 0L, 1);
+ if(seekp<0) return -1; /* enter error state? */
+ switch(f->state){
+ default:
+ return seekp;
+ case RD:
+ return seekp-(f->wp-f->rp);
+ case WR:
+ return (f->flags&LINEBUF?f->lp:f->wp)-f->buf+seekp;
+ }
+}
diff --git a/sys/src/ape/lib/ap/stdio/ftoa.c b/sys/src/ape/lib/ap/stdio/ftoa.c
new file mode 100755
index 000000000..b241d2d43
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/ftoa.c
@@ -0,0 +1,41 @@
+#include <math.h>
+#include <stdlib.h>
+double pow10(int);
+#define NDIG 18
+#define NFTOA (NDIG+4)
+/*
+ * convert floating to ascii. ftoa returns an integer e such that
+ * f=g*10**e, with .1<=|g|<1 (e=0 when g==0) and puts an ascii
+ * representation of g in the buffer pointed to by bp. bp[0] will
+ * be '+' or '-', and bp[1] to bp[NFTOA-2]
+ * will be appropriate digits of g. bp[NFTOA-1] will be '\0'
+ */
+int ftoa(double f, char *bp){
+ int e, e1, e2, i;
+ double digit, g, p;
+ if(f>=0) *bp++='+';
+ else{
+ f=-f;
+ *bp++='-';
+ }
+ /* find e such that f==0 or 1<=f*pow10(e)<10, and set f=f*pow10(e) */
+ if(f==0.) e=1;
+ else{
+ frexp(f, &e);
+ e=-e*30103/100000;
+ /* split in 2 pieces to guard against overflow in extreme cases */
+ e1=e/2;
+ e2=e-e1;
+ p=f*pow10(e2);
+ while((g=p*pow10(e1))<1.) e1++;
+ while((g=p*pow10(e1))>=10.) --e1;
+ e=e1+e2;
+ f=g;
+ }
+ for(i=0;i!=NDIG;i++){
+ f=modf(f, &digit)*10.;
+ *bp++=digit+'0';
+ }
+ *bp='\0';
+ return 1-e;
+}
diff --git a/sys/src/ape/lib/ap/stdio/fwrite.c b/sys/src/ape/lib/ap/stdio/fwrite.c
new file mode 100755
index 000000000..5e871c069
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/fwrite.c
@@ -0,0 +1,55 @@
+/*
+ * pANS stdio -- fwrite
+ */
+#include "iolib.h"
+#include <string.h>
+
+#define BIGN (BUFSIZ/2)
+
+size_t fwrite(const void *p, size_t recl, size_t nrec, FILE *f){
+ char *s;
+ int n, d;
+
+ s=(char *)p;
+ n=recl*nrec;
+ while(n>0){
+ d=f->rp-f->wp;
+ if(d>0){
+ if(d>n)
+ d=n;
+ memcpy(f->wp, s, d);
+ f->wp+=d;
+ }else{
+ if(n>=BIGN && f->state==WR && !(f->flags&(STRING|LINEBUF)) && f->buf!=f->unbuf){
+ d=f->wp-f->buf;
+ if(d>0){
+ if(f->flags&APPEND)
+ lseek(f->fd, 0L, SEEK_END);
+ if(write(f->fd, f->buf, d)!=d){
+ f->state=ERR;
+ goto ret;
+ }
+ f->wp=f->rp=f->buf;
+ }
+ if(f->flags&APPEND)
+ lseek(f->fd, 0L, SEEK_END);
+ d=write(f->fd, s, n);
+ if(d<=0){
+ f->state=ERR;
+ goto ret;
+ }
+ }else{
+ if(_IO_putc(*s, f)==EOF)
+ goto ret;
+ d=1;
+ }
+ }
+ s+=d;
+ n-=d;
+ }
+ ret:
+ if(recl)
+ return (s-(char*)p)/recl;
+ else
+ return s-(char*)p;
+}
diff --git a/sys/src/ape/lib/ap/stdio/getc.c b/sys/src/ape/lib/ap/stdio/getc.c
new file mode 100755
index 000000000..4096972bf
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/getc.c
@@ -0,0 +1,8 @@
+/*
+ * pANS stdio -- getc
+ */
+#include "iolib.h"
+#undef getc
+int getc(FILE *f){
+ return fgetc(f);
+}
diff --git a/sys/src/ape/lib/ap/stdio/getchar.c b/sys/src/ape/lib/ap/stdio/getchar.c
new file mode 100755
index 000000000..f42c119c6
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/getchar.c
@@ -0,0 +1,8 @@
+/*
+ * pANS stdio -- getchar
+ */
+#include "iolib.h"
+#undef getchar
+int getchar(void){
+ return fgetc(stdin);
+}
diff --git a/sys/src/ape/lib/ap/stdio/gets.c b/sys/src/ape/lib/ap/stdio/gets.c
new file mode 100755
index 000000000..909c21485
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/gets.c
@@ -0,0 +1,17 @@
+/*
+ * pANS stdio -- gets
+ */
+#include "iolib.h"
+char *gets(char *as){
+#ifdef secure
+ stdin->flags|=ERR;
+ return NULL;
+#else
+ char *s=as;
+ int c;
+ while((c=getchar())!='\n' && c!=EOF) *s++=c;
+ if(c!=EOF || s!=as) *s='\0';
+ else return NULL;
+ return as;
+#endif
+}
diff --git a/sys/src/ape/lib/ap/stdio/iolib.h b/sys/src/ape/lib/ap/stdio/iolib.h
new file mode 100755
index 000000000..3a5bd63a0
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/iolib.h
@@ -0,0 +1,44 @@
+/*
+ * pANS stdio -- definitions
+ * The following names are defined in the pANS:
+ * FILE fpos_t _IOFBF _IOLBF _IONBF
+ * BUFSIZ EOF FOPEN_MAX FILENAME_MAX L_tmpnam
+ * SEEK_CUR SEEK_END SEEK_SET TMP_MAX stderr
+ * stdin stdout remove rename tmpfile
+ * tmpnam fclose fflush fopen freopen
+ * setbuf setvbuf fprintf fscanf printf
+ * scanf sprintf sscanf vfprintf vprintf
+ * vsprintf fgetc fgets fputc fputs
+ * getc getchar gets putc putchar
+ * puts ungetc fread fwrite fgetpos
+ * fseek fsetpos ftell rewind clearerr
+ * feof ferror perror
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+ * Flag bits
+ */
+#define BALLOC 1 /* did stdio malloc fd->buf? */
+#define LINEBUF 2 /* is stream line buffered? */
+#define STRING 4 /* output to string, instead of file */
+#define APPEND 8 /* append mode output */
+/*
+ * States
+ */
+#define CLOSED 0 /* file not open */
+#define OPEN 1 /* file open, but no I/O buffer allocated yet */
+#define RDWR 2 /* open, buffer allocated, ok to read or write */
+#define RD 3 /* open, buffer allocated, ok to read but not write */
+#define WR 4 /* open, buffer allocated, ok to write but not read */
+#define ERR 5 /* open, but an uncleared error occurred */
+#define END 6 /* open, but at eof */
+char *strerror(int errno);
+int _IO_setvbuf(FILE *);
+FILE *_IO_sopenr(const char*);
+FILE *_IO_sopenw(void);
+char *_IO_sclose(FILE *);
diff --git a/sys/src/ape/lib/ap/stdio/mkfile b/sys/src/ape/lib/ap/stdio/mkfile
new file mode 100755
index 000000000..17be0da58
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/mkfile
@@ -0,0 +1,68 @@
+APE=/sys/src/ape
+<$APE/config
+LIB=/$objtype/lib/ape/libap.a
+OFILES=\
+ _IO_getc.$O\
+ _IO_putc.$O\
+ _dtoa.$O\
+ _fconv.$O\
+ clearerr.$O\
+ atexit.$O\
+ exit.$O\
+ fclose.$O\
+ fdopen.$O\
+ feof.$O\
+ ferror.$O\
+ fflush.$O\
+ fgetc.$O\
+ fgetpos.$O\
+ fgets.$O\
+ fileno.$O\
+ fopen.$O\
+ fprintf.$O\
+ fputc.$O\
+ fputs.$O\
+ fread.$O\
+ freopen.$O\
+ fscanf.$O\
+ fseek.$O\
+ fseeko.$O\
+ fsetpos.$O\
+ ftell.$O\
+ ftello.$O\
+ ftoa.$O\
+ fwrite.$O\
+ getc.$O\
+ getchar.$O\
+ gets.$O\
+ perror.$O\
+ pow10.$O\
+ printf.$O\
+ putc.$O\
+ putchar.$O\
+ puts.$O\
+ remove.$O\
+ rewind.$O\
+ scanf.$O\
+ sclose.$O\
+ setbuf.$O\
+ setvbuf.$O\
+ snprintf.$O\
+ sopenr.$O\
+ sopenw.$O\
+ sprintf.$O\
+ sscanf.$O\
+ stdio.$O\
+ strerror.$O\
+ strtod.$O\
+ tmpnam.$O\
+ ungetc.$O\
+ vfprintf.$O\
+ vfscanf.$O\
+ vprintf.$O\
+ vsprintf.$O\
+ vsnprintf.$O\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=-c -D_POSIX_SOURCE
diff --git a/sys/src/ape/lib/ap/stdio/perror.c b/sys/src/ape/lib/ap/stdio/perror.c
new file mode 100755
index 000000000..71f5c41f0
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/perror.c
@@ -0,0 +1,11 @@
+/*
+ * pANS stdio -- perror
+ */
+#include "iolib.h"
+void perror(const char *s){
+ extern int errno;
+ if(s!=NULL && *s != '\0') fputs(s, stderr), fputs(": ", stderr);
+ fputs(strerror(errno), stderr);
+ putc('\n', stderr);
+ fflush(stderr);
+}
diff --git a/sys/src/ape/lib/ap/stdio/pow10.c b/sys/src/ape/lib/ap/stdio/pow10.c
new file mode 100755
index 000000000..fc2aec265
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/pow10.c
@@ -0,0 +1,30 @@
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+
+static long tab[] =
+{
+ 1L, 10L, 100L, 1000L, 10000L,
+ 100000L, 1000000L, 10000000L
+};
+
+double
+pow10(int n)
+{
+ int m;
+
+ if(n > DBL_MAX_10_EXP){
+ errno = ERANGE;
+ return HUGE_VAL;
+ }
+ if(n < DBL_MIN_10_EXP){
+ errno = ERANGE;
+ return 0.0;
+ }
+ if(n < 0)
+ return 1/pow10(-n);
+ if(n < sizeof(tab)/sizeof(tab[0]))
+ return tab[n];
+ m = n/2;
+ return pow10(m) * pow10(n-m);
+}
diff --git a/sys/src/ape/lib/ap/stdio/printf.c b/sys/src/ape/lib/ap/stdio/printf.c
new file mode 100755
index 000000000..8880b9d8d
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/printf.c
@@ -0,0 +1,12 @@
+/*
+ * pANS stdio -- printf
+ */
+#include "iolib.h"
+int printf(const char *fmt, ...){
+ int n;
+ va_list args;
+ va_start(args, fmt);
+ n=vfprintf(stdout, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/putc.c b/sys/src/ape/lib/ap/stdio/putc.c
new file mode 100755
index 000000000..9cffeeb01
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/putc.c
@@ -0,0 +1,8 @@
+/*
+ * pANS stdio -- putc
+ */
+#include "iolib.h"
+#undef putc
+int putc(int c, FILE *f){
+ return fputc(c, f);
+}
diff --git a/sys/src/ape/lib/ap/stdio/putchar.c b/sys/src/ape/lib/ap/stdio/putchar.c
new file mode 100755
index 000000000..7350012f2
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/putchar.c
@@ -0,0 +1,8 @@
+/*
+ * pANS stdio -- getchar
+ */
+#include "iolib.h"
+#undef putchar
+int putchar(int c){
+ return fputc(c, stdout);
+}
diff --git a/sys/src/ape/lib/ap/stdio/puts.c b/sys/src/ape/lib/ap/stdio/puts.c
new file mode 100755
index 000000000..b25c4718d
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/puts.c
@@ -0,0 +1,9 @@
+/*
+ * pANS stdio -- puts
+ */
+#include "iolib.h"
+int puts(const char *s){
+ fputs(s, stdout);
+ putchar('\n');
+ return ferror(stdin)?EOF:0;
+}
diff --git a/sys/src/ape/lib/ap/stdio/rdline.c b/sys/src/ape/lib/ap/stdio/rdline.c
new file mode 100755
index 000000000..6281a97e8
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/rdline.c
@@ -0,0 +1,65 @@
+/*
+ * pANS stdio -- rdline
+ * This is not a pANS routine.
+ */
+#include "iolib.h"
+#include <string.h>
+
+char *rdline(FILE *f, char **ep){
+ int cnt;
+ char *nlp, *vp;
+ switch(f->state){
+ default: /* CLOSED, WR, ERR, EOF */
+ return NULL;
+ case OPEN:
+ _IO_setvbuf(f);
+ case RDWR:
+ f->state=RD;
+ case RD:
+ if(f->bufl==0){ /* Called by a comedian! */
+ f->state=ERR;
+ return NULL;
+ }
+ vp=f->rp;
+ for(;;){
+ /*
+ * Look for a newline.
+ * If none found, slide the partial line to the beginning
+ * of the buffer, read some more and keep looking.
+ */
+ nlp=memchr(f->rp, '\n', f->wp-f->rp);
+ if(nlp!=0) break;
+ if(f->flags&STRING){
+ f->rp=f->wp;
+ if(ep) *ep=f->wp;
+ return vp;
+ }
+ if(f->rp!=f->buf){
+ memmove(f->buf, f->rp, f->wp-f->rp);
+ f->wp-=f->rp-f->buf;
+ f->rp=f->buf;
+ vp=f->rp;
+ }
+ cnt=f->bufl-(f->wp-f->buf);
+ if(cnt==0){ /* no room left */
+ nlp=f->wp-1;
+ break;
+ }
+ cnt=read(f->fd, f->wp, cnt);
+ if(cnt==-1){
+ f->state=ERR;
+ return NULL;
+ }
+ if(cnt==0){ /* is this ok? */
+ f->state=EOF;
+ return NULL;
+ }
+ f->rp=f->wp;
+ f->wp+=cnt;
+ }
+ *nlp='\0';
+ f->rp=nlp+1;
+ if(ep) *ep=nlp;
+ return vp;
+ }
+}
diff --git a/sys/src/ape/lib/ap/stdio/remove.c b/sys/src/ape/lib/ap/stdio/remove.c
new file mode 100755
index 000000000..bb30c94d5
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/remove.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- remove
+ */
+#include "iolib.h"
+int remove(const char *f){
+ return unlink((char *)f);
+}
diff --git a/sys/src/ape/lib/ap/stdio/rename.c b/sys/src/ape/lib/ap/stdio/rename.c
new file mode 100755
index 000000000..6232407f1
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/rename.c
@@ -0,0 +1,12 @@
+/*
+ * pANS stdio -- rename
+ */
+#include "iolib.h"
+int rename(const char *old, const char *new){
+ if(link((char *)old, (char *)new)<0) return -1;
+ if(unlink((char *)old)<0){
+ unlink((char *)new);
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/src/ape/lib/ap/stdio/rewind.c b/sys/src/ape/lib/ap/stdio/rewind.c
new file mode 100755
index 000000000..0cfdb957c
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/rewind.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- rewind
+ */
+#include "iolib.h"
+void rewind(FILE *f){
+ fseek(f, 0L, SEEK_SET);
+}
diff --git a/sys/src/ape/lib/ap/stdio/scanf.c b/sys/src/ape/lib/ap/stdio/scanf.c
new file mode 100755
index 000000000..30a631cc9
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/scanf.c
@@ -0,0 +1,12 @@
+/*
+ * pANS stdio -- scanf
+ */
+#include "iolib.h"
+int scanf(const char *fmt, ...){
+ int n;
+ va_list args;
+ va_start(args, fmt);
+ n=vfscanf(stdin, fmt, args);
+ va_end(args);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/sclose.c b/sys/src/ape/lib/ap/stdio/sclose.c
new file mode 100755
index 000000000..d55396a3a
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/sclose.c
@@ -0,0 +1,37 @@
+/*
+ * pANS stdio -- sclose
+ */
+#include "iolib.h"
+#include <stdlib.h>
+
+char *_IO_sclose(FILE *f){
+ switch(f->state){
+ default: /* ERR CLOSED */
+ if(f->buf && f->flags&BALLOC)
+ free(f->buf);
+ f->state=CLOSED;
+ f->flags=0;
+ return NULL;
+ case OPEN:
+ f->buf=malloc(1);
+ f->buf[0]='\0';
+ break;
+ case RD:
+ case END:
+ f->flags=0;
+ break;
+ case RDWR:
+ case WR:
+ if(f->wp==f->rp){
+ if(f->flags&BALLOC)
+ f->buf=realloc(f->buf, f->bufl+1);
+ if(f->buf==NULL) return NULL;
+ }
+ *f->wp='\0';
+ f->flags=0;
+ break;
+ }
+ f->state=CLOSED;
+ f->flags=0;
+ return f->buf;
+}
diff --git a/sys/src/ape/lib/ap/stdio/setbuf.c b/sys/src/ape/lib/ap/stdio/setbuf.c
new file mode 100755
index 000000000..31c5d3e1e
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/setbuf.c
@@ -0,0 +1,17 @@
+/*
+ * pANS stdio -- setbuf
+ */
+#include "iolib.h"
+void setbuf(FILE *f, char *buf){
+ if(f->state==OPEN){
+ if(buf)
+ f->bufl=BUFSIZ;
+ else{
+ buf=f->unbuf;
+ f->bufl=0;
+ }
+ f->rp=f->wp=f->lp=f->buf=buf;
+ f->state=RDWR;
+ }
+ /* else error, but there's no way to report it */
+}
diff --git a/sys/src/ape/lib/ap/stdio/setvbuf.c b/sys/src/ape/lib/ap/stdio/setvbuf.c
new file mode 100755
index 000000000..58bea0098
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/setvbuf.c
@@ -0,0 +1,39 @@
+/*
+ * pANS stdio -- setvbuf
+ */
+#include "iolib.h"
+#include <stdlib.h>
+int setvbuf(FILE *f, char *buf, int mode, size_t size){
+ if(f->state!=OPEN){
+ f->state=ERR;
+ return -1;
+ }
+ f->state=RDWR;
+ switch(mode){
+ case _IOLBF:
+ f->flags|=LINEBUF;
+ case _IOFBF:
+ if(buf==0){
+ buf=malloc(size);
+ if(buf==0){
+ f->state=ERR;
+ return -1;
+ }
+ f->flags|=BALLOC;
+ }
+ f->bufl=size;
+ break;
+ case _IONBF:
+ buf=f->unbuf;
+ f->bufl=0;
+ break;
+ }
+ f->rp=f->wp=f->lp=f->buf=buf;
+ f->state=RDWR;
+ return 0;
+}
+int _IO_setvbuf(FILE *f){
+ if(f==stderr || (f==stdout && isatty(1)))
+ return setvbuf(f, (char *)0, _IOLBF, BUFSIZ);
+ return setvbuf(f, (char *)0, _IOFBF, BUFSIZ);
+}
diff --git a/sys/src/ape/lib/ap/stdio/snprintf.c b/sys/src/ape/lib/ap/stdio/snprintf.c
new file mode 100755
index 000000000..0c5c2ae8f
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/snprintf.c
@@ -0,0 +1,20 @@
+/*
+ * pANS stdio -- sprintf
+ */
+#define _C99_SNPRINTF_EXTENSION
+
+#include "iolib.h"
+
+int snprintf(char *buf, size_t nbuf, const char *fmt, ...){
+ int n;
+ va_list args;
+ FILE *f=_IO_sopenw();
+ if(f==NULL)
+ return 0;
+ setvbuf(f, buf, _IOFBF, nbuf);
+ va_start(args, fmt);
+ n=vfprintf(f, fmt, args);
+ va_end(args);
+ _IO_sclose(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/sopenr.c b/sys/src/ape/lib/ap/stdio/sopenr.c
new file mode 100755
index 000000000..279ec726b
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/sopenr.c
@@ -0,0 +1,18 @@
+/*
+ * pANS stdio -- sopenr
+ */
+#include "iolib.h"
+#include <string.h>
+
+FILE *_IO_sopenr(const char *s){
+ FILE *f;
+ for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++) if(f->state==CLOSED) break;
+ if(f==&_IO_stream[FOPEN_MAX]) return NULL;
+ f->buf=f->rp=(char *)s; /* what an annoyance const is */
+ f->bufl=strlen(s);
+ f->wp=f->buf+f->bufl;
+ f->state=RD;
+ f->flags=STRING;
+ f->fd=-1;
+ return f;
+}
diff --git a/sys/src/ape/lib/ap/stdio/sopenw.c b/sys/src/ape/lib/ap/stdio/sopenw.c
new file mode 100755
index 000000000..d13634333
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/sopenw.c
@@ -0,0 +1,15 @@
+/*
+ * pANS stdio -- sopenw
+ */
+#include "iolib.h"
+
+FILE *_IO_sopenw(void){
+ FILE *f;
+ for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++) if(f->state==CLOSED) break;
+ if(f==&_IO_stream[FOPEN_MAX]) return NULL;
+ f->buf=f->rp=f->wp=0;
+ f->state=OPEN;
+ f->flags=STRING;
+ f->fd=-1;
+ return f;
+}
diff --git a/sys/src/ape/lib/ap/stdio/sprintf.c b/sys/src/ape/lib/ap/stdio/sprintf.c
new file mode 100755
index 000000000..5143bccf3
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/sprintf.c
@@ -0,0 +1,17 @@
+/*
+ * pANS stdio -- sprintf
+ */
+#include "iolib.h"
+int sprintf(char *buf, const char *fmt, ...){
+ int n;
+ va_list args;
+ FILE *f=_IO_sopenw();
+ if(f==NULL)
+ return 0;
+ setvbuf(f, buf, _IOFBF, 100000);
+ va_start(args, fmt);
+ n=vfprintf(f, fmt, args);
+ va_end(args);
+ _IO_sclose(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/sscanf.c b/sys/src/ape/lib/ap/stdio/sscanf.c
new file mode 100755
index 000000000..3e1d9b675
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/sscanf.c
@@ -0,0 +1,14 @@
+/*
+ * pANS stdio -- sscanf
+ */
+#include "iolib.h"
+int sscanf(const char *s, const char *fmt, ...){
+ int n;
+ FILE *f=_IO_sopenr(s);
+ va_list args;
+ va_start(args, fmt);
+ n=vfscanf(f, fmt, args);
+ va_end(args);
+ _IO_sclose(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/stdio.c b/sys/src/ape/lib/ap/stdio/stdio.c
new file mode 100755
index 000000000..854efe42b
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/stdio.c
@@ -0,0 +1,10 @@
+/*
+ * pANS stdio -- data
+ */
+#include "iolib.h"
+FILE _IO_stream[]={
+/* fd flags state buf rp wp lp bufl unbuf */
+ 0, 0, OPEN, 0, 0, 0, 0, 0, 0,
+ 1, 0, OPEN, 0, 0, 0, 0, 0, 0,
+ 2, 0, OPEN, 0, 0, 0, 0, 0, 0,
+};
diff --git a/sys/src/ape/lib/ap/stdio/strerror.c b/sys/src/ape/lib/ap/stdio/strerror.c
new file mode 100755
index 000000000..71685d906
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/strerror.c
@@ -0,0 +1,106 @@
+/*
+ * pANS stdio -- strerror (not really in stdio)
+ *
+ * Shouldn't really call this sys_errlist or make it
+ * externally visible, but too many programs in X assume it...
+ */
+#include <string.h>
+#include <errno.h>
+
+#include "iolib.h"
+
+char *sys_errlist[] = {
+ "Error 0",
+ "Too big",
+ "Access denied",
+ "Try again",
+ "Bad file number",
+ "In use",
+ "No children",
+ "Deadlock",
+ "File exists",
+ "Bad address",
+ "File too large",
+ "Interrupted system call",
+ "Invalid argument",
+ "I/O error",
+ "Is a directory",
+ "Too many open files",
+ "Too many links",
+ "Name too long",
+ "File table overflow",
+ "No such device",
+ "No such file or directory",
+ "Exec format error",
+ "Not enough locks",
+ "Not enough memory",
+ "No space left on device",
+ "No such system call",
+ "Not a directory",
+ "Directory not empty",
+ "Inappropriate ioctl",
+ "No such device or address",
+ "Permission denied",
+ "Broken pipe",
+ "Read-only file system",
+ "Illegal seek",
+ "No such process",
+ "Cross-device link",
+
+ /* bsd networking software */
+ "Not a socket",
+ "Protocol not supported", /* EPROTONOSUPPORT, EPROTOTYPE */
+/* "Protocol wrong type for socket", /* EPROTOTYPE */
+ "Connection refused",
+ "Address family not supported",
+ "No buffers",
+ "OP not supported",
+ "Address in use",
+ "Destination address required",
+ "Message size",
+ "Protocol option not supported",
+ "Socket option not supported",
+ "Protocol family not supported", /* EPFNOSUPPORT */
+ "Address not available",
+ "Network down",
+ "Network unreachable",
+ "Network reset",
+ "Connection aborted",
+ "Connected",
+ "Not connected",
+ "Shut down",
+ "Too many references",
+ "Timed out",
+ "Host down",
+ "Host unreachable",
+ "Unknown error", /* EGREG */
+
+ /* These added in 1003.1b-1993 */
+ "Operation canceled",
+ "Operation in progress"
+};
+#define _IO_nerr (sizeof sys_errlist/sizeof sys_errlist[0])
+int sys_nerr = _IO_nerr;
+extern char _plan9err[];
+
+char *
+strerror(int n)
+{
+ if(n == EPLAN9)
+ return _plan9err;
+ if(n >= 0 && n < _IO_nerr)
+ return sys_errlist[n];
+ if(n == EDOM)
+ return "Domain error";
+ else if(n == ERANGE)
+ return "Range error";
+ else
+ return "Unknown error";
+}
+
+char *
+strerror_r(int n, char *buf, int len)
+{
+ strncpy(buf, strerror(n), len);
+ buf[len-1] = 0;
+}
diff --git a/sys/src/ape/lib/ap/stdio/strtod.c b/sys/src/ape/lib/ap/stdio/strtod.c
new file mode 100755
index 000000000..ff820ef62
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/strtod.c
@@ -0,0 +1,731 @@
+#include "fconv.h"
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines (dmg).
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE, IBM, or VAX double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+ static double
+ulp(double xarg)
+{
+ register long L;
+ Dul a;
+ Dul x;
+
+ x.d = xarg;
+ L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+#ifdef IBM
+ L |= Exp_msk1 >> 4;
+#endif
+ word0(a) = L;
+ word1(a) = 0;
+#ifndef Sudden_Underflow
+ }
+ else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ word0(a) = 0x80000 >> L;
+ word1(a) = 0;
+ }
+ else {
+ word0(a) = 0;
+ L -= Exp_shift;
+ word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+ }
+ }
+#endif
+ return a.d;
+ }
+
+ static Bigint *
+s2b(CONST char *s, int nd0, int nd, unsigned long y9)
+{
+ Bigint *b;
+ int i, k;
+ long x, y;
+
+ x = (nd + 8) / 9;
+ for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+ b = Balloc(k);
+ b->x[0] = y9;
+ b->wds = 1;
+#else
+ b = Balloc(k+1);
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do b = multadd(b, 10, *s++ - '0');
+ while(++i < nd0);
+ s++;
+ }
+ else
+ s += 10;
+ for(; i < nd; i++)
+ b = multadd(b, 10, *s++ - '0');
+ return b;
+ }
+
+ static double
+b2d(Bigint *a, int *e)
+{
+ unsigned long *xa, *xa0, w, y, z;
+ int k;
+ Dul d;
+#ifdef VAX
+ unsigned long d0, d1;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y) Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+#ifdef Pack_32
+ if (k < Ebits) {
+ d0 = Exp_1 | y >> Ebits - k;
+ w = xa > xa0 ? *--xa : 0;
+ d1 = y << (32-Ebits) + k | w >> Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | y << k | z >> 32 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k | y >> 32 - k;
+ }
+ else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+#else
+ if (k < Ebits + 16) {
+ z = xa > xa0 ? *--xa : 0;
+ d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+ w = xa > xa0 ? *--xa : 0;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ w = xa > xa0 ? *--xa : 0;
+ k -= Ebits + 16;
+ d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+ word0(d) = d0 >> 16 | d0 << 16;
+ word1(d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+ return d.d;
+ }
+
+ static double
+ratio(Bigint *a, Bigint *b)
+{
+ Dul da, db;
+ int k, ka, kb;
+
+ da.d = b2d(a, &ka);
+ db.d = b2d(b, &kb);
+#ifdef Pack_32
+ k = ka - kb + 32*(a->wds - b->wds);
+#else
+ k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+ if (k > 0) {
+ word0(da) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ da *= 1 << k;
+ }
+ else {
+ k = -k;
+ word0(db) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ db *= 1 << k;
+ }
+#else
+ if (k > 0)
+ word0(da) += k*Exp_msk1;
+ else {
+ k = -k;
+ word0(db) += k*Exp_msk1;
+ }
+#endif
+ return da.d / db.d;
+ }
+
+ double
+strtod(CONST char *s00, char **se)
+{
+ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ CONST char *s, *s0, *s1;
+ double aadj, aadj1, adj;
+ Dul rv, rv0;
+ long L;
+ unsigned long y, z;
+ Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+ sign = nz0 = nz = 0;
+ rv.d = 0.;
+ for(s = s00;;s++) switch(*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ s = s00;
+ goto ret;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+ break2:
+ if (*s == '0') {
+ nz0 = 1;
+ while(*++s == '0') ;
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ y = z = 0;
+ for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10*y + c - '0';
+ else if (nd < 16)
+ z = 10*z + c - '0';
+ nd0 = nd;
+ if (c == '.') {
+ c = *++s;
+ if (!nd) {
+ for(; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+ nz++;
+ if (c -= '0') {
+ nf += nz;
+ for(i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 1)
+ z *= 10;
+ if (nd++ < 9)
+ y = 10*y + c;
+ else if (nd <= DBL_DIG + 1)
+ z = 10*z + c;
+ nz = 0;
+ }
+ }
+ }
+ dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ s = s00;
+ goto ret;
+ }
+ s00 = s;
+ esign = 0;
+ switch(c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while(c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ e = c - '0';
+ s1 = s;
+ while((c = *++s) >= '0' && c <= '9')
+ e = 10*e + c - '0';
+ if (s - s1 > 8)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 9999999;
+ if (esign)
+ e = -e;
+ }
+ else
+ e = 0;
+ }
+ else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0)
+ s = s00;
+ goto ret;
+ }
+ e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+ rv.d = y;
+ if (k > 9)
+ rv.d = tens[k - 9] * rv.d + z;
+ bd0 = 0;
+ if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+ && FLT_ROUNDS == 1
+#endif
+ ) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+#ifdef VAX
+ goto vax_ovfl_check;
+#else
+ /* rv = */ rounded_product(rv.d, tens[e]);
+ goto ret;
+#endif
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+ e -= i;
+ rv.d *= tens[i];
+#ifdef VAX
+ /* VAX exponent range is so narrow we must
+ * worry about overflow here...
+ */
+ vax_ovfl_check:
+ word0(rv) -= P*Exp_msk1;
+ /* rv = */ rounded_product(rv.d, tens[e]);
+ if ((word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+ goto ovfl;
+ word0(rv) += P*Exp_msk1;
+#else
+ /* rv = */ rounded_product(rv.d, tens[e]);
+#endif
+ goto ret;
+ }
+ }
+ else if (e >= -Ten_pmax) {
+ /* rv = */ rounded_quotient(rv.d, tens[-e]);
+ goto ret;
+ }
+ }
+ e1 += nd - k;
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if (nd0 + e1 - 1 > DBL_MAX_10_EXP)
+ goto ovfl;
+ if (i = e1 & 15)
+ rv.d *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+ errno = ERANGE;
+ rv.d = HUGE_VAL;
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ if (e1 >>= 4) {
+ for(j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ rv.d *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(rv) -= P*Exp_msk1;
+ rv.d *= bigtens[j];
+ if ((z = word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+ goto ovfl;
+ if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+
+ }
+ }
+ else if (e1 < 0) {
+ e1 = -e1;
+ if (i = e1 & 15)
+ rv.d /= tens[i];
+ if (e1 &= ~15) {
+ e1 >>= 4;
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+ for(j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ rv.d *= tinytens[j];
+ /* The last multiplication could underflow. */
+ rv0.d = rv.d;
+ rv.d *= tinytens[j];
+ if (rv.d == 0) {
+ rv.d = 2.*rv0.d;
+ rv.d *= tinytens[j];
+ if (rv.d == 0) {
+ undfl:
+ rv.d = 0.;
+ errno = ERANGE;
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ /* The refinement below will clean
+ * this approximation up.
+ */
+ }
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bd0 = s2b(s0, nd0, nd, y);
+
+ for(;;) {
+ bd = Balloc(bd0->k);
+ Bcopy(bd, bd0);
+ bb = d2b(rv.d, &bbe, &bbbits); /* rv = bb * 2^bbe */
+ bs = i2b(1);
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ }
+ else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+#ifdef Sudden_Underflow
+#ifdef IBM
+ j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+ j = P + 1 - bbbits;
+#endif
+#else
+ i = bbe + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j = bbe + (P-Emin);
+ else
+ j = P + 1 - bbbits;
+#endif
+ bb2 += j;
+ bd2 += j;
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ bb1 = mult(bs, bb);
+ Bfree(bb);
+ bb = bb1;
+ }
+ if (bb2 > 0)
+ bb = lshift(bb, bb2);
+ if (bd5 > 0)
+ bd = pow5mult(bd, bd5);
+ if (bd2 > 0)
+ bd = lshift(bd, bd2);
+ if (bs2 > 0)
+ bs = lshift(bs, bs2);
+ delta = diff(bb, bd);
+ dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask)
+ break;
+ delta = lshift(delta,Log2P);
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+ && word1(rv) == 0xffffffff) {
+ /*boundary case -- increment exponent*/
+ word0(rv) = (word0(rv) & Exp_mask)
+ + Exp_msk1
+#ifdef IBM
+ | Exp_msk1 >> 4
+#endif
+ ;
+ word1(rv) = 0;
+ break;
+ }
+ }
+ else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+ drop_down:
+ /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow
+ L = word0(rv) & Exp_mask;
+#ifdef IBM
+ if (L < Exp_msk1)
+#else
+ if (L <= Exp_msk1)
+#endif
+ goto undfl;
+ L -= Exp_msk1;
+#else
+ L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif
+ word0(rv) = L | Bndry_mask1;
+ word1(rv) = 0xffffffff;
+#ifdef IBM
+ goto cont;
+#else
+ break;
+#endif
+ }
+#ifndef ROUND_BIASED
+ if (!(word1(rv) & LSB))
+ break;
+#endif
+ if (dsign)
+ rv.d += ulp(rv.d);
+#ifndef ROUND_BIASED
+ else {
+ rv.d -= ulp(rv.d);
+#ifndef Sudden_Underflow
+ if (rv.d == 0)
+ goto undfl;
+#endif
+ }
+#endif
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = aadj1 = 1.;
+ else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+ if (word1(rv) == Tiny1 && !word0(rv))
+ goto undfl;
+#endif
+ aadj = 1.;
+ aadj1 = -1.;
+ }
+ else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2./FLT_RADIX)
+ aadj = 1./FLT_RADIX;
+ else
+ aadj *= 0.5;
+ aadj1 = -aadj;
+ }
+ }
+ else {
+ aadj *= 0.5;
+ aadj1 = dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+ switch(FLT_ROUNDS) {
+ case 2: /* towards +infinity */
+ aadj1 -= 0.5;
+ break;
+ case 0: /* towards 0 */
+ case 3: /* towards -infinity */
+ aadj1 += 0.5;
+ }
+#else
+ if (FLT_ROUNDS == 0)
+ aadj1 += 0.5;
+#endif
+ }
+ y = word0(rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+ rv0.d = rv.d;
+ word0(rv) -= P*Exp_msk1;
+ adj = aadj1 * ulp(rv.d);
+ rv.d += adj;
+ if ((word0(rv) & Exp_mask) >=
+ Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+ if (word0(rv0) == Big0 && word1(rv0) == Big1)
+ goto ovfl;
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ goto cont;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+ else {
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ rv0.d = rv.d;
+ word0(rv) += P*Exp_msk1;
+ adj = aadj1 * ulp(rv.d);
+ rv.d += adj;
+#ifdef IBM
+ if ((word0(rv) & Exp_mask) < P*Exp_msk1)
+#else
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+ {
+ if (word0(rv0) == Tiny0
+ && word1(rv0) == Tiny1)
+ goto undfl;
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ goto cont;
+ }
+ else
+ word0(rv) -= P*Exp_msk1;
+ }
+ else {
+ adj = aadj1 * ulp(rv.d);
+ rv.d += adj;
+ }
+#else
+ /* Compute adj so that the IEEE rounding rules will
+ * correctly round rv + adj in some half-way cases.
+ * If rv * ulp(rv) is denormalized (i.e.,
+ * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+ * trouble from bits lost to denormalization;
+ * example: 1.2e-307 .
+ */
+ if (y <= (P-1)*Exp_msk1 && aadj >= 1.) {
+ aadj1 = (double)(int)(aadj + 0.5);
+ if (!dsign)
+ aadj1 = -aadj1;
+ }
+ adj = aadj1 * ulp(rv.d);
+ rv.d += adj;
+#endif
+ }
+ z = word0(rv) & Exp_mask;
+ if (y == z) {
+ /* Can we stop now? */
+ L = aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ }
+ else if (aadj < .4999999/FLT_RADIX)
+ break;
+ }
+ cont:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ }
+ retfree:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ ret:
+ if (se)
+ *se = (char *)s;
+ return sign ? -rv.d : rv.d;
+ }
diff --git a/sys/src/ape/lib/ap/stdio/tmpfile.c b/sys/src/ape/lib/ap/stdio/tmpfile.c
new file mode 100755
index 000000000..751986c78
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/tmpfile.c
@@ -0,0 +1,32 @@
+/*
+ * This file not used on plan9: see ../plan9/tmpfile.c
+ */
+/*
+ * pANS stdio -- tmpfile
+ *
+ * Bug: contains a critical section. Two executions by the same
+ * user could interleave as follows, both yielding the same file:
+ * access fails
+ * access fails
+ * fopen succeeds
+ * fopen succeeds
+ * unlink succeeds
+ * unlink fails
+ * As I read the pANS, this can't reasonably use tmpnam to generate
+ * the name, so that code is duplicated.
+ */
+#include "iolib.h"
+FILE *tmpfile(void){
+ FILE *f;
+ static char name[]="/tmp/tf000000000000";
+ char *p;
+ while(access(name, 0)==0){
+ p=name+7;
+ while(*p=='9') *p++='0';
+ if(*p=='\0') return NULL;
+ ++*p;
+ }
+ f=fopen(name, "wb+");
+ unlink(name);
+ return f;
+}
diff --git a/sys/src/ape/lib/ap/stdio/tmpnam.c b/sys/src/ape/lib/ap/stdio/tmpnam.c
new file mode 100755
index 000000000..6ab301378
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/tmpnam.c
@@ -0,0 +1,33 @@
+/*
+ * pANS stdio -- tmpnam
+ */
+#include "iolib.h"
+#include <string.h>
+
+char *
+tmpnam(char *s)
+{
+ static char name[] = "/tmp/tn000000000000";
+ char *p;
+
+ do {
+ p = name + 7;
+ while (*p == '9')
+ *p++ = '0';
+ if (*p == '\0')
+ return NULL;
+ ++*p;
+ } while (access(name, 0) == 0);
+ if (s) {
+ strcpy(s, name);
+ return s;
+ }
+ return name;
+}
+
+
+char *
+tmpnam_r(char *s)
+{
+ return s ? tmpnam(s) : NULL;
+}
diff --git a/sys/src/ape/lib/ap/stdio/ungetc.c b/sys/src/ape/lib/ap/stdio/ungetc.c
new file mode 100755
index 000000000..3c071690b
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/ungetc.c
@@ -0,0 +1,33 @@
+/*
+ * pANS stdio -- ungetc
+ */
+#include "iolib.h"
+int ungetc(int c, FILE *f){
+ if(c==EOF) return EOF;
+ switch(f->state){
+ default: /* WR */
+ f->state=ERR;
+ return EOF;
+ case CLOSED:
+ case ERR:
+ return EOF;
+ case OPEN:
+ _IO_setvbuf(f);
+ case RDWR:
+ case END:
+ f->wp=f->buf;
+ if(f->bufl==0)
+ f->wp += 1;
+ else
+ f->wp += f->bufl;
+ f->rp = f->wp;
+ f->state=RD;
+ case RD:
+ if(f->rp==f->buf) return EOF;
+ if(f->flags&STRING)
+ f->rp--;
+ else
+ *--f->rp=c;
+ return (char)c;
+ }
+}
diff --git a/sys/src/ape/lib/ap/stdio/vfprintf.c b/sys/src/ape/lib/ap/stdio/vfprintf.c
new file mode 100755
index 000000000..dc8c406ff
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/vfprintf.c
@@ -0,0 +1,566 @@
+/*
+ * pANS stdio -- vfprintf
+ */
+#include "iolib.h"
+#include <stdarg.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+/*
+ * Leading flags
+ */
+#define SPACE 1 /* ' ' prepend space if no sign printed */
+#define ALT 2 /* '#' use alternate conversion */
+#define SIGN 4 /* '+' prepend sign, even if positive */
+#define LEFT 8 /* '-' left-justify */
+#define ZPAD 16 /* '0' zero-pad */
+/*
+ * Trailing flags
+ */
+#define SHORT 32 /* 'h' convert a short integer */
+#define LONG 64 /* 'l' convert a long integer */
+#define LDBL 128 /* 'L' convert a long double */
+#define PTR 256 /* convert a void * (%p) */
+#define VLONG 512 /* 'll' convert a long long integer */
+
+static int lflag[] = { /* leading flags */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
+SPACE, 0, 0, ALT, 0, 0, 0, 0, /* sp ! " # $ % & ' */
+0, 0, 0, SIGN, 0, LEFT, 0, 0, /* ( ) * + , - . / */
+ZPAD, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
+0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
+0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
+0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
+0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
+0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
+0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
+0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
+0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
+0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
+
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static int tflag[] = { /* trailing flags */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
+0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
+0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
+0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
+0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
+0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
+0, 0, 0, 0, LDBL, 0, 0, 0, /* H I J K L M N O */
+0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
+0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
+0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
+SHORT, 0, 0, 0, LONG, 0, 0, 0, /* h i j k l m n o */
+0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
+0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
+
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static int ocvt_E(FILE *, va_list *, int, int, int);
+static int ocvt_G(FILE *, va_list *, int, int, int);
+static int ocvt_X(FILE *, va_list *, int, int, int);
+static int ocvt_c(FILE *, va_list *, int, int, int);
+static int ocvt_d(FILE *, va_list *, int, int, int);
+static int ocvt_e(FILE *, va_list *, int, int, int);
+static int ocvt_f(FILE *, va_list *, int, int, int);
+static int ocvt_g(FILE *, va_list *, int, int, int);
+static int ocvt_n(FILE *, va_list *, int, int, int);
+static int ocvt_o(FILE *, va_list *, int, int, int);
+static int ocvt_p(FILE *, va_list *, int, int, int);
+static int ocvt_s(FILE *, va_list *, int, int, int);
+static int ocvt_u(FILE *, va_list *, int, int, int);
+static int ocvt_x(FILE *, va_list *, int, int, int);
+
+static int(*ocvt[])(FILE *, va_list *, int, int, int) = {
+0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
+0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
+0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
+0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
+0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
+0, 0, 0, 0, 0, ocvt_E, 0, ocvt_G, /* @ A B C D E F G */
+0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
+0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
+ocvt_X, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
+0, 0, 0, ocvt_c, ocvt_d, ocvt_e, ocvt_f, ocvt_g, /* ` a b c d e f g */
+0, ocvt_d, 0, 0, 0, 0, ocvt_n, ocvt_o, /* h i j k l m n o */
+ocvt_p, 0, 0, ocvt_s, 0, ocvt_u, 0, 0, /* p q r s t u v w */
+ocvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
+
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static int nprint;
+
+int
+vfprintf(FILE *f, const char *s, va_list args)
+{
+ int tfl, flags, width, precision;
+
+ nprint = 0;
+ while(*s){
+ if(*s != '%'){
+ putc(*s++, f);
+ nprint++;
+ continue;
+ }
+ s++;
+ flags = 0;
+ while(lflag[*s&_IO_CHMASK]) flags |= lflag[*s++&_IO_CHMASK];
+ if(*s == '*'){
+ width = va_arg(args, int);
+ s++;
+ if(width<0){
+ flags |= LEFT;
+ width = -width;
+ }
+ }
+ else{
+ width = 0;
+ while('0'<=*s && *s<='9') width = width*10 + *s++ - '0';
+ }
+ if(*s == '.'){
+ s++;
+ if(*s == '*'){
+ precision = va_arg(args, int);
+ s++;
+ }
+ else{
+ precision = 0;
+ while('0'<=*s && *s<='9') precision = precision*10 + *s++ - '0';
+ }
+ }
+ else
+ precision = -1;
+ while(tfl = tflag[*s&_IO_CHMASK]){
+ if(tfl == LONG && (flags & LONG)){
+ flags &= ~LONG;
+ tfl = VLONG;
+ }
+ flags |= tfl;
+ s++;
+ }
+ if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
+ else if(*s){
+ putc(*s++, f);
+ nprint++;
+ }
+ }
+ return ferror(f)? -1: nprint;;
+}
+
+static int
+ocvt_c(FILE *f, va_list *args, int flags, int width, int precision)
+{
+#pragma ref precision
+ int i;
+
+ if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
+ putc((unsigned char)va_arg(*args, int), f);
+ if(flags&LEFT) for(i=1; i<width; i++) putc(' ', f);
+ return width<1 ? 1 : width;
+}
+
+static int
+ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ int i, n = 0;
+ char *s;
+
+ s = va_arg(*args, char *);
+ if(!s)
+ s = "";
+ if(!(flags&LEFT)){
+ if(precision >= 0)
+ for(i=0; i!=precision && s[i]; i++);
+ else
+ for(i=0; s[i]; i++);
+ for(; i<width; i++){
+ putc(' ', f);
+ n++;
+ }
+ }
+ if(precision >= 0){
+ for(i=0; i!=precision && *s; i++){
+ putc(*s++, f);
+ n++;
+ }
+ } else{
+ for(i=0;*s;i++){
+ putc(*s++, f);
+ n++;
+ }
+ }
+ if(flags&LEFT){
+ for(; i<width; i++){
+ putc(' ', f);
+ n++;
+ }
+ }
+ return n;
+}
+
+static int
+ocvt_n(FILE *f, va_list *args, int flags, int width, int precision)
+{
+#pragma ref f
+#pragma ref width
+#pragma ref precision
+ if(flags&SHORT)
+ *va_arg(*args, short *) = nprint;
+ else if(flags&LONG)
+ *va_arg(*args, long *) = nprint;
+ else if(flags&VLONG)
+ *va_arg(*args, long long*) = nprint;
+ else
+ *va_arg(*args, int *) = nprint;
+ return 0;
+}
+
+/*
+ * Generic fixed-point conversion
+ * f is the output FILE *;
+ * args is the va_list * from which to get the number;
+ * flags, width and precision are the results of printf-cracking;
+ * radix is the number base to print in;
+ * alphabet is the set of digits to use;
+ * prefix is the prefix to print before non-zero numbers when
+ * using ``alternate form.''
+ */
+static int
+ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
+ int radix, int sgned, char alphabet[], char *prefix)
+{
+ char digits[128]; /* no reasonable machine will ever overflow this */
+ char *sign;
+ char *dp;
+ long long snum;
+ unsigned long long num;
+ int nout, npad, nlzero;
+
+ if(sgned){
+ if(flags&PTR) snum = (long)va_arg(*args, void *);
+ else if(flags&SHORT) snum = va_arg(*args, short);
+ else if(flags&LONG) snum = va_arg(*args, long);
+ else if(flags&VLONG) snum = va_arg(*args, long long);
+ else snum = va_arg(*args, int);
+ if(snum < 0){
+ sign = "-";
+ num = -snum;
+ } else{
+ if(flags&SIGN) sign = "+";
+ else if(flags&SPACE) sign = " ";
+ else sign = "";
+ num = snum;
+ }
+ } else {
+ sign = "";
+ if(flags&PTR) num = (long)va_arg(*args, void *);
+ else if(flags&SHORT) num = va_arg(*args, unsigned short);
+ else if(flags&LONG) num = va_arg(*args, unsigned long);
+ else if(flags&VLONG) num = va_arg(*args, unsigned long long);
+ else num = va_arg(*args, unsigned int);
+ }
+ if(num == 0) prefix = "";
+ dp = digits;
+ do{
+ *dp++ = alphabet[num%radix];
+ num /= radix;
+ }while(num);
+ if(precision==0 && dp-digits==1 && dp[-1]=='0')
+ dp--;
+ nlzero = precision-(dp-digits);
+ if(nlzero < 0) nlzero = 0;
+ if(flags&ALT){
+ if(radix == 8) if(dp[-1]=='0' || nlzero) prefix = "";
+ }
+ else prefix = "";
+ nout = dp-digits+nlzero+strlen(prefix)+strlen(sign);
+ npad = width-nout;
+ if(npad < 0) npad = 0;
+ nout += npad;
+ if(!(flags&LEFT)){
+ if(flags&ZPAD && precision <= 0){
+ fputs(sign, f);
+ fputs(prefix, f);
+ while(npad){
+ putc('0', f);
+ --npad;
+ }
+ } else{
+ while(npad){
+ putc(' ', f);
+ --npad;
+ }
+ fputs(sign, f);
+ fputs(prefix, f);
+ }
+ while(nlzero){
+ putc('0', f);
+ --nlzero;
+ }
+ while(dp!=digits) putc(*--dp, f);
+ }
+ else{
+ fputs(sign, f);
+ fputs(prefix, f);
+ while(nlzero){
+ putc('0', f);
+ --nlzero;
+ }
+ while(dp != digits) putc(*--dp, f);
+ while(npad){
+ putc(' ', f);
+ --npad;
+ }
+ }
+ return nout;
+}
+
+static int
+ocvt_X(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789ABCDEF", "0X");
+}
+
+static int
+ocvt_d(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_fixed(f, args, flags, width, precision, 10, 1, "0123456789", "");
+}
+
+static int
+ocvt_o(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_fixed(f, args, flags, width, precision, 8, 0, "01234567", "0");
+}
+
+static int
+ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
+ "0123456789ABCDEF", "0x");
+}
+
+static int
+ocvt_u(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_fixed(f, args, flags, width, precision, 10, 0, "0123456789", "");
+}
+
+static int
+ocvt_x(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789abcdef", "0x");
+}
+
+static int ocvt_flt(FILE *, va_list *, int, int, int, char);
+
+static int
+ocvt_E(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_flt(f, args, flags, width, precision, 'E');
+}
+
+static int
+ocvt_G(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_flt(f, args, flags, width, precision, 'G');
+}
+
+static int
+ocvt_e(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_flt(f, args, flags, width, precision, 'e');
+}
+
+static int
+ocvt_f(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_flt(f, args, flags, width, precision, 'f');
+}
+
+static int
+ocvt_g(FILE *f, va_list *args, int flags, int width, int precision)
+{
+ return ocvt_flt(f, args, flags, width, precision, 'g');
+}
+
+static int
+ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
+{
+ extern char *_dtoa(double, int, int, int*, int*, char **);
+ int echr;
+ char *digits, *edigits;
+ int exponent;
+ char fmt;
+ int sign;
+ int ndig;
+ int nout, i;
+ char ebuf[20]; /* no sensible machine will overflow this */
+ char *eptr;
+ double d;
+
+ echr = 'e';
+ fmt = afmt;
+ d = va_arg(*args, double);
+ if(precision < 0) precision = 6;
+ switch(fmt){
+ case 'f':
+ digits = _dtoa(d, 3, precision, &exponent, &sign, &edigits);
+ break;
+ case 'E':
+ echr = 'E';
+ fmt = 'e';
+ /* fall through */
+ case 'e':
+ digits = _dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
+ break;
+ case 'G':
+ echr = 'E';
+ /* fall through */
+ case 'g':
+ if (precision > 0)
+ digits = _dtoa(d, 2, precision, &exponent, &sign, &edigits);
+ else {
+ digits = _dtoa(d, 0, precision, &exponent, &sign, &edigits);
+ precision = edigits - digits;
+ if (exponent > precision && exponent <= precision + 4)
+ precision = exponent;
+ }
+ if(exponent >= -3 && exponent <= precision){
+ fmt = 'f';
+ precision -= exponent;
+ }else{
+ fmt = 'e';
+ --precision;
+ }
+ break;
+ }
+ if (exponent == 9999) {
+ /* Infinity or Nan */
+ precision = 0;
+ exponent = edigits - digits;
+ fmt = 'f';
+ }
+ ndig = edigits-digits;
+ if(ndig == 0) {
+ ndig = 1;
+ digits = "0";
+ }
+ if((afmt=='g' || afmt=='G') && !(flags&ALT)){ /* knock off trailing zeros */
+ if(fmt == 'f'){
+ if(precision+exponent > ndig) {
+ precision = ndig - exponent;
+ if(precision < 0)
+ precision = 0;
+ }
+ }
+ else{
+ if(precision > ndig-1) precision = ndig-1;
+ }
+ }
+ nout = precision; /* digits after decimal point */
+ if(precision!=0 || flags&ALT) nout++; /* decimal point */
+ if(fmt=='f' && exponent>0) nout += exponent; /* digits before decimal point */
+ else nout++; /* there's always at least one */
+ if(sign || flags&(SPACE|SIGN)) nout++; /* sign */
+ if(fmt != 'f'){ /* exponent */
+ eptr = ebuf;
+ for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
+ *eptr++ = '0' + i%10;
+ while(eptr<ebuf+2) *eptr++ = '0';
+ nout += eptr-ebuf+2; /* e+99 */
+ }
+ if(!(flags&ZPAD) && !(flags&LEFT))
+ while(nout < width){
+ putc(' ', f);
+ nout++;
+ }
+ if(sign) putc('-', f);
+ else if(flags&SIGN) putc('+', f);
+ else if(flags&SPACE) putc(' ', f);
+ if((flags&ZPAD) && !(flags&LEFT))
+ while(nout < width){
+ putc('0', f);
+ nout++;
+ }
+ if(fmt == 'f'){
+ for(i=0; i<exponent; i++) putc(i<ndig?digits[i]:'0', f);
+ if(i == 0) putc('0', f);
+ if(precision>0 || flags&ALT) putc('.', f);
+ for(i=0; i!=precision; i++)
+ putc(0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0', f);
+ }
+ else{
+ putc(digits[0], f);
+ if(precision>0 || flags&ALT) putc('.', f);
+ for(i=0; i!=precision; i++) putc(i<ndig-1?digits[i+1]:'0', f);
+ }
+ if(fmt != 'f'){
+ putc(echr, f);
+ putc(exponent<=0?'-':'+', f);
+ while(eptr>ebuf) putc(*--eptr, f);
+ }
+ while(nout < width){
+ putc(' ', f);
+ nout++;
+ }
+ return nout;
+}
diff --git a/sys/src/ape/lib/ap/stdio/vfscanf.c b/sys/src/ape/lib/ap/stdio/vfscanf.c
new file mode 100755
index 000000000..14a55956c
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/vfscanf.c
@@ -0,0 +1,367 @@
+/*
+ * pANS stdio -- vfscanf
+ */
+#include "iolib.h"
+#include <stdarg.h>
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+static int icvt_f(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_x(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_sq(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_c(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_d(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_i(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_n(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_o(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_p(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_s(FILE *f, va_list *args, int store, int width, int type);
+static int icvt_u(FILE *f, va_list *args, int store, int width, int type);
+static int (*icvt[])(FILE *, va_list *, int, int, int)={
+0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
+0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
+0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
+0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
+0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
+0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
+0, 0, 0, 0, 0, icvt_f, 0, icvt_f, /* @ A B C D E F G */
+0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
+0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
+icvt_x, 0, 0, icvt_sq,0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
+0, 0, 0, icvt_c, icvt_d, icvt_f, icvt_f, icvt_f, /* ` a b c d e f g */
+0, icvt_i, 0, 0, 0, 0, icvt_n, icvt_o, /* h i j k l m n o */
+icvt_p, 0, 0, icvt_s, 0, icvt_u, 0, 0, /* p q r s t u v w */
+icvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
+
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0,
+
+};
+#define ngetc(f) (nread++, getc(f))
+#define nungetc(c, f) (--nread, ungetc((c), f))
+#define wgetc(c, f, out) if(width--==0) goto out; (c)=ngetc(f)
+#define wungetc(c, f) (++width, nungetc(c, f))
+static int nread, ncvt;
+static const char *fmtp;
+
+int vfscanf(FILE *f, const char *s, va_list args){
+ int c, width, type, store;
+ nread=0;
+ ncvt=0;
+ fmtp=s;
+ for(;*fmtp;fmtp++) switch(*fmtp){
+ default:
+ if(isspace(*fmtp)){
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(c==EOF) return ncvt?ncvt:EOF;
+ nungetc(c, f);
+ break;
+ }
+ NonSpecial:
+ c=ngetc(f);
+ if(c==EOF) return ncvt?ncvt:EOF;
+ if(c!=*fmtp){
+ nungetc(c, f);
+ return ncvt;
+ }
+ break;
+ case '%':
+ fmtp++;
+ if(*fmtp!='*') store=1;
+ else{
+ store=0;
+ fmtp++;
+ }
+ if('0'<=*fmtp && *fmtp<='9'){
+ width=0;
+ while('0'<=*fmtp && *fmtp<='9') width=width*10 + *fmtp++ - '0';
+ }
+ else
+ width=-1;
+ type=*fmtp=='h' || *fmtp=='l' || *fmtp=='L'?*fmtp++:'n';
+ if(!icvt[*fmtp]) goto NonSpecial;
+ if(!(*icvt[*fmtp])(f, &args, store, width, type))
+ return ncvt?ncvt:EOF;
+ if(*fmtp=='\0') break;
+ if(store) ncvt++;
+ }
+ return ncvt;
+}
+static int icvt_n(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref f
+#pragma ref width
+ if(store){
+ --ncvt; /* this assignment doesn't count! */
+ switch(type){
+ case 'h': *va_arg(*args, short *)=nread; break;
+ case 'n': *va_arg(*args, int *)=nread; break;
+ case 'l':
+ case 'L': *va_arg(*args, long *)=nread; break;
+ }
+ }
+ return 1;
+}
+#define SIGNED 1
+#define UNSIGNED 2
+#define POINTER 3
+/*
+ * Generic fixed-point conversion
+ * f is the input FILE *;
+ * args is the va_list * into which to store the number;
+ * store is a flag to enable storing;
+ * width is the maximum field width;
+ * type is 'h' 'l' or 'L', the scanf type modifier;
+ * unsgned is SIGNED, UNSIGNED or POINTER, giving part of the type to store in;
+ * base is the number base -- if 0, C number syntax is used.
+ */
+static int icvt_fixed(FILE *f, va_list *args,
+ int store, int width, int type, int unsgned, int base){
+ unsigned long int num=0;
+ int sign=1, ndig=0, dig;
+ int c;
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(width--==0){
+ nungetc(c, f);
+ goto Done;
+ }
+ if(c=='+'){
+ wgetc(c, f, Done);
+ }
+ else if(c=='-'){
+ sign=-1;
+ wgetc(c, f, Done);
+ }
+ switch(base){
+ case 0:
+ if(c=='0'){
+ wgetc(c, f, Done);
+ if(c=='x' || c=='X'){
+ wgetc(c, f, Done);
+ base=16;
+ }
+ else{
+ ndig=1;
+ base=8;
+ }
+ }
+ else
+ base=10;
+ break;
+ case 16:
+ if(c=='0'){
+ wgetc(c, f, Done);
+ if(c=='x' || c=='X'){
+ wgetc(c, f, Done);
+ }
+ else ndig=1;
+ }
+ break;
+ }
+ while('0'<=c && c<='9' || 'a'<=c && c<='f' || 'A'<=c && c<='F'){
+ dig='0'<=c && c<='9'?c-'0':'a'<=c && c<='f'?c-'a'+10:c-'A'+10;
+ if(dig>=base) break;
+ ndig++;
+ num=num*base+dig;
+ wgetc(c, f, Done);
+ }
+ nungetc(c, f);
+Done:
+ if(ndig==0) return 0;
+ if(store){
+ switch(unsgned){
+ case SIGNED:
+ switch(type){
+ case 'h': *va_arg(*args, short *)=num*sign; break;
+ case 'n': *va_arg(*args, int *)=num*sign; break;
+ case 'l':
+ case 'L': *va_arg(*args, long *)=num*sign; break;
+ }
+ break;
+ case UNSIGNED:
+ switch(type){
+ case 'h': *va_arg(*args, unsigned short *)=num*sign; break;
+ case 'n': *va_arg(*args, unsigned int *)=num*sign; break;
+ case 'l':
+ case 'L': *va_arg(*args, unsigned long *)=num*sign; break;
+ }
+ break;
+ case POINTER:
+ *va_arg(*args, void **)=(void *)(num*sign); break;
+ }
+ }
+ return 1;
+}
+static int icvt_d(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, SIGNED, 10);
+}
+static int icvt_x(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, UNSIGNED, 16);
+}
+static int icvt_o(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, UNSIGNED, 8);
+}
+static int icvt_i(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, SIGNED, 0);
+}
+static int icvt_u(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, UNSIGNED, 10);
+}
+static int icvt_p(FILE *f, va_list *args, int store, int width, int type){
+ return icvt_fixed(f, args, store, width, type, POINTER, 16);
+}
+#define NBUF 509
+static int icvt_f(FILE *f, va_list *args, int store, int width, int type){
+ char buf[NBUF+1];
+ char *s=buf;
+ int c, ndig=0, ndpt=0, nexp=1;
+ if(width<0 || NBUF<width) width=NBUF; /* bug -- no limit specified in ansi */
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(width--==0){
+ nungetc(c, f);
+ goto Done;
+ }
+ if(c=='+' || c=='-'){
+ *s++=c;
+ wgetc(c, f, Done);
+ }
+ while('0'<=c && c<='9' || ndpt==0 && c=='.'){
+ if(c=='.') ndpt++;
+ else ndig++;
+ *s++=c;
+ wgetc(c, f, Done);
+ }
+ if(c=='e' || c=='E'){
+ *s++=c;
+ nexp=0;
+ wgetc(c, f, Done);
+ if(c=='+' || c=='-'){
+ *s++=c;
+ wgetc(c, f, Done);
+ }
+ while('0'<=c && c<='9'){
+ *s++=c;
+ nexp++;
+ wgetc(c, f, Done);
+ }
+ }
+ nungetc(c, f);
+Done:
+ if(ndig==0 || nexp==0) return 0;
+ *s='\0';
+ if(store) switch(type){
+ case 'h':
+ case 'n': *va_arg(*args, float *)=atof(buf); break;
+ case 'L': /* bug -- should store in a long double */
+ case 'l': *va_arg(*args, double *)=atof(buf); break;
+ }
+ return 1;
+}
+static int icvt_s(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref type
+ int c, nn;
+ register char *s;
+ if(store) s=va_arg(*args, char *);
+ do
+ c=ngetc(f);
+ while(isspace(c));
+ if(width--==0){
+ nungetc(c, f);
+ goto Done;
+ }
+ nn=0;
+ while(!isspace(c)){
+ if(c==EOF){
+ nread--;
+ if(nn==0) return 0;
+ else goto Done;
+ }
+ nn++;
+ if(store) *s++=c;
+ wgetc(c, f, Done);
+ }
+ nungetc(c, f);
+Done:
+ if(store) *s='\0';
+ return 1;
+}
+static int icvt_c(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref type
+ int c;
+ register char *s;
+ if(store) s=va_arg(*args, char *);
+ if(width<0) width=1;
+ for(;;){
+ wgetc(c, f, Done);
+ if(c==EOF) return 0;
+ if(store) *s++=c;
+ }
+Done:
+ return 1;
+}
+static int match(int c, const char *pat){
+ int ok=1;
+ if(*pat=='^'){
+ ok=!ok;
+ pat++;
+ }
+ while(pat!=fmtp){
+ if(pat+2<fmtp && pat[1]=='-'){
+ if(pat[0]<=c && c<=pat[2]
+ || pat[2]<=c && c<=pat[0])
+ return ok;
+ pat+=2;
+ }
+ else if(c==*pat) return ok;
+ pat++;
+ }
+ return !ok;
+}
+static int icvt_sq(FILE *f, va_list *args, int store, int width, int type){
+#pragma ref type
+ int c, nn;
+ register char *s;
+ register const char *pat;
+ pat=++fmtp;
+ if(*fmtp=='^') fmtp++;
+ if(*fmtp!='\0') fmtp++;
+ while(*fmtp!='\0' && *fmtp!=']') fmtp++;
+ if(store) s=va_arg(*args, char *);
+ nn=0;
+ for(;;){
+ wgetc(c, f, Done);
+ if(c==EOF){
+ nread--;
+ if(nn==0) return 0;
+ else goto Done;
+ }
+ if(!match(c, pat)) break;
+ if(store) *s++=c;
+ nn++;
+ }
+ nungetc(c, f);
+Done:
+ if(store) *s='\0';
+ return 1;
+}
diff --git a/sys/src/ape/lib/ap/stdio/vprintf.c b/sys/src/ape/lib/ap/stdio/vprintf.c
new file mode 100755
index 000000000..6576219eb
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/vprintf.c
@@ -0,0 +1,7 @@
+/*
+ * pANS stdio -- vprintf
+ */
+#include "iolib.h"
+int vprintf(const char *fmt, va_list args){
+ return vfprintf(stdout, fmt, args);
+}
diff --git a/sys/src/ape/lib/ap/stdio/vsnprintf.c b/sys/src/ape/lib/ap/stdio/vsnprintf.c
new file mode 100755
index 000000000..45830fffb
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/vsnprintf.c
@@ -0,0 +1,17 @@
+/*
+ * pANS stdio -- vsnprintf
+ */
+#define _C99_SNPRINTF_EXTENSION
+
+#include "iolib.h"
+
+int vsnprintf(char *buf, size_t nbuf, const char *fmt, va_list args){
+ int n;
+ FILE *f=_IO_sopenw();
+ if(f==NULL)
+ return 0;
+ setvbuf(f, buf, _IOFBF, nbuf);
+ n=vfprintf(f, fmt, args);
+ _IO_sclose(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/stdio/vsprintf.c b/sys/src/ape/lib/ap/stdio/vsprintf.c
new file mode 100755
index 000000000..7b3fe6ec4
--- /dev/null
+++ b/sys/src/ape/lib/ap/stdio/vsprintf.c
@@ -0,0 +1,14 @@
+/*
+ * pANS stdio -- vsprintf
+ */
+#include "iolib.h"
+int vsprintf(char *buf, const char *fmt, va_list args){
+ int n;
+ FILE *f=_IO_sopenw();
+ if(f==NULL)
+ return 0;
+ setvbuf(f, buf, _IOFBF, 100000);
+ n=vfprintf(f, fmt, args);
+ _IO_sclose(f);
+ return n;
+}
diff --git a/sys/src/ape/lib/ap/syscall/genall b/sys/src/ape/lib/ap/syscall/genall
new file mode 100755
index 000000000..5aa992b95
--- /dev/null
+++ b/sys/src/ape/lib/ap/syscall/genall
@@ -0,0 +1,16 @@
+#!/bin/rc
+# genall - generate the APE versions of the system call C interfaces.
+# must be invoked by mk so that the right env variables are set.
+rfork e
+# ugh. sources's build process can't hack absolute path names.
+# we're in /sys/src/ape/lib/ap/syscall.
+SYSH=../../../../libc/9syscall/sys.h # /sys/src/libc/9syscall/sys.h
+
+SYS=`{sed '/^#define._/d; s/#define.([A-Z0-9_]*).*/\1/' $SYSH}
+for(I in $SYS) {
+ i=_^$I
+ n=`{sed -n '/[ ]'$I'[ ]/s/.* //p' $SYSH}
+ gencall
+}
+ar vu /$objtype/lib/ape/libap.a *.$O
+rm -f *.$O *.s
diff --git a/sys/src/ape/lib/ap/syscall/mkfile b/sys/src/ape/lib/ap/syscall/mkfile
new file mode 100755
index 000000000..080839d9a
--- /dev/null
+++ b/sys/src/ape/lib/ap/syscall/mkfile
@@ -0,0 +1,25 @@
+NPROC=1
+</$objtype/mkfile
+
+all:V: install
+
+install:V: genall gencall
+ genall
+
+# ugh. sources's build process can't hack absolute path names.
+# we're in /sys/src/ape/lib/ap/syscall.
+gencall:D: ../../../../libc/9syscall/mkfile # /sys/src/libc/9syscall/mkfile
+ {
+ echo '#!/bin/rc'
+ sed -n -e 's/seek/_SEEK/g' -e '/switch/,/\$AS /p' $prereq
+ } >$target
+ chmod +x $target
+
+nuke clean:V:
+ rm -f *.[$OS] *.s gencall
+
+installall:V:
+ for(objtype in $CPUS) mk install
+
+update:V:
+ update $UPDATEFLAGS mkfile