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/inet/addr.c                                   |    3 +-
 libc/misc/assert/__assert.c                        |   33 +-
 libc/misc/locale/locale.c                          |    4 +-
 libc/misc/time/time.c                              |    2 +-
 libc/misc/wchar/Makefile                           |   18 +-
 libc/misc/wchar/wchar.c                            |   41 +-
 libc/misc/wchar/wstdio.c                           |   14 +-
 libc/pwd_grp/pwd_grp.c                             |   15 +-
 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 +
 libc/stdlib/abort.c                                |    8 -
 libc/stdlib/ptsname.c                              |    3 +-
 libc/stdlib/stdlib.c                               |   10 +-
 libc/string/wstring.c                              |    9 +-
 libc/sysdeps/linux/common/bits/uClibc_locale.h     |    1 +
 libc/sysdeps/linux/common/bits/uClibc_stdio.h      |  716 ++--
 .../linux/common/bits/uClibc_uintmaxtostr.h        |  115 +
 115 files changed, 9165 insertions(+), 7717 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
 create mode 100644 libc/sysdeps/linux/common/bits/uClibc_uintmaxtostr.h

(limited to 'libc')

diff --git a/libc/inet/addr.c b/libc/inet/addr.c
index a75916e69..75ebc191e 100644
--- a/libc/inet/addr.c
+++ b/libc/inet/addr.c
@@ -16,13 +16,14 @@
  * Changed to use _int10tostr.
  */
 
+#define _GNU_SOURCE
 #define __FORCE_GLIBC
 #include <features.h>
-#define _STDIO_UTILITY			/* For _int10tostr. */
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 #include <netinet/in.h>
+#include <bits/uClibc_uintmaxtostr.h>
 
 int inet_aton(const char *cp, struct in_addr *addrptr);
 
diff --git a/libc/misc/assert/__assert.c b/libc/misc/assert/__assert.c
index 74b5ee86f..2949b75f0 100644
--- a/libc/misc/assert/__assert.c
+++ b/libc/misc/assert/__assert.c
@@ -27,10 +27,11 @@
  * and is useful in debugging the stdio code.
  */
 
-#define _STDIO_UTILITY	/* For _stdio_fdout and _int10tostr. */
+#define _ISOC99_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <bits/uClibc_uintmaxtostr.h>
 
 /* Get the prototype from assert.h as a double-check. */
 #undef NDEBUG
@@ -44,8 +45,6 @@
 extern const char *__progname;
 #endif
 
-#if 1
-
 static int in_assert;			/* bss inits to 0. */
 
 void __assert(const char *assertion, const char * filename,
@@ -69,31 +68,3 @@ void __assert(const char *assertion, const char * filename,
 	}
 	abort();
 }
-
-#else
-
-void __assert(const char *assertion, const char * filename,
-			  int linenumber, register const char * function)
-{
-	char buf[__BUFLEN_INT10TOSTR];
-
-	_stdio_fdout(STDERR_FILENO,
-#ifdef ASSERT_SHOW_PROGNAME
-				 __progname,
-				 ": ",
-#endif
-				 filename,
-				 ":",
-				 _int10tostr(buf+sizeof(buf)-1, linenumber),
-				 ": ",
-				 /* Function name isn't available with some compilers. */
-				 ((function == NULL) ? "?function?" : function),
-				 ":  Assertion `",
-				 assertion,
-				 "' failed.\n",
-				 NULL
-				 );
-	abort();
-}
-
-#endif
diff --git a/libc/misc/locale/locale.c b/libc/misc/locale/locale.c
index cf058ce3e..c6a1a2dd0 100644
--- a/libc/misc/locale/locale.c
+++ b/libc/misc/locale/locale.c
@@ -346,7 +346,7 @@ struct lconv *localeconv(void)
 /**********************************************************************/
 #if defined(L__locale_init) && !defined(__LOCALE_C_ONLY)
 
-static __uclibc_locale_t __global_locale_data;
+__uclibc_locale_t __global_locale_data;
 
 __locale_t __global_locale = &__global_locale_data;
 
@@ -1420,7 +1420,7 @@ int __locale_mbrtowc_l(wchar_t *__restrict dst,
 		mbstate_t ps;
 		const char *p = src;
 		size_t r;
-		ps.mask = 0;
+		ps.__mask = 0;
 		r = _wchar_utf8sntowcs(dst, 1, &p, SIZE_MAX, &ps, 1);
 		return (r == 1) ? (p-src) : r; /* Need to return 0 if nul char. */
 	}
diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c
index e2f1f6c6d..8176e071a 100644
--- a/libc/misc/time/time.c
+++ b/libc/misc/time/time.c
@@ -135,7 +135,6 @@
  */
 
 #define _GNU_SOURCE
-#define _STDIO_UTILITY
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
@@ -147,6 +146,7 @@
 #include <ctype.h>
 #include <langinfo.h>
 #include <locale.h>
+#include <bits/uClibc_uintmaxtostr.h>
 
 #ifdef __UCLIBC_HAS_XLOCALE__
 #include <xlocale.h>
diff --git a/libc/misc/wchar/Makefile b/libc/misc/wchar/Makefile
index a96dae2b4..b1db37293 100644
--- a/libc/misc/wchar/Makefile
+++ b/libc/misc/wchar/Makefile
@@ -33,17 +33,17 @@ ifeq ($(UCLIBC_HAS_LOCALE),y)
 	MOBJ1 += iconv.o
 endif
 
-MSRC2=  wstdio.c
-MOBJ2=  fwide.o \
-	fgetwc.o getwchar.o fgetws.o \
-	fputwc.o putwchar.o fputws.o \
-	ungetwc.o
-# getwc (fgetwc alias) getwc_unlocked (fgetwc_unlocked alias)
-# putwc (fputwc alias) putwc_unlocked (fputwc_unlocked alias)
-
+# The stdio and time related wide functions are now built in the normal
+# directories.
+#
+# stdio: 
+#	fwide fgetwc getwchar fgetws fputwc putwchar fputws ungetwc
+#	getwc (fgetwc alias) getwc_unlocked (fgetwc_unlocked alias)
+#	putwc (fputwc alias) putwc_unlocked (fputwc_unlocked alias)
+# time:
 # wcsftime
 
-OBJS=$(MOBJ1) $(MOBJ2)
+OBJS=$(MOBJ1)
 
 all: $(OBJS) $(LIBC)
 
diff --git a/libc/misc/wchar/wchar.c b/libc/misc/wchar/wchar.c
index 4fc96f430..d1383c99f 100644
--- a/libc/misc/wchar/wchar.c
+++ b/libc/misc/wchar/wchar.c
@@ -1,5 +1,5 @@
 
-/*  Copyright (C) 2002     Manuel Novoa III
+/*  Copyright (C) 2002, 2003, 2004     Manuel Novoa III
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
@@ -92,6 +92,9 @@
  * Aug 18, 2003
  * Bug fix: _wchar_utf8sntowcs and _wchar_wcsntoutf8s now set errno if EILSEQ.
  *
+ * Feb 11, 2004
+ * Bug fix: Fix size check for remaining output space in iconv().
+ *
  * Manuel
  */
 
@@ -193,7 +196,7 @@ wint_t btowc(int c)
 
 	if (c != EOF) {
 		*buf = (unsigned char) c;
-		mbstate.mask = 0;		/* Initialize the mbstate. */
+		mbstate.__mask = 0;		/* Initialize the mbstate. */
 		if (mbrtowc(&wc, buf, 1, &mbstate) <= 1) {
 			return wc;
 		}
@@ -251,7 +254,7 @@ int wctob(wint_t c)
 
 int mbsinit(const mbstate_t *ps)
 {
-	return !ps || !ps->mask;
+	return !ps || !ps->__mask;
 }
 
 #endif
@@ -291,7 +294,8 @@ size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s,
 		s = empty_string;
 		n = 1;
 	} else if (!n) {
-		return (ps->mask && (ps->wc == 0xffffU)) /* TODO: change error code? */
+		/* TODO: change error code? */
+		return (ps->__mask && (ps->__wc == 0xffffU))
 			? ((size_t) -1) : ((size_t) -2);
 	}
 
@@ -434,15 +438,15 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
 		return 0;
 	}
 
