diff options
author | Manuel Novoa III <mjn3@codepoet.org> | 2001-02-19 00:28:09 +0000 |
---|---|---|
committer | Manuel Novoa III <mjn3@codepoet.org> | 2001-02-19 00:28:09 +0000 |
commit | d521275a86bb72f824dd76e6cb4e35d899f385da (patch) | |
tree | b156e1a492898f7294952d62f821d6227d1a5472 /libc/stdio/stdio.c | |
parent | dfe2d42547de8197f850f3ff0dfdc3caa4682518 (diff) |
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.
Diffstat (limited to 'libc/stdio/stdio.c')
-rw-r--r-- | libc/stdio/stdio.c | 572 |
1 files changed, 328 insertions, 244 deletions
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 |