OSDN Git Service

Lots of stdio cleanups. Several bug fixes, addition of a number of functions
authorManuel Novoa III <mjn3@codepoet.org>
Mon, 19 Feb 2001 00:28:09 +0000 (00:28 -0000)
committerManuel Novoa III <mjn3@codepoet.org>
Mon, 19 Feb 2001 00:28:09 +0000 (00:28 -0000)
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.

include/stdio.h
libc/stdio/Makefile
libc/stdio/perror.c
libc/stdio/printf.c
libc/stdio/stdio.c

index 5e39824..d98adea 100644 (file)
@@ -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));
index 50f3bd6..7c6b911 100644 (file)
@@ -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)
 
index d6274c0..04cd688 100644 (file)
@@ -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));
 }
index 898d0b9..f6ca8dd 100644 (file)
 #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
 
index e274b90..b3d514c 100644 (file)
 #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