From 082e680bd54e999f2bb4eb77141958938b1e9ee9 Mon Sep 17 00:00:00 2001
From: Manuel Novoa III <mjn3@codepoet.org>
Date: Wed, 11 Feb 2004 23:48:50 +0000
Subject: New stdio core.  Should be more maintainable.  Fixes a couple of
 bugs.   Codepaths streamlined.  Improved performance for nonthreaded apps  
 when linked with a thread-enabled libc. Minor iconv bug and some
 locale/thread related startup issues fixed.   These showed up in getting a
 gcj-compiled java helloworld app running. Removed some old extension
 functions... _stdio_fdout and _stdio_fsfopen.

---
 libc/stdio/Makefile         |  144 +-
 libc/stdio/_READ.c          |   66 +
 libc/stdio/_WRITE.c         |  100 ++
 libc/stdio/__fbufsize.c     |   20 +
 libc/stdio/__flbf.c         |   20 +
 libc/stdio/__fpending.c     |   35 +
 libc/stdio/__fpurge.c       |   34 +
 libc/stdio/__freadable.c    |   20 +
 libc/stdio/__freading.c     |   20 +
 libc/stdio/__fsetlocking.c  |   45 +
 libc/stdio/__fwritable.c    |   20 +
 libc/stdio/__fwriting.c     |   20 +
 libc/stdio/_adjust_pos.c    |   68 +
 libc/stdio/_cs_funcs.c      |   67 +
 libc/stdio/_flushlbf.c      |   18 +
 libc/stdio/_fopen.c         |  207 +++
 libc/stdio/_fpmaxtostr.c    |  738 +++++++++
 libc/stdio/_fwrite.c        |   78 +
 libc/stdio/_load_inttype.c  |   66 +
 libc/stdio/_rfill.c         |   45 +
 libc/stdio/_stdio.c         |  432 +++++
 libc/stdio/_stdio.h         |  436 +++++
 libc/stdio/_store_inttype.c |   57 +
 libc/stdio/_trans2r.c       |   75 +
 libc/stdio/_trans2w.c       |   89 ++
 libc/stdio/_uintmaxtostr.c  |  151 ++
 libc/stdio/_wcommit.c       |   31 +
 libc/stdio/_wfwrite.c       |   75 +
 libc/stdio/asprintf.c       |   29 +
 libc/stdio/clearerr.c       |   39 +
 libc/stdio/ctermid.c        |   54 +-
 libc/stdio/dprintf.c        |   21 +
 libc/stdio/fclose.c         |   86 +
 libc/stdio/fcloseall.c      |   40 +
 libc/stdio/fdopen.c         |   17 +
 libc/stdio/feof.c           |   42 +
 libc/stdio/ferror.c         |   42 +
 libc/stdio/fflush.c         |  161 ++
 libc/stdio/fgetc.c          |   98 ++
 libc/stdio/fgetpos.c        |   44 +
 libc/stdio/fgets.c          |   84 +
 libc/stdio/fgetwc.c         |  134 ++
 libc/stdio/fgetws.c         |   61 +
 libc/stdio/fileno.c         |   45 +
 libc/stdio/flockfile.c      |   16 +
 libc/stdio/fmemopen.c       |  176 +++
 libc/stdio/fopen.c          |   24 +
 libc/stdio/fopencookie.c    |   59 +
 libc/stdio/fprintf.c        |   21 +
 libc/stdio/fputc.c          |   96 ++
 libc/stdio/fputs.c          |   46 +
 libc/stdio/fputwc.c         |   42 +
 libc/stdio/fputws.c         |   44 +
 libc/stdio/fread.c          |  108 ++
 libc/stdio/freopen.c        |   66 +
 libc/stdio/fseeko.c         |   89 ++
 libc/stdio/fsetpos.c        |   44 +
 libc/stdio/ftello.c         |   61 +
 libc/stdio/ftrylockfile.c   |   19 +
 libc/stdio/funlockfile.c    |   15 +
 libc/stdio/fwide.c          |   32 +
 libc/stdio/fwprintf.c       |   22 +
 libc/stdio/fwrite.c         |   59 +
 libc/stdio/getchar.c        |   44 +
 libc/stdio/getdelim.c       |  124 +-
 libc/stdio/getline.c        |   34 +-
 libc/stdio/gets.c           |   36 +
 libc/stdio/getw.c           |   18 +
 libc/stdio/getwchar.c       |   31 +
 libc/stdio/old_vfprintf.c   |   54 +-
 libc/stdio/open_memstream.c |  162 ++
 libc/stdio/perror.c         |   36 +
 libc/stdio/popen.c          |   21 +-
 libc/stdio/printf.c         | 3267 +-------------------------------------
 libc/stdio/putchar.c        |   44 +
 libc/stdio/puts.c           |   33 +
 libc/stdio/putw.c           |   28 +
 libc/stdio/putwchar.c       |   31 +
 libc/stdio/remove.c         |   29 +
 libc/stdio/rewind.c         |   20 +
 libc/stdio/scanf.c          |  227 ++-
 libc/stdio/setbuf.c         |   15 +
 libc/stdio/setbuffer.c      |   21 +
 libc/stdio/setlinebuf.c     |   20 +
 libc/stdio/setvbuf.c        |  106 ++
 libc/stdio/snprintf.c       |   27 +
 libc/stdio/sprintf.c        |   27 +
 libc/stdio/stdio.c          | 3677 -------------------------------------------
 libc/stdio/swprintf.c       |   29 +
 libc/stdio/ungetc.c         |   77 +
 libc/stdio/ungetwc.c        |   48 +
 libc/stdio/vasprintf.c      |   75 +
 libc/stdio/vdprintf.c       |   62 +
 libc/stdio/vfprintf.c       | 1901 ++++++++++++++++++++++
 libc/stdio/vprintf.c        |   14 +
 libc/stdio/vsnprintf.c      |  210 +++
 libc/stdio/vsprintf.c       |   21 +
 libc/stdio/vswprintf.c      |   70 +
 libc/stdio/vwprintf.c       |   15 +
 libc/stdio/wprintf.c        |   23 +
 100 files changed, 8661 insertions(+), 7229 deletions(-)
 create mode 100644 libc/stdio/_READ.c
 create mode 100644 libc/stdio/_WRITE.c
 create mode 100644 libc/stdio/__fbufsize.c
 create mode 100644 libc/stdio/__flbf.c
 create mode 100644 libc/stdio/__fpending.c
 create mode 100644 libc/stdio/__fpurge.c
 create mode 100644 libc/stdio/__freadable.c
 create mode 100644 libc/stdio/__freading.c
 create mode 100644 libc/stdio/__fsetlocking.c
 create mode 100644 libc/stdio/__fwritable.c
 create mode 100644 libc/stdio/__fwriting.c
 create mode 100644 libc/stdio/_adjust_pos.c
 create mode 100644 libc/stdio/_cs_funcs.c
 create mode 100644 libc/stdio/_flushlbf.c
 create mode 100644 libc/stdio/_fopen.c
 create mode 100644 libc/stdio/_fpmaxtostr.c
 create mode 100644 libc/stdio/_fwrite.c
 create mode 100644 libc/stdio/_load_inttype.c
 create mode 100644 libc/stdio/_rfill.c
 create mode 100644 libc/stdio/_stdio.c
 create mode 100644 libc/stdio/_stdio.h
 create mode 100644 libc/stdio/_store_inttype.c
 create mode 100644 libc/stdio/_trans2r.c
 create mode 100644 libc/stdio/_trans2w.c
 create mode 100644 libc/stdio/_uintmaxtostr.c
 create mode 100644 libc/stdio/_wcommit.c
 create mode 100644 libc/stdio/_wfwrite.c
 create mode 100644 libc/stdio/asprintf.c
 create mode 100644 libc/stdio/clearerr.c
 create mode 100644 libc/stdio/dprintf.c
 create mode 100644 libc/stdio/fclose.c
 create mode 100644 libc/stdio/fcloseall.c
 create mode 100644 libc/stdio/fdopen.c
 create mode 100644 libc/stdio/feof.c
 create mode 100644 libc/stdio/ferror.c
 create mode 100644 libc/stdio/fflush.c
 create mode 100644 libc/stdio/fgetc.c
 create mode 100644 libc/stdio/fgetpos.c
 create mode 100644 libc/stdio/fgets.c
 create mode 100644 libc/stdio/fgetwc.c
 create mode 100644 libc/stdio/fgetws.c
 create mode 100644 libc/stdio/fileno.c
 create mode 100644 libc/stdio/flockfile.c
 create mode 100644 libc/stdio/fmemopen.c
 create mode 100644 libc/stdio/fopen.c
 create mode 100644 libc/stdio/fopencookie.c
 create mode 100644 libc/stdio/fprintf.c
 create mode 100644 libc/stdio/fputc.c
 create mode 100644 libc/stdio/fputs.c
 create mode 100644 libc/stdio/fputwc.c
 create mode 100644 libc/stdio/fputws.c
 create mode 100644 libc/stdio/fread.c
 create mode 100644 libc/stdio/freopen.c
 create mode 100644 libc/stdio/fseeko.c
 create mode 100644 libc/stdio/fsetpos.c
 create mode 100644 libc/stdio/ftello.c
 create mode 100644 libc/stdio/ftrylockfile.c
 create mode 100644 libc/stdio/funlockfile.c
 create mode 100644 libc/stdio/fwide.c
 create mode 100644 libc/stdio/fwprintf.c
 create mode 100644 libc/stdio/fwrite.c
 create mode 100644 libc/stdio/getchar.c
 create mode 100644 libc/stdio/gets.c
 create mode 100644 libc/stdio/getw.c
 create mode 100644 libc/stdio/getwchar.c
 create mode 100644 libc/stdio/open_memstream.c
 create mode 100644 libc/stdio/perror.c
 create mode 100644 libc/stdio/putchar.c
 create mode 100644 libc/stdio/puts.c
 create mode 100644 libc/stdio/putw.c
 create mode 100644 libc/stdio/putwchar.c
 create mode 100644 libc/stdio/remove.c
 create mode 100644 libc/stdio/rewind.c
 create mode 100644 libc/stdio/setbuf.c
 create mode 100644 libc/stdio/setbuffer.c
 create mode 100644 libc/stdio/setlinebuf.c
 create mode 100644 libc/stdio/setvbuf.c
 create mode 100644 libc/stdio/snprintf.c
 create mode 100644 libc/stdio/sprintf.c
 delete mode 100644 libc/stdio/stdio.c
 create mode 100644 libc/stdio/swprintf.c
 create mode 100644 libc/stdio/ungetc.c
 create mode 100644 libc/stdio/ungetwc.c
 create mode 100644 libc/stdio/vasprintf.c
 create mode 100644 libc/stdio/vdprintf.c
 create mode 100644 libc/stdio/vfprintf.c
 create mode 100644 libc/stdio/vprintf.c
 create mode 100644 libc/stdio/vsnprintf.c
 create mode 100644 libc/stdio/vsprintf.c
 create mode 100644 libc/stdio/vswprintf.c
 create mode 100644 libc/stdio/vwprintf.c
 create mode 100644 libc/stdio/wprintf.c