-	if ((mask = (__uwchar_t) ps->mask) != 0) { /* A continuation... */
+	if ((mask = (__uwchar_t) ps->__mask) != 0) { /* A continuation... */
 #ifdef DECODER
-		wc = (__uwchar_t) ps->wc;
+		wc = (__uwchar_t) ps->__wc;
 		if (n) {
 			goto CONTINUE;
 		}
 		goto DONE;
 #else
-		if ((wc = (__uwchar_t) ps->wc) != 0xffffU) {
+		if ((wc = (__uwchar_t) ps->__wc) != 0xffffU) {
 			/* TODO: change error code here and below? */
 			if (n) {
 				goto CONTINUE;
@@ -472,8 +476,8 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
 			wc = 0xfffdU;
 			goto COMPLETE;
 #else
-			ps->mask = mask;
-			ps->wc = 0xffffU;
+			ps->__mask = mask;
+			ps->__wc = 0xffffU;
 			__set_errno(EILSEQ);
 			return (size_t) -1;	/* Illegal start byte! */
 #endif
@@ -532,8 +536,8 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
 				} while ((mask >>= 5) >= 0x40);
 				goto DONE;
 			}
-			ps->mask = (wchar_t) mask;
-			ps->wc = (wchar_t) wc;
+			ps->__mask = (wchar_t) mask;
+			ps->__wc = (wchar_t) wc;
 			*src = s;
 			return (size_t) -2;
 		}
@@ -552,8 +556,8 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
 #endif
 
  DONE:
-	/* ps->wc is irrelavent here. */
-	ps->mask = 0;
+	/* ps->__wc is irrelavent here. */
+	ps->__mask = 0;
 	if (pwc != wcbuf) {
 		*src = s;
 	}
@@ -1037,7 +1041,7 @@ int wcswidth(const wchar_t *pwcs, size_t n)
 	else if (ENCODING == __ctype_encoding_8_bit) {
 		mbstate_t mbstate;
 
-		mbstate.mask = 0;			/* Initialize the mbstate. */
+		mbstate.__mask = 0;			/* Initialize the mbstate. */
 		if (__wcsnrtombs(NULL, &pwcs, n, SIZE_MAX, &mbstate) == ((size_t) - 1)) {
 			return -1;
 		}
@@ -1282,7 +1286,8 @@ iconv_t weak_function iconv_open(const char *tocode, const char *fromcode)
 			px->tobom0 = px->tobom = (tocodeset & 0x10) >> 4;
 			px->fromcodeset0 = px->fromcodeset = fromcodeset;
 			px->frombom0 = px->frombom = (fromcodeset & 0x10) >> 4;
-			px->skip_invalid_input = px->tostate.mask = px->fromstate.mask = 0;
+			px->skip_invalid_input = px->tostate.__mask
+				= px->fromstate.__mask = 0;
 			return (iconv_t) px;
 		}
 	} else {
@@ -1316,7 +1321,7 @@ size_t weak_function iconv(iconv_t cd, char **__restrict inbuf,
 		 * shift sequence to return to initial state! */
 		if ((px->fromcodeset & 0xf0) == 0xe0) {
 		}
-		px->tostate.mask = px->fromstate.mask = 0;
+		px->tostate.__mask = px->fromstate.__mask = 0;
 		px->fromcodeset = px->fromcodeset0;
 		px->tobom = px->tobom0;
 		px->frombom = px->frombom0;
@@ -1398,7 +1403,7 @@ size_t weak_function iconv(iconv_t cd, char **__restrict inbuf,
 					INVALID:
 						__set_errno(EINVAL);
 					} else {
-						px->fromstate.mask = 0;
+						px->fromstate.__mask = 0;
 						inci = 1;
 					ILLEGAL:
 						if (px->skip_invalid_input) {
@@ -1444,7 +1449,7 @@ size_t weak_function iconv(iconv_t cd, char **__restrict inbuf,
 
 		if (px->tocodeset >= IC_MULTIBYTE) {
 			inco = (px->tocodeset == IC_WCHAR_T) ? 4: (px->tocodeset & 6);
-			if (*outbytesleft < inci) goto TOO_BIG;
+			if (*outbytesleft < inco) goto TOO_BIG;
 			if (px->tocodeset != IC_WCHAR_T) {
 				if (((__uwchar_t) wc) > (((px->tocodeset & IC_UCS_4) == IC_UCS_4)
 										 ? 0x7fffffffUL : 0x10ffffUL)
diff --git a/libc/misc/wchar/wstdio.c b/libc/misc/wchar/wstdio.c
index e984bf837..b49494f35 100644
--- a/libc/misc/wchar/wstdio.c
+++ b/libc/misc/wchar/wstdio.c
@@ -57,7 +57,7 @@
 #include <errno.h>
 #include <assert.h>
 
-#ifndef __STDIO_THREADSAFE
+#ifndef __UCLIBC_HAS_THREADS__
 
 #ifdef __BCC__
 #define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
@@ -85,7 +85,7 @@ void NAME PARAMS
 #define __STDIO_THREADLOCK_OPENLIST
 #define __STDIO_THREADUNLOCK_OPENLIST
 
-#else  /* __STDIO_THREADSAFE */
+#else  /* __UCLIBC_HAS_THREADS__ */
 
 #include <pthread.h>
 
@@ -121,7 +121,7 @@ void NAME##_unlocked PARAMS
 #define __STDIO_THREADTRYLOCK_OPENLIST \
 	__pthread_mutex_trylock(&_stdio_openlist_lock)
 
-#endif /* __STDIO_THREADSAFE */
+#endif /* __UCLIBC_HAS_THREADS__ */
 
 #ifndef __STDIO_BUFFERS
 #error stdio buffers are currently required for wide i/o
@@ -404,9 +404,9 @@ wint_t ungetwc(wint_t c, register FILE *stream)
 	/* If can't read or c == WEOF or ungot slots already filled, then fail. */
 	if ((stream->modeflags
 		 & (__MASK_UNGOT2|__FLAG_WRITEONLY
-#ifndef __STDIO_AUTO_RW_TRANSITION
+#ifndef __UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION__
 			|__FLAG_WRITING		/* Note: technically no, but yes in spirit */
-#endif /* __STDIO_AUTO_RW_TRANSITION */
+#endif /* __UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION__ */
 			))
 		|| ((stream->modeflags & __MASK_UNGOT1) && (stream->ungot[1]))
 		|| (c == WEOF) ) {
@@ -417,11 +417,11 @@ wint_t ungetwc(wint_t c, register FILE *stream)
 /*  ungot_width */
 
 #ifdef __STDIO_BUFFERS
-#ifdef __STDIO_AUTO_RW_TRANSITION
+#ifdef __UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION__
 	if (stream->modeflags & __FLAG_WRITING) {
 		fflush_unlocked(stream); /* Commit any write-buffered chars. */
 	}
-#endif /* __STDIO_AUTO_RW_TRANSITION */
+#endif /* __UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION__ */
 #endif /* __STDIO_BUFFERS */
 
 	/* Clear EOF and WRITING flags, and set READING FLAG */
diff --git a/libc/pwd_grp/pwd_grp.c b/libc/pwd_grp/pwd_grp.c
index d3047e760..90b4eafd6 100644
--- a/libc/pwd_grp/pwd_grp.c
+++ b/libc/pwd_grp/pwd_grp.c
@@ -777,11 +777,12 @@ int putgrent(const struct group *__restrict p, FILE *__restrict f)
 	char **m;
 	const char *fmt;
 	int rv = -1;
+	__STDIO_AUTO_THREADLOCK_VAR;
 
 	if (!p || !f) {				/* Sigh... glibc checks. */
 		__set_errno(EINVAL);
 	} else {
-		__STDIO_THREADLOCK(f);
+		__STDIO_AUTO_THREADLOCK(f);
 
 		if (fprintf(f, "%s:%s:%lu:",
 					p->gr_name, p->gr_passwd,
@@ -809,7 +810,7 @@ int putgrent(const struct group *__restrict p, FILE *__restrict f)
 
 		}
 
-		__STDIO_THREADUNLOCK(f);
+		__STDIO_AUTO_THREADUNLOCK(f);
 	}
 
 	return rv;
@@ -835,10 +836,11 @@ int putspent(const struct spwd *p, FILE *stream)
 	long int x;
 	int i;
 	int rv = -1;
+	__STDIO_AUTO_THREADLOCK_VAR;
 
 	/* Unlike putpwent and putgrent, glibc does not check the args. */
 
-	__STDIO_THREADLOCK(stream);
+	__STDIO_AUTO_THREADLOCK(stream);
 
 	if (fprintf(stream, "%s:%s:", p->sp_namp,
 				(p->sp_pwdp ? p->sp_pwdp : "")) < 0
@@ -865,7 +867,7 @@ int putspent(const struct spwd *p, FILE *stream)
 	}
 
  DO_UNLOCK:
-	__STDIO_THREADUNLOCK(stream);
+	__STDIO_AUTO_THREADUNLOCK(stream);
 
 	return rv;
 }
@@ -1117,11 +1119,12 @@ int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
 	int line_len;
 	int skip;
 	int rv = ERANGE;
+	__STDIO_AUTO_THREADLOCK_VAR;
 
 	if (buflen < PWD_BUFFER_SIZE) {
 		__set_errno(rv);
 	} else {
-		__STDIO_THREADLOCK(f);
+		__STDIO_AUTO_THREADLOCK(f);
 
 		skip = 0;
 		do {
@@ -1165,7 +1168,7 @@ int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
 			}
 		} while (1);
 
-		__STDIO_THREADUNLOCK(f);
+		__STDIO_AUTO_THREADUNLOCK(f);
 	}
 
 	return rv;
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) * up