Browse Source

Lots of stdio cleanups. Several bug fixes, addition of a number of functions
to supplement macros in stdio.h, change perror to use stdio package instead
of "write". Also add back in weak stdio initialization for static lib case.

Manuel Novoa III 23 years ago
parent
commit
d521275a86
5 changed files with 422 additions and 307 deletions
  1. 38 32
      include/stdio.h
  2. 7 4
      libc/stdio/Makefile
  3. 21 14
      libc/stdio/perror.c
  4. 28 13
      libc/stdio/printf.c
  5. 328 244
      libc/stdio/stdio.c

+ 38 - 32
include/stdio.h

@@ -43,9 +43,9 @@ struct __stdio_file {
   int fd; /* the file descriptor associated with the stream */
   int mode;
 
-  char unbuf[8];	   /* The buffer for 'unbuffered' streams */
-
   struct __stdio_file * next;
+
+  char unbuf[8];	   /* The buffer for 'unbuffered' streams */
 };
 
 typedef struct __stdio_file FILE;
@@ -65,7 +65,6 @@ typedef struct __stdio_file FILE;
 #define _IONBF 2		/* No buffering.  */
 
 /* Possible states for a file stream -- internal use only */
-#define __MODE_IOTRAN	0
 #define __MODE_BUF	0x03	/* Modal buffering dependent on isatty */
 #define __MODE_FREEBUF	0x04	/* Buffer allocated with malloc, can free */
 #define __MODE_FREEFIL	0x08	/* FILE allocated with malloc, can free */
@@ -78,18 +77,12 @@ typedef struct __stdio_file FILE;
 #define __MODE_ERR	0x200	/* Error status */
 #define __MODE_UNGOT	0x400	/* Buffer has been polluted by ungetc */
 
-
 /* The possibilities for the third argument to `fseek'.
    These values should not be changed.  */
 #define SEEK_SET	0	/* Seek from beginning of file.  */
 #define SEEK_CUR	1	/* Seek from current position.  */
 #define SEEK_END	2	/* Seek from end of file.  */
 
-
-#define stdio_pending(fp) ((fp)->bufread>(fp)->bufpos)
-
-
-
 /* Default path prefix for `tempnam' and `tmpnam'.  */
 #define P_tmpdir	"/tmp"
 /* Get the values:
@@ -153,44 +146,43 @@ extern int fclose __P ((FILE *__stream));
 /* Flush STREAM, or all streams if STREAM is NULL.  */
 extern int fflush __P ((FILE *__stream));
 
-/* Open a file and create a new stream for it.  */
-extern FILE *fopen __P ((__const char *__restrict __filename,
-			 __const char *__restrict __modes));
 /* Used internally to actuall open files */
 extern FILE *__fopen __P((__const char *__restrict __filename, int __fd, 
-	    FILE *__restrict __stream, __const char *__restrict __modes));
+	    FILE *__restrict __stream, __const char *__restrict __mode));
+/* Open a file and create a new stream for it.  */
+extern FILE *fopen __P ((__const char *__restrict __filename,
+			 __const char *__restrict __mode));
 #define fopen(__file, __mode)         __fopen((__file), -1, (FILE*)0, (__mode))
 /* Open a file, replacing an existing stream with it. */
 extern FILE *freopen __P ((__const char *__restrict __filename,
-			   __const char *__restrict __modes,
+			   __const char *__restrict __mode,
 			   FILE *__restrict __stream));
 #define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode))
 
 #ifdef __USE_LARGEFILE64
 extern FILE *fopen64 __P ((__const char *__restrict __filename,
-			   __const char *__restrict __modes));
+			   __const char *__restrict __mode));
 extern FILE *freopen64 __P ((__const char *__restrict __filename,
-			     __const char *__restrict __modes,
+			     __const char *__restrict __mode,
 			     FILE *__restrict __stream));
 #endif
 
 #ifdef	__USE_POSIX
 /* Create a new stream that refers to an existing system file descriptor.  */
-extern FILE *fdopen __P ((int __fd, __const char *__modes));
+extern FILE *fdopen __P ((int __fd, __const char *__mode));
 #define fdopen(__file, __mode)  __fopen((char*)0, (__file), (FILE*)0, (__mode))
 #endif
 
 
-/* If BUF is NULL, make STREAM unbuffered.
-   Else make it use buffer BUF, of size BUFSIZ.  */
-extern void setbuf __P ((FILE *__restrict __stream, char *__restrict __buf));
-#define setbuf(__fp, __buf) setbuffer((__fp), (__buf), BUFSIZ)
-
 /* Make STREAM use buffering mode MODE.
    If BUF is not NULL, use N bytes of it for buffering;
    else allocate an internal buffer N bytes long.  */
 extern int setvbuf __P ((FILE *__restrict __stream, char *__restrict __buf,
-			 int __modes, size_t __n));
+			 int __mode, size_t __n));
+
+/* If BUF is NULL, make STREAM unbuffered.
+   Else make it use buffer BUF, of size BUFSIZ.  */
+extern void setbuf __P ((FILE *__restrict __stream, char *__restrict __buf));
 
 #ifdef	__USE_BSD
 /* If BUF is NULL, make STREAM unbuffered.
@@ -200,7 +192,6 @@ extern void setbuffer __P ((FILE *__restrict __stream, char *__restrict __buf,
 
 /* Make STREAM line-buffered.  */
 extern void setlinebuf __P ((FILE *__stream));
