From d521275a86bb72f824dd76e6cb4e35d899f385da Mon Sep 17 00:00:00 2001 From: Manuel Novoa III Date: Mon, 19 Feb 2001 00:28:09 +0000 Subject: 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. --- include/stdio.h | 70 ++++--- libc/stdio/Makefile | 11 +- libc/stdio/perror.c | 35 ++-- libc/stdio/printf.c | 41 ++-- libc/stdio/stdio.c | 572 ++++++++++++++++++++++++++++++---------------------- 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 -#include +#include #include -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 #include #include +#include #if WANT_GNU_ERRNO #include @@ -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 #include #include +#include -#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 -- cgit v1.2.3