(limited to 'libc/stdio')

diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile
index b0ba70ba8..59e80a359 100644
--- a/libc/stdio/Makefile
+++ b/libc/stdio/Makefile
@@ -2,6 +2,7 @@
 #
 # Copyright (C) 2000 by Lineo, inc.
 # Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org>
+# Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
 #
 # This program is free software; you can redistribute it and/or modify it under
 # the terms of the GNU Library General Public License as published by the Free
@@ -25,61 +26,96 @@ TOPDIR=../../
 include $(TOPDIR)Rules.mak
 
 # Note: The *64.o objects are empty when compiled without large file support.
-#
 
-# Note: Use the libpthreads of: flockfile.o ftrylockfile.o funlockfile.o
-#       Also, maybe move __fsetlocking.o as well?
-
-MSRC = stdio.c
-MOBJ = fclose.o fflush.o fopen.o freopen.o perror.o remove.o \
-	setbuf.o setvbuf.o fgetc.o fgets.o fputc.o fputs.o \
-	getc.o getchar.o gets.o putc.o putchar.o puts.o \
-	ungetc.o fread.o fwrite.o fgetpos.o fseek.o fsetpos.o ftell.o \
-	rewind.o clearerr.o feof.o ferror.o \
-	fileno.o fdopen.o getw.o putw.o setbuffer.o setlinebuf.o fcloseall.o \
-	fopen64.o freopen64.o ftello64.o fseeko64.o fsetpos64.o fgetpos64.o \
-	__fbufsize.o __freading.o __fwriting.o __freadable.o __fwritable.o \
-	__flbf.o __fpurge.o __fpending.o _flushlbf.o \
-	 fopencookie.o fmemopen.o open_memstream.o \
-	__fsetlocking.o flockfile.o ftrylockfile.o funlockfile.o \
-	_stdio_fopen.o _stdio_fread.o _stdio_fwrite.o _stdio_adjpos.o \
-	_stdio_lseek.o _stdio_init.o \
-	_stdio_fsfopen.o _stdio_fdout.o _uintmaxtostr.o _stdio_strerror_r.o \
-	getdelim.o getline.o ctermid.o
-
-MSRC2= printf.c
-MOBJ2=  vsnprintf.o vdprintf.o vasprintf.o vprintf.o vsprintf.o \
-	fprintf.o  snprintf.o  dprintf.o  asprintf.o  printf.o  sprintf.o \
-	_store_inttype.o _load_inttype.o
-
-MSRC3=scanf.c
-MOBJ3=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o \
-	__scan_cookie.o __psfs_parse_spec.o __psfs_do_numeric.o
+# SUSv3 functions
+CSRC = fclose.c fcloseall.c fdopen.c fgetpos.c fopen.c freopen.c \
+	fseeko.c fsetpos.c ftello.c getdelim.c getline.c gets.c getw.c \
+	perror.c puts.c putw.c remove.c rewind.c setbuf.c setbuffer.c \
+	setlinebuf.c setvbuf.c ungetc.c \
+	printf.c vprintf.c vsprintf.c fprintf.c snprintf.c dprintf.c \
+	asprintf.c sprintf.c vasprintf.c vdprintf.c vsnprintf.c \
+	tmpfile.c tmpnam.c tmpnam_r.c popen.c tempnam.c ctermid.c
+
+# getc -> alias for fgetc
+# putc -> alias for fputc
+# rename is a syscall
+
+# Implementation support functions
+CSRC += _READ.c _WRITE.c _adjust_pos.c _fopen.c _fwrite.c \
+	_rfill.c _stdio.c _trans2r.c _trans2w.c _wcommit.c \
+	_load_inttype.c _store_inttype.c _uintmaxtostr.c
+ifeq ($(strip $(UCLIBC_HAS_FLOATS)),y)
+CSRC += _fpmaxtostr.c
+endif
 
-ifeq ($(UCLIBC_HAS_WCHAR),y)
-	MOBJ += _wstdio_fwrite.o
-	MOBJ2 += fwprintf.o wprintf.o swprintf.o vwprintf.o vswprintf.o \
-		vfwprintf.o
-	MOBJ3 += wscanf.o swscanf.o fwscanf.o vwscanf.o vswscanf.o vfwscanf.o
+# stdio_ext.h functions
+CSRC += __fbufsize.c __flbf.c __fpending.c __fpurge.c __freadable.c \
+	__freading.c __fsetlocking.c __fwritable.c __fwriting.c _flushlbf.c
+
+# Other glibc extensions
+CSRC += fopencookie.c fmemopen.c open_memstream.c _cs_funcs.c
+
+# pthread functions
+ifeq ($(strip $(UCLIBC_HAS_THREADS)),y)
+CSRC += flockfile.c ftrylockfile.c funlockfile.c
 endif
 
+# Functions with unlocked versions
+CUSRC = clearerr.c feof.c ferror.c fflush.c fgetc.c fgets.c fileno.c \
+	fputc.c fputs.c fread.c fwrite.c getchar.c putchar.c
+# getc_unlocked -> alias for fgetc_unlocked
+# putc_unlocked -> alias for fputc_unlocked
+
+# Largefile functions
+CLOBJS = fgetpos64.o fopen64.o freopen64.o fseeko64.o fsetpos64.o ftello64.o
+# tmpfile64.o
+
+# vfprintf and support functions
+MSRC2=	vfprintf.c
 ifneq ($(USE_OLD_VFPRINTF),y)
-	MOBJ2 += _ppfs_init.o _ppfs_prepargs.o _ppfs_setargs.o \
-		 _ppfs_parsespec.o vfprintf.o \
-		 register_printf_function.o parse_printf_format.o
+MOBJ2=	vfprintf.o \
+	_ppfs_init.o _ppfs_prepargs.o _ppfs_setargs.o _ppfs_parsespec.o \
+	register_printf_function.o parse_printf_format.o
+else
+MOBJ2=
+CSRC += old_vfprintf.c
+endif
+
+# vfscanf and support functions plus other *scanf funcs
+MSRC3=	scanf.c
+MOBJ3=	vfscanf.o __scan_cookie.o __psfs_parse_spec.o __psfs_do_numeric.o \
+	scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o
+
+MWSRC=  wstdio.c
+MWOBJ=
+
+CWSRC =
+ifeq ($(UCLIBC_HAS_WCHAR),y)
+CWSRC += _wfwrite.c fwprintf.c swprintf.c vswprintf.c vwprintf.c wprintf.c \
+	fwide.c ungetwc.c
+CUSRC += fgetwc.c getwchar.c fgetws.c fputwc.c putwchar.c fputws.c
+# getwc (fgetwc alias) getwc_unlocked (fgetwc_unlocked alias)
+# putwc (fputwc alias) putwc_unlocked (fputwc_unlocked alias)
+MOBJ2 += vfwprintf.o
+MOBJ3 += wscanf.o swscanf.o fwscanf.o vwscanf.o vswscanf.o vfwscanf.o
 endif
 
-ifeq ($(UCLIBC_HAS_FLOATS),y)
-	MOBJ2 += _fpmaxtostr.o
+CSRC += $(CUSRC)
+
+COBJS  = $(patsubst %.c,%.o, $(CSRC))
+CUOBJS = $(patsubst %.c,%_unlocked.o, $(CUSRC))
+CWOBJS = $(patsubst %.c,%.o, $(CWSRC))
+
+ifeq ($(strip $(UCLIBC_HAS_WCHAR)),y)
+COBJS += $(CWOBJS)
 endif
 
-CSRC=popen.c tmpfile.c tmpnam.c tmpnam_r.c tempnam.c
-ifeq ($(USE_OLD_VFPRINTF),y)
-	CSRC += old_vfprintf.c
+OBJS = $(COBJS) $(CUOBJS) $(MOBJ2) $(MOBJ3) $(MWOBJ)
+
+ifeq ($(strip $(UCLIBC_HAS_LFS)),y)
+OBJS += $(CLOBJS)
 endif
-COBJS=$(patsubst %.c,%.o, $(CSRC))
 
-OBJS=$(MOBJ) $(MOBJ2) $(MOBJ3) $(COBJS)
 
 all: $(OBJS) $(LIBC)
 
@@ -88,9 +124,17 @@ $(LIBC): ar-target
 ar-target: $(OBJS)
 	$(AR) $(ARFLAGS) $(LIBC) $(OBJS)
 
