summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/stdio.h70
-rw-r--r--libc/stdio/Makefile11
-rw-r--r--libc/stdio/perror.c35
-rw-r--r--libc/stdio/printf.c41
-rw-r--r--libc/stdio/stdio.c572
5 files changed, 422 insertions, 307 deletions
diff --git a/include/stdio.h b/include/stdio.h
index 5e3982416..d98adea15 100644
--- a/include/stdio.h
+++ b/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));
diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile
index 50f3bd602..7c6b9116a 100644
--- a/libc/stdio/Makefile
+++ b/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)
diff --git a/libc/stdio/perror.c b/libc/stdio/perror.c
index d6274c056..04cd688d8 100644
--- a/libc/stdio/perror.c
+++ b/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));
}
diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c
index 898d0b94e..f6ca8dda4 100644
--- a/libc/stdio/printf.c
+++ b/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
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index e274b9018..b3d514c35 100644
--- a/libc/stdio/stdio.c
+++ b/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