-#define setlinebuf(__fp)             setvbuf((__fp), (char*)0, _IOLBF, 0)
 #endif
 
 
@@ -279,7 +270,7 @@ extern int getc __P ((FILE *__stream));
 
 /* Read a character from stdin.  */
 extern int getchar __P ((void));
-#define getchar() getc(stdin)
+#define getchar() getc(_stdin)
 
 /* The C standard explicitly says this is a macro, so be that way */
 #define getc(stream)	\
@@ -292,7 +283,8 @@ extern int putc __P ((int __c, FILE *__stream));
 
 /* Write a character to stdout.  */
 extern int putchar __P ((int __c));
-#define putchar(c) putc((c), stdout)  
+/* Beware! stdout can be redefined! */
+#define putchar(c) putc((c), _stdout)
 
 /* The C standard explicitly says this can be a macro, so be that way */
 #define putc(c, stream)	\
@@ -354,12 +346,13 @@ extern size_t fread __P ((void *__restrict __ptr, size_t __size,
 extern size_t fwrite __P ((__const void *__restrict __ptr, size_t __size,
 			   size_t __n, FILE *__restrict __s));
 
+/* Rewind to the beginning of STREAM.  */
+extern void rewind __P ((FILE *__stream));
+
 /* Seek to a certain position on STREAM.  */
 extern int fseek __P ((FILE *__stream, long int __off, int __whence));
 /* Return the current position of STREAM.  */
 extern long int ftell __P ((FILE *__stream));
-/* Rewind to the beginning of STREAM.  */
-extern void rewind __P ((FILE *__stream));
 
 /* The Single Unix Specification, Version 2, specifies an alternative,
    more adequate interface for the two functions above which deal with
@@ -377,15 +370,27 @@ typedef __off64_t off64_t;
 # define off64_t off64_t
 #endif
 
+#ifndef fpos_t
+typedef off_t fpos_t;
+#define fpos_t fpos_t
+#endif
+
+/* Seek to a certain position on STREAM.  */
+extern int fsetpos __P((FILE *__stream, __const fpos_t *__pos));
+/* Return the current position of STREAM.  */
+extern int fgetpos __P((FILE *__stream, fpos_t *__pos));
 
 /* Clear the error and EOF indicators for STREAM.  */
 extern void clearerr __P ((FILE *__stream));
-#define clearerr(fp)	((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0)
 /* Return the EOF indicator for STREAM.  */
 extern int feof __P ((FILE *__stream));
-#define feof(fp)   	(((fp)->mode&__MODE_EOF) != 0)
 /* Return the error indicator for STREAM.  */
 extern int ferror __P ((FILE *__stream));
+
+/* Macro versions of the 3 previous functions */
+/* If fp is NULL... */
+#define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR), (void)0)
+#define feof(fp)   	(((fp)->mode&__MODE_EOF) != 0)
 #define ferror(fp)	(((fp)->mode&__MODE_ERR) != 0)
 
 /* Print a message describing the meaning of the value of errno.  */
@@ -399,13 +404,14 @@ extern __const char *__const sys_errlist[];
 #ifdef	__USE_POSIX
 /* Return the system file descriptor for STREAM.  */
 extern int fileno __P ((FILE *__stream));
-#define fileno(fp)	((fp)->fd)
+/* Only use the macro below if you know fp is a valid FILE for a valid fd. */
+#define __fileno(fp)	((fp)->fd)
 #endif /* Use POSIX.  */
 
 #if (defined __USE_POSIX2 || defined __USE_SVID  || defined __USE_BSD || \
      defined __USE_MISC)
 /* Create a new stream connected to a pipe running the given command.  */
-extern FILE *popen __P ((__const char *__command, __const char *__modes));
+extern FILE *popen __P ((__const char *__command, __const char *__mode));
 
 /* Close a stream opened by popen and return the status of its child.  */
 extern int pclose __P ((FILE *__stream));

+ 7 - 4
libc/stdio/Makefile

@@ -35,9 +35,12 @@ ifeq ($(HAS_LONG_LONG),true)
 endif
 
 MSRC=stdio.c
-MOBJ=_stdio_init.o fputc.o fgetc.o fflush.o fgets.o gets.o fputs.o	\
-     puts.o fread.o fwrite.o fopen.o fclose.o fseek.o rewind.o ftell.o	\
-     setbuffer.o setvbuf.o ungetc.o _alloc_stdio_buffer.o _free_stdio_buffer.o
+MOBJ=_stdio_init.o _stdio_buffer.o  clearerr.o feof.o ferror.o fileno.o \
+     setbuffer.o setvbuf.o setbuf.o setlinebuf.o \
+     fclose.o _fopen.o fopen.o freopen.o fdopen.o fflush.o \
+     fseek.o rewind.o ftell.o fgetpos.o fsetpos.o \
+     fputc.o fgetc.o fgets.o gets.o fputs.o puts.o ungetc.o \
+     fread.o fwrite.o getchar.o putchar.o
 
 MSRC2=printf.c
 MOBJ2=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o snprintf.o \
@@ -46,7 +49,7 @@ MOBJ2=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o snprintf.o \
 MSRC3=scanf.c
 MOBJ3=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o
 
-CSRC=dputs.c popen.c perror.c remove.c getdelim.c getline.c tmpnam.c
+CSRC=popen.c perror.c remove.c getdelim.c getline.c tmpnam.c tmpnam_r.c
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 OBJS=$(MOBJ) $(MOBJ2) $(MOBJ3) $(COBJS)
 

+ 21 - 14
libc/stdio/perror.c

@@ -1,19 +1,26 @@
-#include <unistd.h>
-#include <string.h>
+#include <stdio.h>
 #include <errno.h>
 
-void perror(str)
-__const char *str;
-{
-	register char *ptr;
+/*
+ * Manuel Novoa III           Feb 2001
+ *
+ * Replaced old version that did write(2,...)'s with a version using
+ * stream functions.  If the program is calling perror, it's a safe
+ * bet that printf and friends are used as well.  It is also possible
+ * that the calling program could buffer stderr, or reassign it.
+ * Also, the old version did not conform the standards when the 
+ * passed char * was either NULL or pointed to an empty string.
+ */
 
-	if (str) {
-		write(2, str, strlen(str));
-		write(2, ": ", 2);
-	} else
-		write(2, "perror: ", 8);
+void perror(__const char *str)
+{
+	static const char perror_str[] = ": ";
+	const char *sep;
 
-	ptr = strerror(errno);
-	write(2, ptr, strlen(ptr));
-	write(2, "\n", 1);
+	sep = perror_str;
+	if (!(str && *str)) {		/* Caller did not supply a prefix message */
+		sep += 2;				/* or passed an empty string. */
+		str = sep;
+	}
+	fprintf(stderr, "%s%s%s\n", str, sep, strerror(errno));
 }

+ 28 - 13
libc/stdio/printf.c

@@ -119,6 +119,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <assert.h>
 
 #if WANT_GNU_ERRNO
 #include <errno.h>
@@ -242,7 +243,7 @@ int vprintf(const char *fmt, va_list ap)
 
 int vfprintf(FILE * op, register __const char *fmt, register va_list ap)
 {
-	return (vfnprintf(op, -1, fmt, ap));
+	return vfnprintf(op, -1, fmt, ap);
 }
 
 #endif
@@ -258,35 +259,49 @@ int vsprintf(char *sp, __const char *fmt, va_list ap)
 int vsnprintf(char *sp, size_t size, __const char *fmt, va_list ap)
 {
 	int rv;
-#if 0
-	FILE f = {0, 0, (char *) (unsigned) -1, 0, (char *) (unsigned) -1, -1,
-			  _IOFBF | __MODE_WRITE};
-#else
-	/* As we're only using the putc macro in vfnprintf, we don't need to
-	   initialize all FILE fields. */
 	FILE f;
 
-	f.bufwrite = (char *) (unsigned) -1;
+	/*
+	 * As we're only using the putc macro in vfnprintf, we don't need to
+	 * initialize all FILE f's fields.
+	 */
+	f.bufwrite = (char *) ((unsigned) -1);
 	f.bufpos = sp;
 	f.mode = _IOFBF | __MODE_WRITE;
-#endif
 
 	rv = vfnprintf(&f, size, fmt, ap);
-	if (size) {
-		*(f.bufpos) = 0;
+	if (size) {					/* If this is going to a buffer, */
+		*(f.bufpos) = 0;		/* don't forget to nul-terminate. */
 	}
 	return rv;
 }
 #endif
 
 #ifdef L_vdprintf
-#warning rewrite vdprintf ... fd may have an associated file!!! plus buffer?
+/*
+ * Note: If fd has an associated buffered FILE, bad things happen.
+ */
 extern int vdprintf(int fd, const char *fmt, va_list ap)
 {
+#if 0
 	FILE f = {f.unbuf, f.unbuf, f.unbuf, f.unbuf, f.unbuf + sizeof(f.unbuf),
-			  fd, _IONBF | __MODE_WRITE | __MODE_IOTRAN};
+			  fd, _IONBF | __MODE_WRITE};
+
+	assert(fd >= 0);			/* fd==0 may no longer be stdin */
 
 	return vfnprintf(&f, -1, fmt, ap);
+#else
+	char buf[BUFSIZ];
+	FILE f = {buf, buf, buf, buf, buf + sizeof(buf),
+			  fd, _IOFBF | __MODE_WRITE};
+	int rv;
+
+	assert(fd >= 0);			/* fd==0 may no longer be stdin */
+
+	rv = vfnprintf(&f, -1, fmt, ap);
+	fflush(&f);
+	return rv;
+#endif
 }
 #endif
 

+ 328 - 244
libc/stdio/stdio.c

@@ -25,25 +25,31 @@
 #include <malloc.h>
 #include <errno.h>
 #include <string.h>
+#include <assert.h>
 
-#undef STUB_FWRITE
-
-extern FILE *__IO_list;			/* For fflush at exit */
 
+#define FIXED_STREAMS 3
 #define FIXED_BUFFERS 2
+
 struct fixed_buffer {
 	unsigned char data[BUFSIZ];
 	unsigned char used;
 };
 
-extern void __init_stdio(void);
+extern FILE *__IO_list;			/* For fflush at exit */
+extern FILE _stdio_streams[FIXED_STREAMS];
 extern struct fixed_buffer _fixed_buffers[FIXED_BUFFERS];
 
+#if defined L__fopen || defined L_fclose || defined L_setvbuf
 extern unsigned char *_alloc_stdio_buffer(size_t size);
 extern void _free_stdio_buffer(unsigned char *buf);
+#endif
 
-#ifdef L__alloc_stdio_buffer
+#if defined L__fopen || defined L_fclose
+extern void _free_stdio_stream(FILE *fp);
+#endif
 
+#ifdef L__stdio_buffer
 unsigned char *_alloc_stdio_buffer(size_t size)
 {
 	if (size == BUFSIZ) {
@@ -57,9 +63,6 @@ unsigned char *_alloc_stdio_buffer(size_t size)
 	}
 	return malloc(size);
 }
-#endif
-
-#ifdef L__free_stdio_buffer
 
 void _free_stdio_buffer(unsigned char *buf)
 {
@@ -87,13 +90,20 @@ void _free_stdio_buffer(unsigned char *buf)
 
 struct fixed_buffer _fixed_buffers[FIXED_BUFFERS];
 
-FILE _stdio_streams[3] = {
+#if FIXED_STREAMS < 3
+#error FIXED_STREAMS must be >= 3
+#endif
+
+FILE _stdio_streams[FIXED_STREAMS] = {
 	{bufin, bufin, bufin, bufin, bufin + BUFSIZ,
-	 0, _IOFBF | __MODE_READ | __MODE_IOTRAN | __MODE_FREEBUF},
+	 0, _IOFBF | __MODE_READ | __MODE_FREEBUF,
+	 _stdio_streams + 1},
 	{bufout, bufout, bufout, bufout, bufout + BUFSIZ,
-	 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN | __MODE_FREEBUF},
+	 1, _IOFBF | __MODE_WRITE | __MODE_FREEBUF,
+	 _stdio_streams + 2},
 	{buferr, buferr, buferr, buferr, buferr + sizeof(buferr),
-	 2, _IONBF | __MODE_WRITE | __MODE_IOTRAN}
+	 2, _IONBF | __MODE_WRITE,
+	 0},
 };
 
 FILE *_stdin = _stdio_streams + 0;
@@ -102,10 +112,10 @@ FILE *_stderr = _stdio_streams + 2;
 
 /*
  * Note: the following forces linking of the __init_stdio function if
- * any of the stdio functions are used (except perror) since they all
- * call fflush directly or indirectly.
+ * any of the stdio functions are used since they all call fflush directly
+ * or indirectly.
  */
-FILE *__IO_list = 0;			/* For fflush at exit */
+FILE *__IO_list = _stdio_streams;			/* For fflush at exit */
 
 /* Call the stdio initiliser; it's main job it to call atexit */
 
@@ -113,33 +123,27 @@ void __stdio_close_all(void)
 {
 	FILE *fp;
 
-	fflush(stdout);
-	fflush(stderr);
 	for (fp = __IO_list; fp; fp = fp->next) {
 		fflush(fp);
 		close(fp->fd);
-		/* Note we're not de-allocating the memory */
-		/* There doesn't seem to be much point :-) */
-		fp->fd = -1;
 	}
 }
 
 void __init_stdio(void)
 {
-	static int stdio_initialized = 0;
-#if FIXED_BUFFERS > 2
+#if (FIXED_BUFFERS > 2) || (FIXED_STREAMS > 3)
 	int i;
 #endif
-
-	if (stdio_initialized!=0)
-	    return;
-	stdio_initialized++;
-
 #if FIXED_BUFFERS > 2
 	for ( i = 2 ; i < FIXED_BUFFERS ; i++ ) {
 		_fixed_buffers[i].used = 0;
 	}
 #endif
+#if FIXED_STREAMS > 3
+	for ( i = 3 ; i < FIXED_STREAMS ; i++ ) {
+		_stdio_streams[i].fd = -1;
+	}
+#endif
 
 	_fixed_buffers[0].used = 1;
 	_fixed_buffers[1].used = 1;
@@ -147,7 +151,9 @@ void __init_stdio(void)
 	if (isatty(1)) {
 		stdout->mode |= _IOLBF;
 	}
-	atexit(__stdio_close_all);
+
+	/* Cleanup is now taken care of in __uClibc_main. */
+	/* atexit(__stdio_close_all); */
 }
 #endif
 
@@ -158,8 +164,6 @@ FILE *fp;
 {
 	register int v;
 
-	 __init_stdio();
-
 	v = fp->mode;
 	/* If last op was a read ... */
 	if ((v & __MODE_READING) && fflush(fp))
@@ -169,12 +173,6 @@ FILE *fp;
 	if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE)
 		return EOF;
 
-	/* In MSDOS translation mode */
-#if __MODE_IOTRAN
-	if (ch == '\n' && (v & __MODE_IOTRAN) && fputc('\r', fp) == EOF)
-		return EOF;
-#endif
-
 	/* Buffer is full */
 	if (fp->bufpos >= fp->bufend && fflush(fp))
 		return EOF;
@@ -189,7 +187,7 @@ FILE *fp;
 		return EOF;
 
 	/* Can the macro handle this by itself ? */
-	if (v & (__MODE_IOTRAN | _IOLBF | _IONBF))
+	if (v & (_IOLBF | _IONBF))
 		fp->bufwrite = fp->bufstart;	/* Nope */
 	else
 		fp->bufwrite = fp->bufend;	/* Yup */
@@ -205,17 +203,13 @@ FILE *fp;
 {
 	int ch;
 
-	 __init_stdio();
-
 	if (fp->mode & __MODE_WRITING)
 		fflush(fp);
 
-	if ( (fp == stdin) && (stdout->fd != -1) && (stdout->mode & __MODE_WRITING) ) 
+	if ( (fp == stdin) && (stdout->fd != -1) 
+		 && (stdout->mode & __MODE_WRITING) ) 
 	    fflush(stdout);
 
-#if __MODE_IOTRAN
-  try_again:
-#endif
 	/* Can't read or there's been an EOF or error then return EOF */
 	if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) !=
 		__MODE_READ) return EOF;
