summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/ap/stdio
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/stdio
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/ape/lib/ap/stdio')
-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
66 files changed, 4653 insertions, 0 deletions
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;
+}