diff options
author | Manuel Novoa III <mjn3@codepoet.org> | 2004-02-11 23:48:50 +0000 |
---|---|---|
committer | Manuel Novoa III <mjn3@codepoet.org> | 2004-02-11 23:48:50 +0000 |
commit | 082e680bd54e999f2bb4eb77141958938b1e9ee9 (patch) | |
tree | 203c45b85ca608e1550d8ffc459456fc9cf0b30b /libc/stdio/_stdio.h | |
parent | 17c21765b4a97c6f0b74ba8466073e5a3f97cdee (diff) |
New stdio core. Should be more maintainable. Fixes a couple of bugs.
Codepaths streamlined. Improved performance for nonthreaded apps
when linked with a thread-enabled libc.
Minor iconv bug and some locale/thread related startup issues fixed.
These showed up in getting a gcj-compiled java helloworld app running.
Removed some old extension functions... _stdio_fdout and _stdio_fsfopen.
Diffstat (limited to 'libc/stdio/_stdio.h')
-rw-r--r-- | libc/stdio/_stdio.h | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/libc/stdio/_stdio.h b/libc/stdio/_stdio.h new file mode 100644 index 000000000..aedcc526a --- /dev/null +++ b/libc/stdio/_stdio.h @@ -0,0 +1,436 @@ +/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> + * + * GNU Library General Public License (LGPL) version 2 or later. + * + * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. + */ + +#define _GNU_SOURCE + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef __UCLIBC_HAS_WCHAR__ +#include <wchar.h> +#endif + +#ifdef __UCLIBC_HAS_THREADS__ +#include <pthread.h> + +#define __STDIO_THREADLOCK_OPENLIST \ + __pthread_mutex_lock(&_stdio_openlist_lock) + +#define __STDIO_THREADUNLOCK_OPENLIST \ + __pthread_mutex_unlock(&_stdio_openlist_lock) + +#define __STDIO_THREADTRYLOCK_OPENLIST \ + __pthread_mutex_trylock(&_stdio_openlist_lock) + +#else + +#define __STDIO_THREADLOCK_OPENLIST ((void)0) +#define __STDIO_THREADUNLOCK_OPENLIST ((void)0) + +#endif + +#define __UNDEFINED_OR_NONPORTABLE ((void)0) + +/**********************************************************************/ +#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ + +extern __ssize_t _cs_read(void *cookie, char *buf, size_t bufsize); +extern __ssize_t _cs_write(void *cookie, const char *buf, size_t bufsize); +extern int _cs_seek(void *cookie, __offmax_t *pos, int whence); +extern int _cs_close(void *cookie); + +#define __STDIO_STREAM_RESET_GCS(S) \ + (S)->__cookie = &((S)->__filedes); \ + (S)->__gcs.read = _cs_read; \ + (S)->__gcs.write = _cs_write; \ + (S)->__gcs.seek = _cs_seek; \ + (S)->__gcs.close = _cs_close + + +#define __READ(STREAMPTR,BUF,SIZE) \ + ((((STREAMPTR)->__gcs.read) == NULL) ? -1 : \ + (((STREAMPTR)->__gcs.read)((STREAMPTR)->__cookie,(BUF),(SIZE)))) +#define __WRITE(STREAMPTR,BUF,SIZE) \ + ((((STREAMPTR)->__gcs.write) == NULL) ? -1 : \ + (((STREAMPTR)->__gcs.write)((STREAMPTR)->__cookie,(BUF),(SIZE)))) +#define __SEEK(STREAMPTR,PPOS,WHENCE) \ + ((((STREAMPTR)->__gcs.seek) == NULL) ? -1 : \ + (((STREAMPTR)->__gcs.seek)((STREAMPTR)->__cookie,(PPOS),(WHENCE)))) +#define __CLOSE(STREAMPTR) \ + ((((STREAMPTR)->__gcs.close) == NULL) ? 0 : \ + (((STREAMPTR)->__gcs.close)((STREAMPTR)->__cookie))) + +#else /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */ + +#define __STDIO_STREAM_RESET_GCS(S) ((void)0) + +#define __READ(STREAMPTR,BUF,SIZE) \ + (read((STREAMPTR)->__filedes,(BUF),(SIZE))) +#define __WRITE(STREAMPTR,BUF,SIZE) \ + (write((STREAMPTR)->__filedes,(BUF),(SIZE))) +#define __SEEK(STREAMPTR,PPOS,WHENCE) \ + (__stdio_seek((STREAMPTR),(PPOS),(WHENCE))) +#define __CLOSE(STREAMPTR) \ + (close((STREAMPTR)->__filedes)) + +#endif /* __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */ + +/**********************************************************************/ +#ifdef __UCLIBC_HAS_WCHAR__ + +#define __STDIO_STREAM_TRANS_TO_WRITE(S,O) __stdio_trans2w_o((S), (O)) +#define __STDIO_STREAM_TRANS_TO_READ(S,O) __stdio_trans2r_o((S), (O)) + +#else + +#define __STDIO_STREAM_TRANS_TO_WRITE(S,O) __stdio_trans2w((S)) +#define __STDIO_STREAM_TRANS_TO_READ(S,O) __stdio_trans2r((S)) + +#endif +/**********************************************************************/ + +#define __STDIO_STREAM_IS_READING(S) ((S)->__modeflags & __MASK_READING) +#define __STDIO_STREAM_IS_WRITING(S) ((S)->__modeflags & __FLAG_WRITING) + +#define __STDIO_STREAM_SET_READING(S) ((S)->__modeflags |= __FLAG_READING) +#define __STDIO_STREAM_SET_WRITING(S) ((S)->__modeflags |= __FLAG_WRITING) + +#define __STDIO_STREAM_IS_READING_OR_READONLY(S) \ + ((S)->__modeflags & (__MASK_READING|__FLAG_READONLY)) + +#define __STDIO_STREAM_IS_WRITING_OR_WRITEONLY(S) \ + ((S)->__modeflags & (__FLAG_WRITING|__FLAG_WRITEONLY)) + +#define __STDIO_STREAM_IS_READONLY(S) ((S)->__modeflags & __FLAG_READONLY) +#define __STDIO_STREAM_IS_WRITEONLY(S) ((S)->__modeflags & __FLAG_WRITEONLY) + + +/**********************************************************************/ +#ifdef __UCLIBC_HAS_WCHAR__ + +#define __STDIO_STREAM_IS_NARROW_WRITING(S) \ + (((S)->__modeflags & (__FLAG_WRITING|__FLAG_NARROW)) \ + == (__FLAG_WRITING|__FLAG_NARROW)) + +#define __STDIO_STREAM_IS_WIDE_WRITING(S) \ + (((S)->__modeflags & (__FLAG_WRITING|__FLAG_WIDE)) \ + == (__FLAG_WRITING|__FLAG_WIDE)) + +#if (__FLAG_NARROW <= __MASK_READING) +#error assumption violated regarding __FLAG_NARROW +#endif + +#define __STDIO_STREAM_IS_NARROW_READING(S) \ + (((S)->__modeflags & (__MASK_READING|__FLAG_NARROW)) > __FLAG_NARROW) + +#define __STDIO_STREAM_IS_WIDE_READING(S) \ + (((S)->__modeflags & (__MASK_READING|__FLAG_WIDE)) > __FLAG_WIDE) + +#define __STDIO_STREAM_IS_NARROW(S) ((S)->__modeflags & __FLAG_NARROW) +#define __STDIO_STREAM_IS_WIDE(S) ((S)->__modeflags & __FLAG_WIDE) + +#define __STDIO_STREAM_SET_NARROW(S) \ + ((void)((S)->__modeflags |= __FLAG_NARROW)) +#define __STDIO_STREAM_SET_WIDE(S) \ + ((void)((S)->__modeflags |= __FLAG_WIDE)) + +#else + +#define __STDIO_STREAM_IS_NARROW_WRITING(S) __STDIO_STREAM_IS_WRITING(S) + +#define __STDIO_STREAM_IS_NARROW_READING(S) __STDIO_STREAM_IS_READING(S) + +#define __STDIO_STREAM_IS_NARROW(S) (1) +#define __STDIO_STREAM_IS_WIDE(S) (0) + +#define __STDIO_STREAM_SET_NARROW(S) ((void)0) +#define __STDIO_STREAM_SET_WIDE(S) ((void)0) + +#endif +/**********************************************************************/ + +#define __STDIO_STREAM_SET_EOF(S) \ + ((void)((S)->__modeflags |= __FLAG_EOF)) +#define __STDIO_STREAM_SET_ERROR(S) \ + ((void)((S)->__modeflags |= __FLAG_ERROR)) + +#define __STDIO_STREAM_CLEAR_EOF(S) \ + ((void)((S)->__modeflags &= ~__FLAG_EOF)) +#define __STDIO_STREAM_CLEAR_ERROR(S) \ + ((void)((S)->__modeflags &= ~__FLAG_ERROR)) + +#define __STDIO_STREAM_CLEAR_READING_AND_UNGOTS(S) \ + ((void)((S)->__modeflags &= ~__MASK_READING)) +#define __STDIO_STREAM_CLEAR_WRITING(S) \ + ((void)((S)->__modeflags &= ~__FLAG_WRITING)) + +#ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ +# define __STDIO_STREAM_DISABLE_GETC(S) \ + ((void)((S)->__bufgetc_u = (S)->__bufstart)) +# define __STDIO_STREAM_ENABLE_GETC(S) \ + ((void)((S)->__bufgetc_u = (S)->__bufread)) +# define __STDIO_STREAM_CAN_USE_BUFFER_GET(S) \ + ((S)->__bufpos < (S)->__bufgetc_u) +#else +# define __STDIO_STREAM_DISABLE_GETC(S) ((void)0) +# define __STDIO_STREAM_ENABLE_GETC(S) ((void)0) +# define __STDIO_STREAM_CAN_USE_BUFFER_GET(S) (0) +#endif + +#ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ +# define __STDIO_STREAM_DISABLE_PUTC(S) \ + ((void)((S)->__bufputc_u = (S)->__bufstart)) +# define __STDIO_STREAM_ENABLE_PUTC(S) \ + ((void)((S)->__bufputc_u = (S)->__bufend)) +# define __STDIO_STREAM_CAN_USE_BUFFER_ADD(S) \ + ((S)->__bufpos < (S)->__bufputc_u) +#else +# define __STDIO_STREAM_DISABLE_PUTC(S) ((void)0) +# define __STDIO_STREAM_ENABLE_PUTC(S) ((void)0) +# define __STDIO_STREAM_CAN_USE_BUFFER_ADD(S) (0) +#endif + +#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ +#define __STDIO_STREAM_IS_CUSTOM(S) ((S)->__cookie != &((S)->__filedes)) +#else +#define __STDIO_STREAM_IS_CUSTOM(S) (0) +#endif + +/**********************************************************************/ + +#ifdef __STDIO_BUFFERS +#define __STDIO_STREAM_FREE_BUFFER(S) \ + do { if ((S)->__modeflags & __FLAG_FREEBUF) free((S)->__bufstart); } while (0) +#else +#define __STDIO_STREAM_FREE_BUFFER(S) ((void)0) +#endif + +#define __STDIO_STREAM_FREE_FILE(S) \ + do { if ((S)->__modeflags & __FLAG_FREEFILE) free((S)); } while (0) + + +#ifdef __UCLIBC_HAS_LFS__ +#define __STDIO_WHEN_LFS(E) E +#else +#define __STDIO_WHEN_LFS(E) ((void)0) +#endif + +/**********************************************************************/ +/* The following return 0 on success. */ + +#ifdef __STDIO_BUFFERS +/* Assume stream in valid writing state. Do not reset writing flag + * or disble putc macro unless error. */ +/* Should we assume that buffer is not empty to avoid a check? */ +extern size_t __stdio_wcommit(FILE *__restrict stream); + +/* Remember to fail if at EOF! */ +extern size_t __stdio_rfill(FILE *__restrict stream); + +extern size_t __stdio_fwrite(const unsigned char *__restrict buffer, + size_t bytes, FILE *__restrict stream); +#else + +#define __stdio_fwrite(B,N,S) __stdio_WRITE((S),(B),(N)) + +#endif + +extern size_t __stdio_WRITE(FILE *stream, const unsigned char *buf, + size_t bufsize); +extern size_t __stdio_READ(FILE *stream, unsigned char *buf, size_t bufsize); + +extern int __stdio_trans2r(FILE *__restrict stream); +extern int __stdio_trans2w(FILE *__restrict stream); + +extern int __stdio_trans2r_o(FILE *__restrict stream, int oflag); +extern int __stdio_trans2w_o(FILE *__restrict stream, int oflag); + +/**********************************************************************/ +#ifdef __STDIO_BUFFERS + +#define __STDIO_STREAM_IS_FBF(S) (!((S)->__modeflags & __MASK_BUFMODE)) +#define __STDIO_STREAM_IS_LBF(S) ((S)->__modeflags & __FLAG_LBF) +#define __STDIO_STREAM_IS_NBF(S) ((S)->__modeflags & __FLAG_NBF) + +#define __STDIO_STREAM_BUFFER_SIZE(S) ((S)->__bufend - (S)->__bufstart) + +/* Valid when writing... */ +#define __STDIO_STREAM_BUFFER_ADD(S,C) (*(S)->__bufpos++ = (C)) +#define __STDIO_STREAM_BUFFER_UNADD(S) (--(S)->__bufpos) +#define __STDIO_STREAM_BUFFER_WAVAIL(S) ((S)->__bufend - (S)->__bufpos) +#define __STDIO_STREAM_BUFFER_WUSED(S) ((S)->__bufpos - (S)->__bufstart) +#define __STDIO_COMMIT_WRITE_BUFFER(S) __stdio_wcommit((S)) +#ifdef __UCLIBC_HAS_WCHAR__ +#define __STDIO_STREAM_IS_NARROW_FBF(S) \ + (!((S)->__modeflags & (__MASK_BUFMODE|__FLAG_WIDE))) +#else +#define __STDIO_STREAM_IS_NARROW_FBF(S) __STDIO_STREAM_IS_FBF((S)) +#endif + +/* Valid when reading... */ +#define __STDIO_STREAM_BUFFER_RAVAIL(S) ((S)->__bufread - (S)->__bufpos) +#define __STDIO_STREAM_BUFFER_GET(S) (*(S)->__bufpos++) +#define __STDIO_FILL_READ_BUFFER(S) __stdio_rfill((S)) + +#define __STDIO_STREAM_INIT_BUFREAD_BUFPOS(S) \ + (S)->__bufread = (S)->__bufpos = (S)->__bufstart + + +#define __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES (-2) +#define __STDIO_STREAM_FAKE_VSSCANF_FILEDES (-2) +#define __STDIO_STREAM_FAKE_VSWPRINTF_FILEDES (-3) +#define __STDIO_STREAM_FAKE_VSWSCANF_FILEDES (-3) + +#define __STDIO_STREAM_IS_FAKE_VSNPRINTF(S) \ + ((S)->__filedes == __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES) +#define __STDIO_STREAM_IS_FAKE_VSSCANF(S) \ + ((S)->__filedes == __STDIO_STREAM_FAKE_VSSCANF_FILEDES) +#define __STDIO_STREAM_IS_FAKE_VSWPRINTF(S) \ + ((S)->__filedes == __STDIO_STREAM_FAKE_VSWPRINTF_FILEDES) +#define __STDIO_STREAM_IS_FAKE_VSWSCANF(S) \ + ((S)->__filedes == __STDIO_STREAM_FAKE_VSWSCANF_FILEDES) + +#else /* __STDIO_BUFFERS */ + +#define __STDIO_STREAM_IS_FBF(S) (0) +#define __STDIO_STREAM_IS_LBF(S) (0) +#define __STDIO_STREAM_IS_NBF(S) (1) + +#define __STDIO_STREAM_BUFFER_SIZE(S) (0) +#define __STDIO_STREAM_BUFFER_ADD(S,C) ((void)0) +#define __STDIO_STREAM_BUFFER_UNADD(S) ((void)0) +#define __STDIO_STREAM_BUFFER_WAVAIL(S) (0) +#define __STDIO_STREAM_BUFFER_WUSED(S) (0) +#define __STDIO_COMMIT_WRITE_BUFFER(S) (0) +#define __STDIO_STREAM_IS_NARROW_FBF(S) (0) + +#define __STDIO_STREAM_BUFFER_RAVAIL(S) (0) +#define __STDIO_STREAM_BUFFER_GET(S) (EOF) +#define __STDIO_FILL_READ_BUFFER(S) (0) +#define __STDIO_STREAM_INIT_BUFREAD_BUFPOS(S) ((void)0) + +#undef __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES +#undef __STDIO_STREAM_FAKE_VSSCANF_FILEDES +#undef __STDIO_STREAM_FAKE_VSWPRINTF_FILEDES + +#define __STDIO_STREAM_IS_FAKE_VSNPRINTF(S) (0) +#define __STDIO_STREAM_IS_FAKE_VSSCANF(S) (0) +#undef __STDIO_STREAM_IS_FAKE_VSWPRINTF + +# ifdef __USE_OLD_VFPRINTF__ +# define __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES_NB (-2) +# define __STDIO_STREAM_IS_FAKE_VSNPRINTF_NB(S) \ + ((S)->__filedes == __STDIO_STREAM_FAKE_VSNPRINTF_FILEDES_NB) +# endif + +# ifndef __UCLIBC_HAS_WCHAR__ +# define __STDIO_STREAM_FAKE_VSSCANF_FILEDES_NB (-2) +# define __STDIO_STREAM_IS_FAKE_VSSCANF_NB(S) \ + ((S)->__filedes == __STDIO_STREAM_FAKE_VSSCANF_FILEDES_NB) +# endif + +#endif /* __STDIO_BUFFERS */ +/**********************************************************************/ + +extern int __fputs_unlocked(const char *__restrict s, FILE *__restrict stream); + +extern int __putchar_unlocked(int c); + + +extern size_t __fwrite_unlocked(const void *__restrict ptr, size_t size, + size_t nmemb, FILE *__restrict stream); + +extern size_t __fread_unlocked(void *__restrict ptr, size_t size, + size_t nmemb, FILE *__restrict stream); + +extern int __fputc_unlocked(int c, FILE *stream); + +extern int __fflush_unlocked(FILE *stream); + +extern int __stdio_adjust_position(FILE *__restrict stream, __offmax_t *pos); + +extern void __clearerr_unlocked(FILE *stream); +extern int __feof_unlocked(FILE *stream); +extern int __ferror_unlocked(FILE *stream); + +extern int __fgetc_unlocked(FILE *stream); +extern char *__fgets_unlocked(char *__restrict s, int n, + FILE * __restrict stream); + +extern int __fileno_unlocked(FILE *stream); + +extern int __getchar_unlocked(void); + +#ifdef __UCLIBC_HAS_LFS__ +extern int __fseeko64(FILE *stream, __off64_t offset, int whence); +extern __off64_t __ftello64(FILE *stream); +#endif + +#ifdef __STDIO_HAS_OPENLIST + /* Uses an implementation hack!!! */ +#define __STDIO_FLUSH_LBF_STREAMS __fflush_unlocked((FILE *) &_stdio_openlist) +#else +#define __STDIO_FLUSH_LBF_STREAMS ((void)0) +#endif + +#ifdef NDEBUG +#define __STDIO_STREAM_VALIDATE(S) ((void)0) +#else +extern void _stdio_validate_FILE(const FILE *stream); +#define __STDIO_STREAM_VALIDATE(S) _stdio_validate_FILE((S)) +#endif + +#ifdef __STDIO_MBSTATE +#define __COPY_MBSTATE(dest,src) \ + ((void)((dest)->__mask = (src)->__mask, (dest)->__wc = (src)->__wc)) +#define __INIT_MBSTATE(dest) ((void)((dest)->__mask = 0)) +#else +#define __COPY_MBSTATE(dest,src) ((void)0) +#define __INIT_MBSTATE(dest) ((void)0) +#endif + +/**********************************************************************/ + +extern int _stdio_adjpos(FILE *__restrict stream, __offmax_t * pos); +extern int _stdio_lseek(FILE *stream, __offmax_t *pos, int whence); + +extern size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, + FILE *stream); +extern size_t _stdio_fread(unsigned char *buffer, size_t bytes, + FILE *stream); + +extern FILE *_stdio_fopen(intptr_t fname_or_mode, + const char *__restrict mode, + FILE *__restrict stream, int filedes); + +#ifdef __UCLIBC_HAS_WCHAR__ +extern size_t _wstdio_fwrite(const wchar_t *__restrict ws, size_t n, + FILE *__restrict stream); + +extern wint_t __fgetwc_unlocked(register FILE *stream); +extern wint_t __fputwc_unlocked(wchar_t wc, FILE *stream); +#endif + +/**********************************************************************/ +/* Only use the macro below if you know fp is a valid FILE for a valid fd. + * This is _not_ true for custom streams! */ +#define __FILENO_UNLOCKED(fp) ((fp)->__filedes) + +#define __FEOF_OR_FERROR_UNLOCKED(stream) \ + ((stream)->__modeflags & (__FLAG_EOF|__FLAG_ERROR)) + +#if defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__) +#define __STDIO_HAS_VSNPRINTF 1 +#endif |