@@ -232,12 +226,6 @@ FILE *fp;
 	}
 	ch = *(fp->bufpos++);
 
-#if __MODE_IOTRAN
-	/* In MSDOS translation mode; WARN: Doesn't work with UNIX macro */
-	if (ch == '\r' && (fp->mode & __MODE_IOTRAN))
-		goto try_again;
-#endif
-
 	return ch;
 }
 #endif
@@ -246,24 +234,17 @@ FILE *fp;
 int fflush(fp)
 FILE *fp;
 {
-	int len, cc, rv = 0;
+	int len, cc, rv;
 	char *bstart;
 
-	 __init_stdio();
-
+	rv = 0;
 	if (fp == NULL) {			/* On NULL flush the lot. */
-		if (fflush(stdin))
-			return EOF;
-		if (fflush(stdout))
-			return EOF;
-		if (fflush(stderr))
-			return EOF;
-
-		for (fp = __IO_list; fp; fp = fp->next)
-			if (fflush(fp))
-				return EOF;
-
-		return 0;
+		for (fp = __IO_list; fp; fp = fp->next) {
+			if (fflush(fp)) {
+				rv = EOF;
+			}
+		}
+		return rv;
 	}
 
 	/* If there's output data pending */
@@ -329,8 +310,6 @@ FILE *f;
 	register size_t i;
 	register int ch;
 
-	 __init_stdio();
-
 	ret = s;
 	for (i = count-1; i > 0; i--) {
 		ch = getc(f);
@@ -360,8 +339,6 @@ char *str;
 	register char *p = str;
 	register int c;
 
-	 __init_stdio();
-
 	while (((c = getc(stdin)) != EOF) && (c != '\n'))
 		*p++ = c;
 	*p = '\0';
@@ -376,8 +353,6 @@ FILE *fp;
 {
 	register int n = 0;
 
-	 __init_stdio();
-
 	while (*str) {
 		if (putc(*str++, fp) == EOF)
 			return (EOF);
@@ -393,8 +368,6 @@ const char *str;
 {
 	register int n;
 
-	 __init_stdio();
-
 	if (((n = fputs(str, stdout)) == EOF)
 		|| (putc('\n', stdout) == EOF))
 		return (EOF);
@@ -407,9 +380,6 @@ const char *str;
  * fread will often be used to read in large chunks of data calling read()
  * directly can be a big win in this case. Beware also fgetc calls this
  * function to fill the buffer.
- * 
- * This ignores __MODE__IOTRAN; probably exactly what you want. (It _is_ what
- * fgetc wants)
  */
 size_t fread(buf, size, nelm, fp)
 void *buf;
@@ -420,8 +390,6 @@ FILE *fp;
 	int len, v;
 	unsigned bytes, got = 0;
 
-	 __init_stdio();
-
 	v = fp->mode;
 
 	/* Want to do this to bring the file pointer up to date */
@@ -465,8 +433,6 @@ FILE *fp;
  * data; calling write() directly can be a big win in this case.
  * 
  * But first we check to see if there's space in the buffer.
- * 
- * Again this ignores __MODE__IOTRAN.
  */
 size_t fwrite(buf, size, nelm, fp)
 const void *buf;
@@ -478,21 +444,6 @@ FILE *fp;
 	int len;
 	unsigned bytes, put;
 
-	 __init_stdio();
-
-#ifdef STUB_FWRITE
-	bytes = size * nelm;
-	while (bytes > 0) {
-		len = write(fp->fd, buf, bytes);
-		if (len <= 0) {
-			break;
-		}
-		bytes -= len;
-		buf += len;
-	}
-	return nelm;
-#else
-
 	v = fp->mode;
 	/* If last op was a read ... */
 	if ((v & __MODE_READING) && fflush(fp))
@@ -543,7 +494,6 @@ FILE *fp;
 	}
 
 	return put / size;
-#endif
 }
 #endif
 
@@ -551,8 +501,6 @@ FILE *fp;
 void rewind(fp)
 FILE *fp;
 {
-	 __init_stdio();
-
 	fseek(fp, (long) 0, 0);
 	clearerr(fp);
 }
@@ -591,11 +539,9 @@ int ref;
 #endif
 
 	/* Use fflush to sync the pointers */
-
-	if (fflush(fp) == EOF)
-		return EOF;
-	if (lseek(fp->fd, offset, ref) < 0)
+	if (fflush(fp) || (lseek(fp->fd, offset, ref) < 0)) {
 		return EOF;
+	}
 	return 0;
 }
 #endif
@@ -610,7 +556,7 @@ FILE *fp;
 }
 #endif
 
-#ifdef L_fopen
+#ifdef L__fopen
 /*
  * This Fopen is all three of fopen, fdopen and freopen. The macros in
  * stdio.h show the other names.
@@ -621,19 +567,15 @@ int fd;
 FILE *fp;
 const char *mode;
 {
-	int open_mode = 0;
-
-#if __MODE_IOTRAN
-	int do_iosense = 1;
-#endif
-	int fopen_mode = 0;
-	FILE *nfp = 0;
+	FILE *nfp;
+	int open_mode;
+	int fopen_mode;
+	int i;
 
-	 __init_stdio();
+	fopen_mode = 0;
 
 	/* If we've got an fp close the old one (freopen) */
-	if (fp) {
-		/* Careful, don't de-allocate it */
+	if (fp) {					/* We don't want to deallocate fp. */
 		fopen_mode |=
 			(fp->mode & (__MODE_BUF | __MODE_FREEFIL | __MODE_FREEBUF));
 		fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF);
@@ -641,85 +583,73 @@ const char *mode;
 	}
 
 	/* decode the new open mode */
-	while (*mode)
-		switch (*mode++) {
-		case 'r':
+	switch (*mode++) {
+		case 'r':				/* read */
 			fopen_mode |= __MODE_READ;
+			open_mode = O_RDONLY;
 			break;
-		case 'w':
+		case 'w':				/* write (create or truncate)*/
 			fopen_mode |= __MODE_WRITE;
-			open_mode = (O_CREAT | O_TRUNC);
+			open_mode = (O_WRONLY | O_CREAT | O_TRUNC);
 			break;
-		case 'a':
+		case 'a':				/* write (create or append) */
 			fopen_mode |= __MODE_WRITE;
-			open_mode = (O_CREAT | O_APPEND);
-			break;
-		case '+':
-			fopen_mode |= __MODE_RDWR;
+			open_mode = (O_WRONLY | O_CREAT | O_APPEND);
 			break;
-#if __MODE_IOTRAN
-		case 'b':				/* Binary */
-			fopen_mode &= ~__MODE_IOTRAN;
-			do_iosense = 0;
-			break;
-		case 't':				/* Text */
-			fopen_mode |= __MODE_IOTRAN;
-			do_iosense = 0;
-			break;
-#endif
-		}
+		default:				/* illegal mode */
+			return 0;
+	}
 
-	/* Add in the read/write options to mode for open() */
-	switch (fopen_mode & (__MODE_READ | __MODE_WRITE)) {
-	case 0:
-		return 0;
-	case __MODE_READ:
-		open_mode |= O_RDONLY;
-		break;
-	case __MODE_WRITE:
-		open_mode |= O_WRONLY;
-		break;
-	default:
+	if ((*mode == 'b')) {		/* binary mode (nop for uClibc) */
+		++mode;
+	}
+
+	if (*mode == '+') {			/* read-write */
+		++mode;
+		fopen_mode |= __MODE_RDWR;
+		open_mode &= ~(O_RDONLY | O_WRONLY);
 		open_mode |= O_RDWR;
-		break;
 	}
 
-	/* Allocate the (FILE) before we do anything irreversable */
-	if (fp == 0) {
-		nfp = malloc(sizeof(FILE));
-		if (nfp == 0)
+	while (*mode) {				/* ignore everything else except ... */
+		if (*mode == 'x') {		/* open exclusive -- GNU extension */
+			open_mode |= O_EXCL;
+		}
+		++mode;
+	}
+
+	nfp = 0;
+	if (fp == 0) {				/* We need a FILE so allocate it before */
+		for (i = 0; i < FIXED_STREAMS; i++) { /* we potentially call open. */
+			if (_stdio_streams[i].fd == -1) {
+				nfp = _stdio_streams + i;
+				break;
+			}
+		}
+		if ((i == FIXED_STREAMS) && (!(nfp = malloc(sizeof(FILE))))) {
 			return 0;
+		}
 	}
 
-	/* Open the file itself */
-	if (fname)
+
+	if (fname) {				/* Open the file itself */
 		fd = open(fname, open_mode, 0666);
-	if (fd < 0) {				/* Grrrr */
-		if (nfp)
-			free(nfp);
+	}
+	if (fd < 0) {				/* Error from open or bad arg. */
+		if (nfp) {
+			_free_stdio_stream(nfp);
+		}
 		return 0;
 	}
 
-	/* If this isn't freopen create a (FILE) and buffer for it */
-	if (fp == 0) {
-		fp = nfp;
-		fp->next = __IO_list;
+	if (fp == 0) {				/* Not freopen so... */
+		fp = nfp;				/* use newly created FILE and */
+		fp->next = __IO_list;	/* add it to the list of open files. */
 		__IO_list = fp;
 
 		fp->mode = __MODE_FREEFIL;
-		if (isatty(fd)) {
-			fp->mode |= _IOLBF;
-#if __MODE_IOTRAN
-			if (do_iosense)
-				fopen_mode |= __MODE_IOTRAN;
-#endif
-		} else
-			fp->mode |= _IOFBF;
-
-		fp->bufstart = _alloc_stdio_buffer(BUFSIZ);
-
-		if (fp->bufstart == 0) {	/* Oops, no mem *//* Humm, full buffering with a two(!) byte
-									   * buffer. */
+		if (!(fp->bufstart = _alloc_stdio_buffer(BUFSIZ))) {
+			/* Allocation failed so use 8 byte buffer in FILE structure */
 			fp->bufstart = fp->unbuf;
 			fp->bufend = fp->unbuf + sizeof(fp->unbuf);
 		} else {
@@ -727,6 +657,13 @@ const char *mode;
 			fp->mode |= __MODE_FREEBUF;
 		}
 	}
+
+	if (isatty(fd)) {
+		fp->mode |= _IOLBF;
+	} else {					/* Note: the following should be optimized */
+		fp->mode |= _IOFBF;		/* away since we should have _IOFBF = 0. */
+	}
+
 	/* Ok, file's ready clear the buffer and save important bits */
 	fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
 	fp->mode |= fopen_mode;
@@ -739,119 +676,154 @@ const char *mode;
 int fclose(fp)
 FILE *fp;
 {
-	int rv = 0;
+	FILE *prev;
+	FILE *ptr;
+	int rv;
 
-	 __init_stdio();
+	assert(fp);					/* Shouldn't be NULL */
+	assert(fp->fd >= 0);		/* Need file descriptor in valid range. */
 
-	if (fp == 0) {
-		errno = EINVAL;
-		return EOF;
-	}
-	if (fflush(fp))
-		return EOF;
-
-	if (close(fp->fd))
+	rv = fflush(fp);
+	if (close(fp->fd)) {		/* Need to close even if fflush fails. */
 		rv = EOF;
-	fp->fd = -1;
+	}
 
 	if (fp->mode & __MODE_FREEBUF) {
 		_free_stdio_buffer(fp->bufstart);
-		fp->mode &= ~__MODE_FREEBUF;
-		fp->bufstart = fp->bufend = 0;
 	}
 
 	if (fp->mode & __MODE_FREEFIL) {
-		FILE *prev = 0, *ptr;
-
-		fp->mode = 0;
-
-		for (ptr = __IO_list; ptr && ptr != fp; ptr = ptr->next);
-		if (ptr == fp) {
-			if (prev == 0)
-				__IO_list = fp->next;
-			else
-				prev->next = fp->next;
+		prev = 0;
+		for (ptr = __IO_list; ptr ; ptr = ptr->next) {
+			if (ptr == fp) {
+				if (prev == 0) {
+					__IO_list = fp->next;
+				} else {
+					prev->next = fp->next;
+				}
+				_free_stdio_stream(fp);
+				break;
+			}
+			prev = ptr;
 		}
-		free(fp);
-	} else
-		fp->mode = 0;
+	}
 
 	return rv;
 }
-#endif
 
-#ifdef L_setbuffer
-void setbuffer(fp, buf, size)
-FILE *fp;
-char *buf;
-size_t size;
+/* The following is only called by fclose and _fopen (which calls fclose) */
+void _free_stdio_stream(FILE *fp)
 {
-	fflush(fp);
-
-	if ((fp->bufstart == (unsigned char *) buf)
-		&& (fp->bufend == ((unsigned char *) buf + size)))
-		return;
+	int i;
 
-	if (fp->mode & __MODE_FREEBUF) {
-		_free_stdio_buffer(fp->bufstart);
+	for (i = 0; i < FIXED_STREAMS; i++) {
+		if (fp == _stdio_streams + i) {
+			fp->fd = -1;
+			return;
+		}
 	}
-	fp->mode &= ~(__MODE_FREEBUF | __MODE_BUF);
+	free(fp);
+}
+#endif
 
-	if (buf == 0) {
-		fp->bufstart = fp->unbuf;
-		fp->bufend = fp->unbuf + sizeof(fp->unbuf);
-		fp->mode |= _IONBF;
-	} else {
-		fp->bufstart = buf;
-		fp->bufend = buf + size;
-		fp->mode |= _IOFBF;
+#ifdef L_setbuffer
+/*
+ * Rewritten   Feb 2001    Manuel Novoa III
+ *
+ * Just call setvbuf with appropriate args.
+ */
+void setbuffer(FILE *fp, char *buf, size_t size)
+{
+	int mode;
+
+	mode = _IOFBF;
+	if (!buf) {
+		mode = _IONBF;
 	}
-	fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+	setvbuf(fp, buf, mode, size);
 }
 #endif
 
 #ifdef L_setvbuf
-int setvbuf(fp, buf, mode, size)
-FILE *fp;
-char *buf;
-int mode;
-size_t size;
+/*
+ * Rewritten   Feb 2001    Manuel Novoa III
+ *
+ * Bugs in previous version:
+ *   No checking on mode arg.
+ *   If alloc of new buffer failed, some FILE fields not set correctly.
+ *   If requested buf is same size as current and buf is NULL, then
+ *      don't free current buffer; just use it.
+ */
+
+int setvbuf(FILE *fp, char *buf, int mode, size_t size)
 {
-	fflush(fp);
-	if (fp->mode & __MODE_FREEBUF) {
-		_free_stdio_buffer(fp->bufstart);
+	int allocated_buf_flag;
+
+	if (fflush(fp)) {			/* Standard requires no ops before setvbuf */
+		return EOF;				/* called.  We'll try to be more flexible. */
 	}
-	fp->mode &= ~(__MODE_FREEBUF | __MODE_BUF);
-	fp->bufstart = fp->unbuf;
-	fp->bufend = fp->unbuf + sizeof(fp->unbuf);
-	fp->mode |= _IONBF;
 
-	if (mode == _IOFBF || mode == _IOLBF) {
-		if (size <= 0) {
-			size = BUFSIZ;
-		}
-		if (buf == 0) {
-			buf = _alloc_stdio_buffer(size);
-			if (buf == 0)
-				return EOF;
+	if (mode & ~__MODE_BUF) {	/* Illegal mode. */
+		return EOF;
+	}
+
+	if ((mode == _IONBF) || (size <= sizeof(fp->unbuf))) {
+		size = sizeof(fp->unbuf); /* Either no buffering requested or */
+		buf = fp->unbuf;		/*     requested buffer size very small. */
+	}
+
+	fp->mode &= ~(__MODE_BUF);	/* Clear current mode */
+	fp->mode |= mode;			/*   and set new one. */
+
+	allocated_buf_flag = 0;
+	if ((!buf) && (size != (fp->bufend - fp->bufstart))) {
+		/* No buffer supplied and requested size different from current. */
+		allocated_buf_flag = __MODE_FREEBUF;
+		if (!(buf = _alloc_stdio_buffer(size))) {
+			return EOF;
 		}
+	}
 
+	if (buf && (buf != (char *) fp->bufstart)) { /* Want different buffer. */
+		if (fp->mode & __MODE_FREEBUF) {
+			_free_stdio_buffer(fp->bufstart);
+			fp->mode &= ~(__MODE_FREEBUF);
+		}
+		fp->mode |= allocated_buf_flag;
 		fp->bufstart = buf;
 		fp->bufend = buf + size;
-		fp->mode |= mode;
+		fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
 	}
-	fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+
 	return 0;
 }
 #endif
 
+#ifdef L_setbuf
+void setbuf(FILE *fp, char *buf)
+{
+	int mode;
+
+	mode = _IOFBF;
+	if (!buf) {
+		mode = _IONBF;
+	}
+	setvbuf(fp, buf, mode, BUFSIZ);
+}
+#endif
+
+#ifdef L_setlinebuf
+void setlinebuf(FILE *fp)
+{
+	setvbuf(fp, NULL, _IOLBF, BUFSIZ);
+}
+#endif
+
 #ifdef L_ungetc
 int ungetc(c, fp)
 int c;
 FILE *fp;
 {
-	 __init_stdio();
-
 	if (fp->mode & __MODE_WRITING)
 		fflush(fp);
 
@@ -870,3 +842,115 @@ FILE *fp;
 		return EOF;
 }
 #endif
+
+#ifdef L_fopen
+#undef fopen
+FILE *fopen(const char *__restrict filename,
+			const char *__restrict mode)
+{
+	return __fopen(filename, -1, NULL, mode);
+}
+#endif
+
+#ifdef L_freopen
+#undef freopen
+FILE *freopen(__const char *__restrict filename,
+			  __const char *__restrict mode, FILE *__restrict fp)
+{
+	return __fopen(filename, -1, fp, mode);
+}
+#endif
+
+#ifdef L_fdopen
+#undef fdopen
+FILE *fdopen(int fd, __const char *mode)
+{
+	return __fopen(NULL, fd, NULL, mode);
+}
+#endif
+
+#ifdef L_getchar
+#undef getchar
+int getchar(void)
+{
+	return getc(stdin);
+}
+#endif
+
+#ifdef L_putchar
+#undef putchar
+int putchar(int c)
+{
+	return putc(c, stdout);
+}
+#endif
+
+#ifdef L_clearerr
+#undef clearerr
+void clearerr(FILE *fp)
+{
+	assert(fp);
+
+	fp->mode &= ~(__MODE_EOF|__MODE_ERR);
+}
+#endif
+
+#ifdef L_feof
+#undef feof
+int feof(FILE *fp)
+{
+	assert(fp);
+
+  	return ((fp->mode & __MODE_EOF) != 0);
+}
+#endif
+
+#ifdef L_ferror
+#undef ferror
+int ferror(FILE *fp)
+{
+	assert(fp);
+
+	return ((fp->mode & __MODE_ERR) != 0);
+}
+#endif
+
+#ifdef L_fileno
+int fileno(FILE *fp)
+{
+	if (!fp || (fp->fd < 0)) {
+		return -1;
+	}
+	return fp->fd;
+}
+#endif
+
+#ifdef L_fgetpos
+int fgetpos(FILE *fp, fpos_t *pos)
+{
+	fpos_t p;
+
+	if (!pos) {					/* NULL pointer. */
+		errno = EINVAL;
+		return -1;
+	}
+
+	if ((p = ftell(fp)) < 0) {	/* ftell failed. */
+		return -1;				/* errno set by ftell. */
+	}
+
+	*pos = p;
+	return 0;
+}
+#endif
+
+#ifdef L_fsetpos
+int fsetpos(FILE *fp, __const fpos_t *pos)
+{
+	if (pos) {					/* Pointer ok. */
+		return fseek(fp, *pos, SEEK_SET);
+	}
+	errno = EINVAL;				/* NULL pointer. */
+	return EOF;
+}
+#endif