-$(MOBJ): $(MSRC)
-	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
-	$(STRIPTOOL) -x -R .note -R .comment $*.o
+$(COBJS): %.o : %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+	$(STRIPTOOL) -x -R .note -R .comment $@
+
+%_unlocked.o : %.c
+	$(CC) $(CFLAGS) -D__DO_UNLOCKED -c $< -o $@
+	$(STRIPTOOL) -x -R .note -R .comment $@
+
+%64.o : %.c
+	$(CC) $(CFLAGS) -D__DO_LARGEFILE -c $< -o $@
+	$(STRIPTOOL) -x -R .note -R .comment $@
 
 $(MOBJ2): $(MSRC2)
 	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
@@ -100,12 +144,12 @@ $(MOBJ3): $(MSRC3)
 	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
 	$(STRIPTOOL) -x -R .note -R .comment $*.o
 
-$(COBJS): %.o : %.c
-	$(CC) $(CFLAGS) -c $< -o $@
+$(MWOBJ): $(MWSRC)
+	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
 	$(STRIPTOOL) -x -R .note -R .comment $*.o
 
 $(OBJ): Makefile
 
 clean:
-	$(RM) *.[oa] *~ core
+	rm -f *.[oa] *~ core
 
diff --git a/libc/stdio/_READ.c b/libc/stdio/_READ.c
new file mode 100644
index 000000000..7d3c38ce6
--- /dev/null
+++ b/libc/stdio/_READ.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+/* Given a reading stream without its end-of-file indicator set and
+ * with no buffered input or ungots, read at most 'bufsize' bytes
+ * into 'buf' (which may be the stream's __bufstart).
+ * If a read error occurs, set the stream's error indicator.
+ * If EOF is encountered, set the stream's end-of-file indicator.
+ *
+ * Returns the number of bytes read, even in EOF and error cases.
+ *
+ * Notes:
+ *   Calling with bufsize == 0 is NOT permitted (unlike __stdio_WRITE).
+ *   NOT THREADSAFE!  Assumes stream already locked if necessary.
+ */
+
+size_t __stdio_READ(register FILE *stream,
+					unsigned char *buf, size_t bufsize)
+{
+	ssize_t rv = 0;
+
+	__STDIO_STREAM_VALIDATE(stream);
+	assert(stream->__filedes >= -1);
+	assert(__STDIO_STREAM_IS_READING(stream));
+	assert(!__STDIO_STREAM_BUFFER_RAVAIL(stream)); /* Buffer must be empty. */
+	assert(!(stream->__modeflags & __FLAG_UNGOT));
+	assert(bufsize);
+
+	if (!__FEOF_UNLOCKED(stream)) {
+		if (bufsize > SSIZE_MAX) {
+			bufsize = SSIZE_MAX;
+		}
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning EINTR?
+#endif
+/* 	RETRY: */
+		if ((rv = __READ(stream, buf, bufsize)) <= 0) {
+			if (rv == 0) {
+				__STDIO_STREAM_SET_EOF(stream);
+			} else {
+/* 				if (errno == EINTR) goto RETRY; */
+				__STDIO_STREAM_SET_ERROR(stream);
+				rv = 0;
+			}
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Make custom stream read return check optional.
+#endif
+#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
+		} else {
+			assert(rv <= bufsize);
+			if (rv > bufsize) {	/* Read more than bufsize! */
+				abort();
+			}
+#endif
+		}
+	}
+
+	return rv;
+}
diff --git a/libc/stdio/_WRITE.c b/libc/stdio/_WRITE.c
new file mode 100644
index 000000000..d300d3919
--- /dev/null
+++ b/libc/stdio/_WRITE.c
@@ -0,0 +1,100 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+/* Given a writing stream with no buffered output, write the
+ * data in 'buf' (which may be the stream's bufstart) of size
+ * 'bufsize' to the stream.  If a write error occurs, set the
+ * stream's error indicator and (if buffering) buffer as much
+ * data as possible (FBF) or only up to '\n' (LBF) to implement
+ * "as if fputc()" clause in the standard.
+ *
+ * Returns the number of bytes written and/or buffered.
+ *
+ * Notes:
+ *   Calling with bufsize == 0 is permitted, and buf is ignored in
+ *     that case.
+ *   We implement fflush() by setting bufpos to bufstart and passing
+ *     bufstart as the buf arg.  If there is a write error, the
+ *     unwritten buffered data will simply be moved to the beginning
+ *     of the buffer.  Since the data obviously fits in the buffer
+ *     and since there will be no '\n' chars in the buffer in the LBF
+ *     case, no data will be lost.
+ *   NOT THREADSAFE!  Assumes stream already locked if necessary.
+ */
+
+size_t __stdio_WRITE(register FILE *stream,
+					 register const unsigned char *buf, size_t bufsize)
+{
+	size_t todo;
+	ssize_t rv, stodo;
+
+	__STDIO_STREAM_VALIDATE(stream);
+	assert(stream->__filedes >= -1);
+	assert(__STDIO_STREAM_IS_WRITING(stream));
+	assert(!__STDIO_STREAM_BUFFER_WUSED(stream)); /* Buffer must be empty. */
+
+	todo = bufsize;
+
+	do {
+		if (todo == 0) {		/* Done? */
+			__STDIO_STREAM_VALIDATE(stream);
+			return bufsize;
+		}
+		stodo = (todo <= SSIZE_MAX) ? todo : SSIZE_MAX;
+		if ((rv = __WRITE(stream, buf, stodo)) >= 0) {
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Make custom stream write return check optional.
+#endif
+#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
+			assert(rv <= stodo);
+			if (rv > stodo) {	/* Wrote more than stodo! */
+/* 				abort(); */
+			}
+#endif
+			todo -= rv;
+			buf += rv;
+		} else
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning EINTR?
+#endif
+/* 		if (errno != EINTR) */
+		{
+			__STDIO_STREAM_SET_ERROR(stream);
+
+#ifdef __STDIO_BUFFERS
+			if ((stodo = __STDIO_STREAM_BUFFER_SIZE(stream)) != 0) {
+				unsigned char *s;
+
+				if (stodo > todo) {
+					stodo = todo;
+				}
+
+				s  = stream->__bufstart;
+
+				do {
+					if (((*s = *buf) == '\n')
+						&& __STDIO_STREAM_IS_LBF(stream)
+						) {
+						break;
+					}
+					++s;
+					++buf;
+				} while (--stodo);
+
+				stream->__bufpos = s;
+
+				todo -= (s - stream->__bufstart);
+			}
+#endif /* __STDIO_BUFFERS */
+
+			__STDIO_STREAM_VALIDATE(stream);
+			return bufsize - todo;
+		}
+	} while (1);
+}
diff --git a/libc/stdio/__fbufsize.c b/libc/stdio/__fbufsize.c
new file mode 100644
index 000000000..09ade15ae
--- /dev/null
+++ b/libc/stdio/__fbufsize.c
@@ -0,0 +1,20 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Returns the size of the buffer in bytes..
+ */
+
+size_t __fbufsize(register FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return __STDIO_STREAM_BUFFER_SIZE(stream);
+}
diff --git a/libc/stdio/__flbf.c b/libc/stdio/__flbf.c
new file mode 100644
index 000000000..13d8cea96
--- /dev/null
+++ b/libc/stdio/__flbf.c
@@ -0,0 +1,20 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Returns nonzero if the stream is line buffered, and 0 otherwise.
+ */
+
+int __flbf(FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return __STDIO_STREAM_IS_LBF(stream);
+}
diff --git a/libc/stdio/__fpending.c b/libc/stdio/__fpending.c
new file mode 100644
index 000000000..a7fe05463
--- /dev/null
+++ b/libc/stdio/__fpending.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Returns the number of bytes in the buffer for a writing stream.
+ *
+ * NOTE: GLIBC DIFFERENCE!!!
+ *
+ * glibc will return the number of wide chars pending for wide oriented
+ * streams.  We always return the number of bytes in the buffer, as we
+ * convert wide chars to their multibyte encodings and buffer _those_.
+ */
+
+#ifdef __UCLIBC_HAS_WCHAR__
+#warning Note: Unlike the glibc version, this __fpending returns bytes in buffer for wide streams too!
+
+link_warning(__fpending, "This version of __fpending returns bytes remaining in buffer for both narrow and wide streams.  glibc's version returns wide chars in buffer for the wide stream case.")
+
+#endif
+
+size_t __fpending(register FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return (__STDIO_STREAM_IS_WRITING(stream))
+		? __STDIO_STREAM_BUFFER_WUSED(stream)
+		: 0;
+}
diff --git a/libc/stdio/__fpurge.c b/libc/stdio/__fpurge.c
new file mode 100644
index 000000000..c17ecf4c0
--- /dev/null
+++ b/libc/stdio/__fpurge.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Discard all buffered data whether reading or writing.
+ */
+
+void __fpurge(register FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	__STDIO_STREAM_DISABLE_GETC(stream);
+	__STDIO_STREAM_DISABLE_PUTC(stream);
+	__STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream);
+	stream->__ungot[1] = 0;
+
+#ifdef __STDIO_MBSTATE
+	__INIT_MBSTATE(&(stream->__state));
+#endif
+#ifdef __UCLIBC_HAS_WCHAR__
+	stream->__ungot_width[0] = 0;
+#endif
+
+	stream->__modeflags &= ~(__MASK_READING|__FLAG_WRITING);
+
+	__STDIO_STREAM_VALIDATE(stream);
+}
diff --git a/libc/stdio/__freadable.c b/libc/stdio/__freadable.c
new file mode 100644
index 000000000..006a66fc8
--- /dev/null
+++ b/libc/stdio/__freadable.c
@@ -0,0 +1,20 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Return nonzero if readable, and 0 if write-only.
+ */
+
+int __freadable(FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return !__STDIO_STREAM_IS_WRITEONLY(stream);
+}
diff --git a/libc/stdio/__freading.c b/libc/stdio/__freading.c
new file mode 100644
index 000000000..aab91b238
--- /dev/null
+++ b/libc/stdio/__freading.c
@@ -0,0 +1,20 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Return nonzero if read-only or was last read from, and 0 otherwise.
+ */
+
+int __freading(FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return __STDIO_STREAM_IS_READING_OR_READONLY(stream);
+}
diff --git a/libc/stdio/__fsetlocking.c b/libc/stdio/__fsetlocking.c
new file mode 100644
index 000000000..f49503207
--- /dev/null
+++ b/libc/stdio/__fsetlocking.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Not threadsafe. */
+
+/* Notes:
+ *   When setting the locking mode, glibc returns the previous setting.
+ *   glibc treats invalid locking_mode args as FSETLOCKING_INTERNAL.
+ */
+
+int __fsetlocking(FILE *stream, int locking_mode)
+{
+#ifdef __UCLIBC_HAS_THREADS__
+	int current = 1 + (stream->__user_locking & 1);
+
+	/* Check constant assumptions.  We can't test at build time
+	 * since these are enums. */
+	assert((FSETLOCKING_QUERY == 0) && (FSETLOCKING_INTERNAL == 1)
+		   && (FSETLOCKING_BYCALLER == 2));
+
+	__STDIO_STREAM_VALIDATE(stream);
+	assert(((unsigned int) locking_mode) <= 2);
+
+	if (locking_mode != FSETLOCKING_QUERY) {
+		stream->__user_locking = ((locking_mode == FSETLOCKING_BYCALLER)
+								  ? 1
+								  : _stdio_user_locking); /* 0 or 2 */
+		__STDIO_STREAM_VALIDATE(stream);
+	}
+
+	return current;
+#else
+	__STDIO_STREAM_VALIDATE(stream);
+	assert(((unsigned int) locking_mode) <= 2);
+
+	return FSETLOCKING_INTERNAL;
+#endif
+}
diff --git a/libc/stdio/__fwritable.c b/libc/stdio/__fwritable.c
new file mode 100644
index 000000000..59c70a648
--- /dev/null
+++ b/libc/stdio/__fwritable.c
@@ -0,0 +1,20 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Return nonzero if writable, and 0 if read-only.
+ */
+
+int __fwritable(FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return !__STDIO_STREAM_IS_READONLY(stream);
+}
diff --git a/libc/stdio/__fwriting.c b/libc/stdio/__fwriting.c
new file mode 100644
index 000000000..926eaa95f
--- /dev/null
+++ b/libc/stdio/__fwriting.c
@@ -0,0 +1,20 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Return nonzero if write-only or was last written to, and 0 otherwise.
+ */
+
+int __fwriting(FILE * __restrict stream)
+{
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return __STDIO_STREAM_IS_WRITING_OR_WRITEONLY(stream);
+}
diff --git a/libc/stdio/_adjust_pos.c b/libc/stdio/_adjust_pos.c
new file mode 100644
index 000000000..bc48d32b7
--- /dev/null
+++ b/libc/stdio/_adjust_pos.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+/* Both ftell() and fseek() (for SEEK_CUR) need to correct the stream's
+ * position to take into account buffered data and ungotten chars.
+ *
+ * If successful, store corrected position in *pos and return >= 0.
+ * Otherwise return < 0.
+ *
+ * If position is unrepresentable, set errno to EOVERFLOW.
+ */
+
+int __stdio_adjust_position(register FILE * __restrict stream,
+							register __offmax_t *pos)
+{
+	__offmax_t oldpos;
+	int corr;
+
+	if ((corr = stream->__modeflags & __MASK_READING) != 0) {
+		--corr;	/* Correct for ungots. Assume narrow, and fix below. */
+	}
+
+#ifdef __UCLIBC_HAS_WCHAR__
+	if (corr && __STDIO_STREAM_IS_WIDE(stream)) {
+		/* A wide stream and we have at least one ungotten wchar.
+		 * If it is a user ungot, we need to fail since position
+		 * is unspecified as per C99. */
+		if ((corr > 1) || stream->__ungot[1]) { /* User ungetwc, */
+			return -1;			/* so position is undefined. */
+		}
+		corr -= (1 + stream->__ungot_width[1]);
+		if (stream->__state.__mask > 0) { /* Incomplete (bad?) mb char. */
+			corr -= stream->__ungot_width[0];
+		}
+	}
+#endif
+
+#ifdef __STDIO_BUFFERS
+	corr += (((__STDIO_STREAM_IS_WRITING(stream))
+			  ? stream->__bufstart : stream->__bufread)
+			 - stream->__bufpos);
+#endif
+
+	oldpos = *pos;
+
+	/* Range checking cases:
+	 * (pos - corr >  pos) && (corr >  0) : underflow?  return -corr < 0
+	 * (pos - corr >  pos) && (corr <  0) : ok .. return -corr > 0
+	 * (pos - corr <= pos) && (corr >= 0) : ok .. return  corr > 0
+	 * (pos - corr <= pos) && (corr <  0) : overflow ..  return corr < 0
+	 */
+
+	if ((*pos -= corr) > oldpos) {
+		corr = -corr;
+	}
+
+	if (corr < 0) {
+		__set_errno(EOVERFLOW);
+	}
+
+	return corr;
+}
diff --git a/libc/stdio/_cs_funcs.c b/libc/stdio/_cs_funcs.c
new file mode 100644
index 000000000..fd81a6f95
--- /dev/null
+++ b/libc/stdio/_cs_funcs.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+/**********************************************************************/
+#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
+/**********************************************************************/
+
+ssize_t _cs_read(void *cookie, char *buf, size_t bufsize)
+{
+	return read(*((int *) cookie), buf, bufsize);
+}
+
+/**********************************************************************/
+
+ssize_t _cs_write(void *cookie, const char *buf, size_t bufsize)
+{
+	return write(*((int *) cookie), (char *) buf, bufsize);
+}
+
+/**********************************************************************/
+
+int _cs_seek(void *cookie, register __offmax_t *pos, int whence)
+{
+	__offmax_t res;
+
+#ifdef __UCLIBC_HAS_LFS__
+	res = lseek64(*((int *) cookie), *pos, whence);
+#else
+	res = lseek(*((int *) cookie), *pos, whence);
+#endif
+
+	return (res >= 0) ? ((*pos = res), 0) : ((int) res);
+}
+
+/**********************************************************************/
+
+int _cs_close(void *cookie)
+{
+	return close(*((int *) cookie));
+}
+
+/**********************************************************************/
+#else
+/**********************************************************************/
+
+int __stdio_seek(FILE *stream, register __offmax_t *pos, int whence)
+{
+	__offmax_t res;
+
+#ifdef __UCLIBC_HAS_LFS__
+	res = lseek64(stream->__filedes, *pos, whence);
+#else
+	res = lseek(stream->__filedes, *pos, whence);
+#endif
+
+	return (res >= 0) ? ((*pos = res), 0) : ((int) res);
+}
+
+/**********************************************************************/
+#endif
+/**********************************************************************/
diff --git a/libc/stdio/_flushlbf.c b/libc/stdio/_flushlbf.c
new file mode 100644
index 000000000..31ed2fc55
--- /dev/null
+++ b/libc/stdio/_flushlbf.c
@@ -0,0 +1,18 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <stdio_ext.h>
+
+/* Solaris function --
+ * Flush all line buffered (writing) streams.
+ */
+
+void _flushlbf(void)
+{
+	__STDIO_FLUSH_LBF_STREAMS;
+}
diff --git a/libc/stdio/_fopen.c b/libc/stdio/_fopen.c
new file mode 100644
index 000000000..6e3d53bd8
--- /dev/null
+++ b/libc/stdio/_fopen.c
@@ -0,0 +1,207 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+/*
+ * Cases:
+ *  fopen64  : filename != NULL, stream == NULL, filedes == -2
+ *  fopen    : filename != NULL, stream == NULL, filedes == -1
+ *  freopen  : filename != NULL, stream != NULL, filedes == -1
+ *  fdopen   : filename == NULL, stream == NULL, filedes valid
+ *
+ *  fsfopen  : filename != NULL, stream != NULL, filedes == -1
+ */
+
+#if (O_ACCMODE != 3) || (O_RDONLY != 0) || (O_WRONLY != 1) || (O_RDWR != 2)
+#error Assumption violated - mode constants
+#endif
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
+
+/* Internal function -- reentrant (locks open file list) */
+
+FILE *_stdio_fopen(intptr_t fname_or_mode,
+				   register const char * __restrict mode,
+				   register FILE * __restrict stream, int filedes)
+{
+	__mode_t open_mode;
+	int i;
+
+	/* Parse the specified mode. */
+	open_mode = O_RDONLY;
+	if (*mode != 'r') {			/* Not read... */
+		open_mode = (O_WRONLY | O_CREAT | O_TRUNC);
+		if (*mode != 'w') {		/* Not write (create or truncate)... */
+			open_mode = (O_WRONLY | O_CREAT | O_APPEND);
+			if (*mode != 'a') {	/* Not write (create or append)... */
+			DO_EINVAL:
+				__set_errno(EINVAL); /* So illegal mode. */
+				if (stream) {
+				FREE_STREAM:
+					assert(!(stream->__modeflags & __FLAG_FREEBUF));
+					__STDIO_STREAM_FREE_FILE(stream);
+				}
+				return NULL;
+			}
+		}
+	}
+
+	if ((mode[1] == 'b')) {		/* Binary mode (NO-OP currently). */
+		++mode;
+	}
+
+	if (mode[1] == '+') {			/* Read and Write. */
+		++mode;
+		open_mode |= (O_RDONLY | O_WRONLY);
+		open_mode += (O_RDWR - (O_RDONLY | O_WRONLY));
+	}
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Implement glibc ccs option to bind a codeset?
+#warning CONSIDER: Implement glibc mmap option for readonly files?
+#warning CONSIDER: Implement a text mode using custom read/write funcs?
+#endif
+#if defined(__UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE__) || defined(__UCLIBC_HAS_FOPEN_LARGEFILE_MODE__)
+
+	while (*++mode) {
+# ifdef __UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE__
+		if (*mode == 'x') {	   /* Open exclusive (a glibc extension). */
+			open_mode |= O_EXCL;
+			continue;
+		}
+# endif
+# ifdef __UCLIBC_HAS_FOPEN_LARGEFILE_MODE__
+		if (*mode == 'F') {		/* Open as large file (uClibc extension). */
+			open_mode |= O_LARGEFILE;
+			continue;
+		}
+# endif
+ 	}
+
+#endif
+
+	if (!stream) {		  /* Need to allocate a FILE (not freopen). */
+		if ((stream = malloc(sizeof(FILE))) == NULL) {
+			return stream;
+		}
+		stream->__modeflags = __FLAG_FREEFILE;
+#ifdef __STDIO_BUFFERS
+		stream->__bufstart = NULL; /* We allocate a buffer below. */
+#endif
+#ifdef __UCLIBC_HAS_THREADS__
+		/* We only initialize the mutex in the non-freopen case. */
+		/* stream->__user_locking = _stdio_user_locking; */
+		__stdio_init_mutex(&stream->__lock);
+#endif
+	}
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Verify fdopen append behavior of glibc.
+#endif
+
+	if (filedes >= 0) {			/* Handle fdopen trickery. */
+		stream->__filedes = filedes;
+		/* NOTE: it is insufficient to just check R/W/RW agreement.
+		 * We must also check largefile compatibility if applicable.
+		 * Also, if append mode is desired for fdopen but O_APPEND isn't
+		 * currently set, then set it as recommended by SUSv3.  However,
+		 * if append mode is not specified for fdopen but O_APPEND is set,
+		 * leave it set (glibc compat). */
+		i = (open_mode & (O_ACCMODE|O_LARGEFILE)) + 1;
+
+		/* NOTE: fopencookie needs changing if the basic check changes! */
+		if (((i & (((int) fname_or_mode) + 1)) != i) /* Basic agreement? */
+			|| (((open_mode & ~((__mode_t) fname_or_mode)) & O_APPEND)
+				&& fcntl(filedes, F_SETFL, O_APPEND))	/* Need O_APPEND. */
+			) {
+			goto DO_EINVAL;
+		}
+		/* For later... to reflect largefile setting in stream flags. */
+		__STDIO_WHEN_LFS( open_mode |= (((__mode_t) fname_or_mode)
+										& O_LARGEFILE) );
+	} else {
+		__STDIO_WHEN_LFS( if (filedes < -1) open_mode |= O_LARGEFILE );
+		if ((stream->__filedes = open(((const char *) fname_or_mode),
+									  open_mode, 0666)) < 0) {
+			goto FREE_STREAM;
+		}
+	}
+
+	stream->__modeflags &= __FLAG_FREEFILE;
+/* 	stream->__modeflags &= ~(__FLAG_READONLY|__FLAG_WRITEONLY); */
+
+	stream->__modeflags |=		/* Note: Makes assumptions about flag vals! */
+#if (O_APPEND != __FLAG_APPEND) || ((O_LARGEFILE != __FLAG_LARGEFILE) && (O_LARGEFILE != 0))
+# if (O_APPEND != __FLAG_APPEND)
+		((open_mode & O_APPEND) ? __FLAG_APPEND : 0) |
+# else
+		(open_mode & O_APPEND) |
+# endif
+# if (O_LARGEFILE != __FLAG_LARGEFILE) && (O_LARGEFILE != 0)
+		((open_mode & O_LARGEFILE) ? __FLAG_LARGEFILE : 0) |
+# else
+		(open_mode & O_LARGEFILE) |
+# endif
+#else
+		(open_mode & (O_APPEND|O_LARGEFILE)) | /* i386 linux and elks */
+#endif
+		((((open_mode & O_ACCMODE) + 1) ^ 0x03) * __FLAG_WRITEONLY);
+
+#ifdef __STDIO_BUFFERS
+	i = errno;					/* Preserve errno against isatty call. */
+	stream->__modeflags |= (isatty(stream->__filedes) * __FLAG_LBF);
+	__set_errno(i);
+
+	if (!stream->__bufstart) {
+		if ((stream->__bufstart = malloc(BUFSIZ)) != NULL) {
+			stream->__bufend = stream->__bufstart + BUFSIZ;
+			stream->__modeflags |= __FLAG_FREEBUF;
+		} else {
+# if __STDIO_BUILTIN_BUF_SIZE > 0
+#warning if builtin buffer, then need probably want to test vs that too
+			stream->__bufstart = stream->unbuf;
+			stream->__bufend = stream->unbuf + sizeof(stream->unbuf);
+# else  /* __STDIO_BUILTIN_BUF_SIZE > 0 */
+			stream->__bufend = stream->__bufstart;
+# endif /* __STDIO_BUILTIN_BUF_SIZE > 0 */
+		}
+	}
+
+	__STDIO_STREAM_DISABLE_GETC(stream);
+	__STDIO_STREAM_DISABLE_PUTC(stream);
+	__STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream);
+#endif
+
+	__STDIO_STREAM_RESET_GCS(stream);
+
+#ifdef __UCLIBC_HAS_WCHAR__
+	stream->__ungot_width[0] = 0;
+#endif
+#ifdef __STDIO_MBSTATE
+	__INIT_MBSTATE(&(stream->__state));
+#endif
+
+#ifdef __UCLIBC_HAS_THREADS__
+	/* Even in the freopen case, we reset the user locking flag. */
+	stream->__user_locking = _stdio_user_locking;
+	/* __stdio_init_mutex(&stream->__lock); */
+#endif
+
+#ifdef __STDIO_HAS_OPENLIST
+	__STDIO_THREADLOCK_OPENLIST;
+	stream->__nextopen = _stdio_openlist; /* New files are inserted at */
+	_stdio_openlist = stream;			  /*   the head of the list. */
+	__STDIO_THREADUNLOCK_OPENLIST;
+#endif
+
+	__STDIO_STREAM_VALIDATE(stream);
+
+	return stream;
+}
diff --git a/libc/stdio/_fpmaxtostr.c b/libc/stdio/_fpmaxtostr.c
new file mode 100644
index 000000000..7fd67ffb4
--- /dev/null
+++ b/libc/stdio/_fpmaxtostr.c
@@ -0,0 +1,738 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <printf.h>
+#include <float.h>
+#include <locale.h>
+#include <bits/uClibc_fpmax.h>
+
+typedef void (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
+							  intptr_t buf);
+
+
+/* Copyright (C) 2000, 2001, 2003      Manuel Novoa III
+ *
+ * Function: 
+ *
+ *     size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
+ *                         __fp_outfunc_t fp_outfunc);
+ *
+ * This is derived from the old _dtostr, whic I wrote for uClibc to provide
+ * floating point support for the printf functions.  It handles +/- infinity,
+ * nan, and signed 0 assuming you have ieee arithmetic.  It also now handles
+ * digit grouping (for the uClibc supported locales) and hexadecimal float
+ * notation.  Finally, via the fp_outfunc parameter, it now supports wide
+ * output.
+ *
+ * Notes:
+ *
+ * At most DECIMAL_DIG significant digits are kept.  Any trailing digits
+ * are treated as 0 as they are really just the results of rounding noise
+ * anyway.  If you want to do better, use an arbitary precision arithmetic
+ * package.  ;-)
+ *
+ * It should also be fairly portable, as no assumptions are made about the
+ * bit-layout of doubles.  Of course, that does make it less efficient than
+ * it could be.
+ *
+ */
+
+/*****************************************************************************/
+/* Don't change anything that follows unless you know what you're doing.     */
+/*****************************************************************************/
+/* Fairly portable nan check.  Bitwise for i386 generated larger code.
+ * If you have a better version, comment this out.
+ */
+#define isnan(x)             ((x) != (x))
+
+/* Without seminumerical functions to examine the sign bit, this is
+ * about the best we can do to test for '-0'.
+ */
+#define zeroisnegative(x)    ((1./(x)) < 0)
+
+/*****************************************************************************/
+/* Don't change anything that follows peroid!!!  ;-)                         */
+/*****************************************************************************/
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+#if FLT_RADIX != 2
+#error FLT_RADIX != 2 is not currently supported
+#endif
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+#define NUM_HEX_DIGITS      ((FPMAX_MANT_DIG + 3)/ 4)
+
+/* WARNING: Adjust _fp_out_wide() below if this changes! */
+/* With 32 bit ints, we can get 9 decimal digits per block. */
+#define DIGITS_PER_BLOCK     9
+#define HEX_DIGITS_PER_BLOCK 8
+
+/* Maximum number of subcases to output double is...
+ *  0 - sign
+ *  1 - padding and initial digit
+ *  2 - digits left of the radix
+ *  3 - 0s left of the radix        or   radix
+ *  4 - radix                       or   digits right of the radix
+ *  5 - 0s right of the radix
+ *  6 - exponent
+ *  7 - trailing space padding
+ * although not all cases may occur.
+ */
+#define MAX_CALLS 8
+
+/*****************************************************************************/
+
+#define NUM_DIGIT_BLOCKS   ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
+#define NUM_HEX_DIGIT_BLOCKS \
+   ((NUM_HEX_DIGITS+HEX_DIGITS_PER_BLOCK-1)/HEX_DIGITS_PER_BLOCK)
+
+/* WARNING: Adjust _fp_out_wide() below if this changes! */
+
+/* extra space for '-', '.', 'e+###', and nul */
+#define BUF_SIZE  ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
+
+/*****************************************************************************/
+
+static const char fmt[] = "inf\0INF\0nan\0NAN\0.\0,";
+
+#define INF_OFFSET        0		/* must be 1st */
+#define NAN_OFFSET        8		/* must be 2nd.. see hex sign handling */
+#define DECPT_OFFSET     16
+#define THOUSEP_OFFSET   18
+
+#define EMPTY_STRING_OFFSET 3
+
+/*****************************************************************************/
+#if FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
+#error scaling code can not handle FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
+#endif
+
+static const __fpmax_t exp10_table[] =
+{
+	1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L,	/* floats */
+#if FPMAX_MAX_10_EXP < 32
+#error unsupported FPMAX_MAX_10_EXP (< 32).  ANSI/ISO C requires >= 37.
+#endif
+#if FPMAX_MAX_10_EXP >= 64
+	1e64L,
+#endif
+#if FPMAX_MAX_10_EXP >= 128
+	1e128L,
+#endif
+#if FPMAX_MAX_10_EXP >= 256
+	1e256L,
+#endif
+#if FPMAX_MAX_10_EXP >= 512
+	1e512L,
+#endif
+#if FPMAX_MAX_10_EXP >= 1024
+	1e1024L,
+#endif
+#if FPMAX_MAX_10_EXP >= 2048
+	1e2048L,
+#endif
+#if FPMAX_MAX_10_EXP >= 4096
+	1e4096L
+#endif
+#if FPMAX_MAX_10_EXP >= 8192
+#error unsupported FPMAX_MAX_10_EXP.  please increase table
+#endif
+};
+
+#define EXP10_TABLE_SIZE     (sizeof(exp10_table)/sizeof(exp10_table[0]))
+#define EXP10_TABLE_MAX      (1U<<(EXP10_TABLE_SIZE-1))
+
+/*****************************************************************************/
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+
+#if FLT_RADIX != 2
+#error FLT_RADIX != 2 is not currently supported
+#endif
+
+#if FPMAX_MAX_EXP < -FPMAX_MIN_EXP
+#error scaling code can not handle FPMAX_MAX_EXP < -FPMAX_MIN_EXP
+#endif
+
+static const __fpmax_t exp16_table[] = {
+	0x1.0p4L, 0x1.0p8L, 0x1.0p16L, 0x1.0p32L, 0x1.0p64L,
+#if FPMAX_MAX_EXP >= 128
+	0x1.0p128L,
+#endif
+#if FPMAX_MAX_EXP >= 256
+	0x1.0p256L,
+#endif
+#if FPMAX_MAX_EXP >= 512
+	0x1.0p512L,
+#endif
+#if FPMAX_MAX_EXP >= 1024
+	0x1.0p1024L,
+#endif
+#if FPMAX_MAX_EXP >= 2048
+	0x1.0p2048L,
+#endif
+#if FPMAX_MAX_EXP >= 4096
+	0x1.0p4096L,
+#endif
+#if FPMAX_MAX_EXP >= 8192
+	0x1.0p8192L,
+#endif
+#if FPMAX_MAX_EXP >= 16384
+	0x1.0p16384L
+#endif
+#if FPMAX_MAX_EXP >= 32768 
+#error unsupported FPMAX_MAX_EXP.  please increase table
+#endif
+};
+
+#define EXP16_TABLE_SIZE     (sizeof(exp16_table)/sizeof(exp16_table[0]))
+#define EXP16_TABLE_MAX      (1U<<(EXP16_TABLE_SIZE-1))
+
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+/*****************************************************************************/
+
+#define FPO_ZERO_PAD    (0x80 | '0')
+#define FPO_STR_WIDTH   (0x80 | ' ');
+#define FPO_STR_PREC    'p'
+
+size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
+				   __fp_outfunc_t fp_outfunc)
+{
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+	__fpmax_t lower_bnd;
+	__fpmax_t upper_bnd = 1e9;
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+	uint_fast32_t digit_block;
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+	uint_fast32_t base = 10;
+	const __fpmax_t *power_table;
+	int dpb = DIGITS_PER_BLOCK;
+	int ndb = NUM_DIGIT_BLOCKS;
+	int nd = DECIMAL_DIG;
+	int sufficient_precision = 0;
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+	int num_groups = 0;
+	int initial_group;	   /* This does not need to be initialized. */
+	int tslen;			   /* This does not need to be initialized. */
+	int nblk2;			   /* This does not need to be initialized. */
+	const char *ts;		   /* This does not need to be initialized. */
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+	int i, j;
+	int round, o_exp;
+	int exp, exp_neg;
+	int width, preci;
+	int cnt;
+	char *s;
+	char *e;
+	intptr_t pc_fwi[3*MAX_CALLS];
+	intptr_t *ppc;
+	intptr_t *ppc_last;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: The size of exp_buf[] should really be determined by the float constants.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+	char exp_buf[16];
+	char buf[BUF_SIZE];
+	char sign_str[6];			/* Last 2 are for 1st digit + nul. */
+	char o_mode;
+	char mode;
+
+
+	width = info->width;
+	preci = info->prec;
+	mode = info->spec;
+
+	*exp_buf = 'e';
+	if ((mode|0x20) == 'a') {
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+		*exp_buf = 'p';
+		if (preci < 0) {
+			preci = NUM_HEX_DIGITS;
+			sufficient_precision = 1;
+		}
+#else
+		mode += ('g' - 'a');
+#endif
+	}
+
+	if (preci < 0) {
+		preci = 6;
+	}
+
+	*sign_str = '\0';
+	if (PRINT_INFO_FLAG_VAL(info,showsign)) {
+		*sign_str = '+';
+	} else if (PRINT_INFO_FLAG_VAL(info,space)) {
+		*sign_str = ' ';
+	}
+
+	*(sign_str+1) = 0;
+	pc_fwi[5] = INF_OFFSET;
+	if (isnan(x)) {				/* First, check for nan. */
+		pc_fwi[5] = NAN_OFFSET;
+		goto INF_NAN;
+	}
+
+	if (x == 0) {				/* Handle 0 now to avoid false positive. */
+#if 1
+		if (zeroisnegative(x)) { /* Handle 'signed' zero. */
+			*sign_str = '-';
+		}
+#endif
+		exp = -1;
+		goto GENERATE_DIGITS;
+	}
+
+	if (x < 0) {				/* Convert negatives to positives. */
+		*sign_str = '-';
+		x = -x;
+	}
+
+	if (__FPMAX_ZERO_OR_INF_CHECK(x)) {	/* Inf since zero handled above. */
+	INF_NAN:
+		info->pad = ' ';
+		ppc = pc_fwi + 6;
+		pc_fwi[3] = FPO_STR_PREC;
+		pc_fwi[4] = 3;
+		if (mode < 'a') {
+			pc_fwi[5] += 4;
+		}
+		pc_fwi[5] = (intptr_t)(fmt + pc_fwi[5]);
+		goto EXIT_SPECIAL;
+	}
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Clean up defines when hexadecimal float notation is unsupported.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+
+	if ((mode|0x20) == 'a') {
+		lower_bnd = 0x1.0p31L;
+		upper_bnd = 0x1.0p32L;
+		power_table = exp16_table;
+		exp = HEX_DIGITS_PER_BLOCK - 1;
+		i = EXP16_TABLE_SIZE;
+		j = EXP16_TABLE_MAX;
+		dpb = HEX_DIGITS_PER_BLOCK;
+		ndb = NUM_HEX_DIGIT_BLOCKS;
+		nd = NUM_HEX_DIGITS;
+		base = 16;
+	} else {
+		lower_bnd = 1e8;
+/* 		upper_bnd = 1e9; */
+		power_table = exp10_table;
+		exp = DIGITS_PER_BLOCK - 1;
+		i = EXP10_TABLE_SIZE;
+		j = EXP10_TABLE_MAX;
+/* 		dpb = DIGITS_PER_BLOCK; */
+/* 		ndb = NUM_DIGIT_BLOCKS; */
+/* 		base = 10; */
+	}
+
+
+
+#else  /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+#define lower_bnd    1e8
+#define upper_bnd    1e9
+#define power_table  exp10_table
+#define dpb          DIGITS_PER_BLOCK
+#define base         10
+#define ndb          NUM_DIGIT_BLOCKS
+#define nd           DECIMAL_DIG
+
+	exp = DIGITS_PER_BLOCK - 1;
+	i = EXP10_TABLE_SIZE;
+	j = EXP10_TABLE_MAX;
+
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+	exp_neg = 0;
+	if (x < lower_bnd) {		/* Do we need to scale up or down? */
+		exp_neg = 1;
+	}
+
+	do {
+		--i;
+		if (exp_neg) {
+			if (x * power_table[i] < upper_bnd) {
+				x *= power_table[i];
+				exp -= j;
+			}
+		} else {
+			if (x / power_table[i] >= lower_bnd) {
+				x /= power_table[i];
+				exp += j;
+			}
+		}
+		j >>= 1;
+	} while (i);
+	if (x >= upper_bnd) {		/* Handle bad rounding case. */
+		x /= power_table[0];
+		++exp;
+	}
+	assert(x < upper_bnd);
+
+ GENERATE_DIGITS:
+	s = buf + 2;				/* Leave space for '\0' and '0'. */
+	i = 0;
+	do {
+		digit_block = (uint_fast32_t) x;
+		assert(digit_block < upper_bnd);
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Can rounding be a problem?
+#endif /* __UCLIBC_MJN3_ONLY__ */
+		x = (x - digit_block) * upper_bnd;
+		s += dpb;
+		j = 0;
+		do {
+			s[- ++j] = '0' + (digit_block % base);
+			digit_block /= base;
+		} while (j < dpb);
+	} while (++i < ndb);
+
+	/*************************************************************************/
+
+	if (mode < 'a') {
+		*exp_buf -= ('a' - 'A'); /* e->E and p->P */
+		mode += ('a' - 'A');
+	} 
+
+	o_mode = mode;
+	if ((mode == 'g') && (preci > 0)){
+		--preci;
+	}
+	round = preci;
+
+	if (mode == 'f') {
+		round += exp;
+		if (round < -1) {
+			memset(buf, '0', DECIMAL_DIG); /* OK, since 'f' -> decimal case. */
+		    exp = -1;
+		    round = -1;
+		}
+	}
+
+	s = buf;
+	*s++ = 0;					/* Terminator for rounding and 0-triming. */
+	*s = '0';					/* Space to round. */
+
+	i = 0;
+	e = s + nd + 1;
+	if (round < nd) {
+		e = s + round + 2;
+		if (*e >= '0' + (base/2)) {	/* NOTE: We always round away from 0! */
+			i = 1;
+		}
+	}
+
+	do {						/* Handle rounding and trim trailing 0s. */
+		*--e += i;				/* Add the carry. */
+	} while ((*e == '0') || (*e > '0' - 1 + base));
+
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+	if ((mode|0x20) == 'a') {
+		char *q;
+			
+		for (q = e ; *q ; --q) {
+			if (*q > '9') {
+				*q += (*exp_buf - ('p' - 'a') - '9' - 1);
+			}
+		}
+
+		if (e > s) {
+			exp *= 4;			/* Change from base 16 to base 2. */
+		}
+	}
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+	o_exp = exp;
+	if (e <= s) {				/* We carried into an extra digit. */
+		++o_exp;
+		e = s;					/* Needed if all 0s. */
+	} else {
+		++s;
+	}
+	*++e = 0;					/* Terminating nul char. */
+
+	if ((mode == 'g') && ((o_exp >= -4) && (o_exp <= round))) {
+		mode = 'f';
+		preci = round - o_exp;
+	}
+
+	exp = o_exp;
+	if (mode != 'f') {
+		o_exp = 0;
+	}
+
+	if (o_exp < 0) {			/* Exponent is < 0, so */
+		*--s = '0';				/* fake the first 0 digit. */
+	}
+
+	pc_fwi[3] = FPO_ZERO_PAD;
+	pc_fwi[4] = 1;
+	pc_fwi[5] = (intptr_t)(sign_str + 4);
+	sign_str[4] = *s++;
+	sign_str[5] = 0;
+	ppc = pc_fwi + 6;
+
+	i = e - s;					/* Total digits is 'i'. */
+	if (o_exp >= 0) {
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+
+		const char *p;
+
+		if (PRINT_INFO_FLAG_VAL(info,group)
+			&& *(p = __UCLIBC_CURLOCALE_DATA.grouping)
+			) {
+			int nblk1;
+
+			nblk2 = nblk1 = *p;
+			if (*++p) {
+				nblk2 = *p;
+				assert(!*++p);
+			}
+
+			if (o_exp >= nblk1) {
+				num_groups = (o_exp - nblk1) / nblk2 + 1;
+				initial_group = (o_exp - nblk1) % nblk2;
+
+#ifdef __UCLIBC_HAS_WCHAR__
+				if (PRINT_INFO_FLAG_VAL(info,wide)) {
+					/* _fp_out_wide() will fix this up. */
+					ts = fmt + THOUSEP_OFFSET;
+					tslen = 1;
+				} else {
+#endif /* __UCLIBC_HAS_WCHAR__ */
+					ts = __UCLIBC_CURLOCALE_DATA.thousands_sep;
+					tslen = __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
+#ifdef __UCLIBC_HAS_WCHAR__
+				}
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+				width -= num_groups * tslen;
+			}
+		}
+
+
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+		ppc[0] = FPO_STR_PREC;
+		ppc[2] = (intptr_t)(s);
+		if (o_exp >= i) {		/* all digit(s) left of decimal */
+			ppc[1] = i;
+			ppc += 3;
+			o_exp -= i;
+			i = 0;
+			if (o_exp>0) {		/* have 0s left of decimal */
+				ppc[0] = FPO_ZERO_PAD;
+				ppc[1] = o_exp;
+				ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+				ppc += 3;
+			}
+		} else if (o_exp > 0) {	/* decimal between digits */
+			ppc[1] = o_exp;
+			ppc += 3;
+			s += o_exp;
+			i -= o_exp;
+		}
+		o_exp = -1;
+	}
+
+	if (PRINT_INFO_FLAG_VAL(info,alt)
+		|| (i)
+		|| ((o_mode != 'g')
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+			&& (o_mode != 'a')
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+			&& (preci > 0))
+		) {
+		ppc[0] = FPO_STR_PREC;
+#ifdef __LOCALE_C_ONLY
+		ppc[1] = 1;
+		ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
+#else  /* __LOCALE_C_ONLY */
+#ifdef __UCLIBC_HAS_WCHAR__
+			if (PRINT_INFO_FLAG_VAL(info,wide)) {
+				/* _fp_out_wide() will fix this up. */
+				ppc[1] = 1;
+				ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
+			} else {
+#endif /* __UCLIBC_HAS_WCHAR__ */
+				ppc[1] = __UCLIBC_CURLOCALE_DATA.decimal_point_len;
+				ppc[2] = (intptr_t)(__UCLIBC_CURLOCALE_DATA.decimal_point);
+#ifdef __UCLIBC_HAS_WCHAR__
+			}
+#endif /* __UCLIBC_HAS_WCHAR__ */
+#endif /* __LOCALE_C_ONLY */
+			ppc += 3;
+	}
+
+	if (++o_exp < 0) {			/* Have 0s right of decimal. */
+		ppc[0] = FPO_ZERO_PAD;
+		ppc[1] = -o_exp;
+		ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+		ppc += 3;
+	}
+	if (i) {					/* Have digit(s) right of decimal. */
+		ppc[0] = FPO_STR_PREC;
+		ppc[1] = i;
+		ppc[2] = (intptr_t)(s);
+		ppc += 3;
+	}
+
+	if (((o_mode != 'g') || PRINT_INFO_FLAG_VAL(info,alt))
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+		&& !sufficient_precision
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+		) {
+		i -= o_exp;
+		if (i < preci) {		/* Have 0s right of digits. */
+			i = preci - i;
+			ppc[0] = FPO_ZERO_PAD;
+			ppc[1] = i;
+			ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+			ppc += 3;
+		}
+	}
+
+	/* Build exponent string. */
+	if (mode != 'f') {
+		char *p = exp_buf + sizeof(exp_buf);
+		char exp_char = *exp_buf;
+		char exp_sign = '+';
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+		int min_exp_dig_plus_2 = ((o_mode != 'a') ? (2+2) : (2+1));
+#else  /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+#define min_exp_dig_plus_2  (2+2)
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+		if (exp < 0) {
+			exp_sign = '-';
+			exp = -exp;
+		}
+
+		*--p = 0;			/* nul-terminate */
+		j = 2;				/* Count exp_char and exp_sign. */
+		do {
+			*--p = '0' + (exp % 10);
+			exp /= 10;
+		} while ((++j < min_exp_dig_plus_2) || exp); /* char+sign+mindigits */
+		*--p = exp_sign;
+		*--p = exp_char;
+
+		ppc[0] = FPO_STR_PREC;
+		ppc[1] = j;
+		ppc[2] = (intptr_t)(p);
+		ppc += 3;
+	}
+
+ EXIT_SPECIAL:
+	ppc_last = ppc;
+	ppc = pc_fwi + 4;	 /* Need width fields starting with second. */
+	do {
+		width -= *ppc;
+		ppc += 3;
+	} while (ppc < ppc_last);
+
+	ppc = pc_fwi;
+	ppc[0] = FPO_STR_WIDTH;
+	ppc[1] = i = ((*sign_str) != 0);
+	ppc[2] = (intptr_t) sign_str;
+
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+	if (((mode|0x20) == 'a') && (pc_fwi[3] >= 16)) { /* Hex sign handling. */
+		/* Hex and not inf or nan, so prefix with 0x. */
+		char *h = sign_str + i;
+		*h = '0';
+		*++h = 'x' - 'p' + *exp_buf;
+		*++h = 0;
+		ppc[1] = (i += 2);
+	}
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+	if ((width -= i) > 0) {
+		if (PRINT_INFO_FLAG_VAL(info,left)) { /* Left-justified. */
+			ppc_last[0] = FPO_STR_WIDTH;
+			ppc_last[1] = width;
+			ppc_last[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+			ppc_last += 3;
+		} else if (info->pad == '0') { /* 0 padding */
+			ppc[4] += width;	/* Pad second field. */
+		} else {
+			ppc[1] += width;	/* Pad first (sign) field. */
+		}
+	}
+
+	cnt = 0;
+
+	do {
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+
+		if ((ppc == pc_fwi + 6) && num_groups) {
+			const char *gp = (const char *) ppc[2];
+			int len = ppc[1];
+			int blk = initial_group;
+
+			cnt += num_groups * tslen; /* Adjust count now for sep chars. */
+
+/* 			printf("\n"); */
+			do {
+				if (!blk) {		/* Initial group could be 0 digits long! */
+					blk = nblk2;
+				} else if (len >= blk) { /* Enough digits for a group. */
+/* 					printf("norm:  len=%d blk=%d  \"%.*s\"\n", len, blk, blk, gp); */
+					fp_outfunc(fp, *ppc, blk, (intptr_t) gp);
+					assert(gp);
+					if (*gp) {
+						gp += blk;
+					}
+					len -= blk;
+				} else {		/* Transition to 0s. */
+/* 					printf("trans: len=%d blk=%d  \"%.*s\"\n", len, blk, len, gp); */
+					if (len) {
+/* 						printf("len\n"); */
+						fp_outfunc(fp, *ppc, len, (intptr_t) gp);
+						gp += len;
+					}
+
+					if (ppc[3] == FPO_ZERO_PAD) { /* Need to group 0s */
+/* 						printf("zeropad\n"); */
+						cnt += ppc[1];
+						ppc += 3;
+						gp = (const char *) ppc[2];
+						blk -= len;	/* blk > len, so blk still > 0. */
+						len = ppc[1];
+						continue; /* Don't decrement num_groups here. */
+					} else {
+						assert(num_groups == 0);
+						break;
+					}
+				}
+
+				if (num_groups <= 0) {
+					break;
+				}
+				--num_groups;
+
+				fp_outfunc(fp, FPO_STR_PREC, tslen, (intptr_t) ts);
+				blk = nblk2;
+
+/* 				printf("num_groups=%d   blk=%d\n", num_groups, blk); */
+
+			} while (1);
+		} else
+
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+
+		fp_outfunc(fp, *ppc, ppc[1], ppc[2]); /* NOTE: Remember 'else' above! */
+
+		cnt += ppc[1];
+		ppc += 3;
+	} while (ppc < ppc_last);
+
+	return cnt;
+}
diff --git a/libc/stdio/_fwrite.c b/libc/stdio/_fwrite.c
new file mode 100644
index 000000000..a706ba7e6
--- /dev/null
+++ b/libc/stdio/_fwrite.c
@@ -0,0 +1,78 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+#ifdef __STDIO_BUFFERS
+
+/* Either buffer data or (commit buffer if necessary and) write. */
+
+size_t __stdio_fwrite(const unsigned char * __restrict buffer,
+					  size_t bytes,
+					  register FILE * __restrict stream)
+{
+	size_t pending;
+	const unsigned char *p;
+
+	__STDIO_STREAM_VALIDATE(stream);
+	assert(__STDIO_STREAM_IS_WRITING(stream));
+	assert(buffer);
+	assert(bytes);
+
+	if (!__STDIO_STREAM_IS_NBF(stream)) { /* FBF or LBF. */
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Try to consolidate some of the code?
+#endif
+		if (__STDIO_STREAM_IS_FAKE_VSNPRINTF(stream)) {
+			pending = __STDIO_STREAM_BUFFER_WAVAIL(stream);
+			if (pending > bytes) {
+				pending = bytes;
+			}
+			memcpy(stream->__bufpos, buffer, pending);
+			stream->__bufpos += pending;
+			__STDIO_STREAM_VALIDATE(stream);
+			return bytes;
+		}
+
+/* 	RETRY: */
+		if (bytes <= __STDIO_STREAM_BUFFER_WAVAIL(stream)) {
+			memcpy(stream->__bufpos, buffer, bytes);
+			stream->__bufpos += bytes;
+			if (__STDIO_STREAM_IS_LBF(stream)
+				&& memrchr(buffer, '\n', bytes)	/* Search backwards. */
+				) {
+				if ((pending = __STDIO_COMMIT_WRITE_BUFFER(stream)) > 0) {
+					if (pending > bytes) {
+						pending = bytes;
+					}
+					buffer += (bytes - pending);
+					if ((p = memchr(buffer, '\n', pending)) != NULL) {
+						pending = (buffer + pending) - p;
+						bytes -= pending;
+						stream->__bufpos -= pending;
+					}
+				}
+			}
+			__STDIO_STREAM_VALIDATE(stream);
+			return bytes;
+		}
+		/* FBF or LBF and not enough space in buffer. */
+		if (__STDIO_STREAM_BUFFER_WUSED(stream)) { /* Buffered data. */
+			if (__STDIO_COMMIT_WRITE_BUFFER(stream)) { /* Commit failed! */
+				return 0;
+			}
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Do we want to try again if data now fits in buffer?
+#endif
+/* 			goto RETRY; */
+		}
+	}
+
+	return __stdio_WRITE(stream, buffer, bytes);
+}
+
+#endif
diff --git a/libc/stdio/_load_inttype.c b/libc/stdio/_load_inttype.c
new file mode 100644
index 000000000..2dd559a53
--- /dev/null
+++ b/libc/stdio/_load_inttype.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+#include <printf.h>
+
+uintmax_t _load_inttype(int desttype, register const void *src, int uflag)
+{
+	if (uflag >= 0) {			/* unsigned */
+#if LONG_MAX != INT_MAX
+		if (desttype & (PA_FLAG_LONG|PA_FLAG_LONG_LONG)) {
+#ifdef LLONG_MAX
+			if (desttype == PA_FLAG_LONG_LONG) {
+				return *((unsigned long long int *) src);
+			}
+#endif
+			return *((unsigned long int *) src);
+		}
+#else  /* LONG_MAX != INT_MAX */
+#ifdef LLONG_MAX
+		if (desttype & PA_FLAG_LONG_LONG) {
+			return *((unsigned long long int *) src);
+		}
+#endif
+#endif /* LONG_MAX != INT_MAX */
+		{
+			unsigned int x;
+			x = *((unsigned int *) src);
+			if (desttype == __PA_FLAG_CHAR) x = (unsigned char) x;
+#if SHRT_MAX != INT_MAX
+			if (desttype == PA_FLAG_SHORT) x = (unsigned short int) x;
+#endif
+			return x;
+		}
+	} else {					/* signed */
+#if LONG_MAX != INT_MAX
+		if (desttype & (PA_FLAG_LONG|PA_FLAG_LONG_LONG)) {
+#ifdef LLONG_MAX
+			if (desttype == PA_FLAG_LONG_LONG) {
+				return *((long long int *) src);
+			}
+#endif
+			return *((long int *) src);
+		}
+#else  /* LONG_MAX != INT_MAX */
+#ifdef LLONG_MAX
+		if (desttype & PA_FLAG_LONG_LONG) {
+			return *((long long int *) src);
+		}
+#endif
+#endif /* LONG_MAX != INT_MAX */
+		{
+			int x;
+			x = *((int *) src);
+			if (desttype == __PA_FLAG_CHAR) x = (char) x;
+#if SHRT_MAX != INT_MAX
+			if (desttype == PA_FLAG_SHORT) x = (short int) x;
+#endif
+			return x;
+		}
+	}
+}
diff --git a/libc/stdio/_rfill.c b/libc/stdio/_rfill.c
new file mode 100644
index 000000000..145c1d78e
--- /dev/null
+++ b/libc/stdio/_rfill.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Do we really need a seperate rfill function?
+#endif
+
+#ifdef __STDIO_BUFFERS
+
+/* Read some data into the buffer.
+ * Returns number of bytes read into the buffer.
+ * If 0 is returned, then either EOF or ERROR.
+ * Side effects are those of _stdio_READ.
+ */
+
+size_t __stdio_rfill(register FILE *__restrict stream)
+{
+	size_t rv;
+
+	__STDIO_STREAM_VALIDATE(stream);
+	assert(stream->__filedes >= -1);
+	assert(__STDIO_STREAM_IS_READING(stream));
+	assert(!__STDIO_STREAM_BUFFER_RAVAIL(stream)); /* Buffer must be empty. */
+	assert(__STDIO_STREAM_BUFFER_SIZE(stream));	/* Must have a buffer. */
+	assert(!(stream->__modeflags & __FLAG_UNGOT));
+#ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__
+	assert(stream->__bufgetc_u == stream->__bufstart);
+#endif
+
+	rv = __stdio_READ(stream, stream->__bufstart,
+					  stream->__bufend - stream->__bufstart);
+	stream->__bufpos = stream->__bufstart;
+	stream->__bufread = stream->__bufstart + rv;
+
+	__STDIO_STREAM_VALIDATE(stream);
+	return rv;
+}
+
+#endif
diff --git a/libc/stdio/_stdio.c b/libc/stdio/_stdio.c
new file mode 100644
index 000000000..4aae3c418
--- /dev/null
+++ b/libc/stdio/_stdio.c
@@ -0,0 +1,432 @@
+/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+/* This is pretty much straight from uClibc, but with one important
+ * difference.
+ *
+ * We now initialize the locking flag to user locking instead of
+ * auto locking (i.e. FSETLOCKING_BYCALLER vs FSETLOCKING_INTERNAL).
+ * This greatly benefits non-threading applications linked to a
+ * shared thread-enabled library.  In threading applications, we
+ * walk the stdio open file list and reset the locking mode
+ * appropriately when the thread subsystem is initialized.
+ */
+
+/**********************************************************************/
+
+#ifdef __UCLIBC_HAS_WCHAR__
+#define __STDIO_FILE_INIT_WUNGOT		{ 0, 0 },
+#else
+#define __STDIO_FILE_INIT_WUNGOT
+#endif
+
+#ifdef __STDIO_GETC_MACRO
+# define __STDIO_FILE_INIT_BUFGETC(x) x,
+#else
+# define __STDIO_FILE_INIT_BUFGETC(x)
+#endif
+
+#ifdef __STDIO_PUTC_MACRO
+# define __STDIO_FILE_INIT_BUFPUTC(x) x,
+#else
+# define __STDIO_FILE_INIT_BUFPUTC(x)
+#endif
+
+#ifdef __STDIO_HAS_OPENLIST
+#define __STDIO_FILE_INIT_NEXT(next)	(next),
+#else
+#define __STDIO_FILE_INIT_NEXT(next)
+#endif
+
+#ifdef __STDIO_BUFFERS
+#define __STDIO_FILE_INIT_BUFFER