From 082e680bd54e999f2bb4eb77141958938b1e9ee9 Mon Sep 17 00:00:00 2001 From: Manuel Novoa III Date: Wed, 11 Feb 2004 23:48:50 +0000 Subject: 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. --- libc/sysdeps/linux/common/bits/uClibc_stdio.h | 716 ++++++++++++-------------- 1 file changed, 325 insertions(+), 391 deletions(-) (limited to 'libc/sysdeps/linux/common/bits/uClibc_stdio.h') diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index 904681631..621cacaba 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -30,93 +30,50 @@ #endif /**********************************************************************/ -#ifdef __UCLIBC__ - -#ifdef __UCLIBC_HAS_THREADS__ -#define __STDIO_THREADSAFE -#endif - -#ifdef __UCLIBC_HAS_LFS__ -#define __STDIO_LARGE_FILES -#endif /* __UCLIBC_HAS_LFS__ */ - -#ifdef __UCLIBC_HAS_WCHAR__ -#define __STDIO_WIDE -#endif #define __STDIO_BUFFERS /* ANSI/ISO mandate at least 256. */ #if defined(__UCLIBC_HAS_STDIO_BUFSIZ_NONE__) /* Fake this because some apps use stdio.h BUFSIZ. */ -#define _STDIO_BUFSIZ 256 +#define __STDIO_BUFSIZ 256 #undef __STDIO_BUFFERS #elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_256__) -#define _STDIO_BUFSIZ 256 +#define __STDIO_BUFSIZ 256 #elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_512__) -#define _STDIO_BUFSIZ 512 +#define __STDIO_BUFSIZ 512 #elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_1024__) -#define _STDIO_BUFSIZ 1024 +#define __STDIO_BUFSIZ 1024 #elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_2048__) -#define _STDIO_BUFSIZ 2048 +#define __STDIO_BUFSIZ 2048 #elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_4096__) -#define _STDIO_BUFSIZ 4096 +#define __STDIO_BUFSIZ 4096 #elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_8192__) -#define _STDIO_BUFSIZ 8192 +#define __STDIO_BUFSIZ 8192 #else #error config seems to be out of sync regarding bufsiz options #endif -#ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ -#define __STDIO_GETC_MACRO -#endif - -#ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ -#define __STDIO_PUTC_MACRO -#endif - -#ifdef __UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION__ -#define __STDIO_AUTO_RW_TRANSITION -#endif - -#ifdef __UCLIBC_HAS_FOPEN_LARGEFILE_MODE__ -#define __STDIO_FOPEN_LARGEFILE_MODE -#endif - -#ifdef __UCLIBC_HAS_FOPEN_LARGEFILE_MODE__ -#define __STDIO_FOPEN_EXCLUSIVE_MODE -#endif - -#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__ -#define __STDIO_PRINTF_M_SUPPORT -#endif - -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ -#define __STDIO_GLIBC_CUSTOM_STREAMS -#endif - #ifdef __UCLIBC_HAS_STDIO_BUFSIZ_NONE__ -#define _STDIO_BUILTIN_BUF_SIZE 0 +#define __STDIO_BUILTIN_BUF_SIZE 0 #else /* __UCLIBC_HAS_STDIO_BUFSIZ_NONE__ */ #if defined(__UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE__) -#define _STDIO_BUILTIN_BUF_SIZE 0 +#define __STDIO_BUILTIN_BUF_SIZE 0 #elif defined(__UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4__) -#define _STDIO_BUILTIN_BUF_SIZE 4 +#define __STDIO_BUILTIN_BUF_SIZE 4 #elif defined(__UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8__) -#define _STDIO_BUILTIN_BUF_SIZE 8 +#define __STDIO_BUILTIN_BUF_SIZE 8 #else #error config seems to be out of sync regarding builtin buffer size #endif -#endif /* __UCLIBC_HAS_STDIO_BUFSIZ_NONE__ */ - -#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__ -#define __STDIO_GLIBC_CUSTOM_PRINTF #endif +#if defined(__STDIO_BUFFERS) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__) || defined(__UCLIBC_HAS_THREADS__) +#define __STDIO_HAS_OPENLIST 1 +#else +#undef __STDIO_HAS_OPENLIST +#endif -/* Currently unimplemented/untested */ -/* #define __STDIO_FLEXIBLE_SETVBUF */ - - +/**********************************************************************/ /* Make sure defines related to large files are consistent. */ #ifdef _LIBC @@ -124,62 +81,44 @@ #undef __USE_LARGEFILE #undef __USE_LARGEFILE64 #undef __USE_FILE_OFFSET64 -/* if we're actually building uClibc with large file support, only define... */ +/* If we're actually building uClibc with large file support, only define... */ #define __USE_LARGEFILE64 1 #endif /* __UCLIBC_HAS_LFS__ */ #else /* not _LIBC */ #ifndef __UCLIBC_HAS_LFS__ -#if defined(__LARGEFILE64_SOURCE) || defined(__USE_LARGEFILE64) \ - || defined(__USE_FILE_OFFSET64) +#if defined(__LARGEFILE64_SOURCE) || defined(__USE_LARGEFILE64) || defined(__USE_FILE_OFFSET64) #error Sorry... uClibc was built without large file support! #endif #endif /* __UCLIBC_HAS_LFS__ */ #endif /* _LIBC */ - -#endif /* __UCLIBC__ */ /**********************************************************************/ -/* These are the stdio configuration options. Keep them here until - uClibc's configuration process gets reworked. */ +#ifdef __UCLIBC_HAS_WCHAR__ -#ifdef __STDIO_WIDE #define __need_wchar_t #include + /* Note: we don't really need mbstate for 8-bit locales. We do for UTF-8. * For now, always use it. */ #define __STDIO_MBSTATE #define __need_mbstate_t #include -#endif - -/* For uClibc, these are currently handled above. */ -/* #define __STDIO_BUFFERS */ -/* #define __STDIO_GETC_MACRO */ -/* #define __STDIO_PUTC_MACRO */ -/* #define __STDIO_LARGE_FILES */ -/* #define __STDIO_THREADSAFE */ -/* ANSI/ISO mandate at least 256. */ -/* #define _STDIO_BUFSIZ 256 */ -/* #define __STDIO_AUTO_RW_TRANSITION */ -/* #define __STDIO_FOPEN_EXCLUSIVE_MODE */ -/* #define __STDIO_PRINTF_M_SPEC */ -/* #define __STDIO_GLIBC_CUSTOM_STREAMS */ -/* L mode extension for fopen. */ -/* #define __STDIO_FOPEN_LARGEFILE_MODE */ -/* size of builtin buf -- only tested with 0 */ -/* #define _STDIO_BUILTIN_BUF_SIZE 0 */ +#endif +/**********************************************************************/ /* Currently unimplemented/untested */ /* #define __STDIO_FLEXIBLE_SETVBUF */ -/**********************************************************************/ -/* TODO -- posix or gnu -- belongs in limits.h and >= 9 for sus */ -/* NOTE: for us it is currently _always_ 9 */ -/*#define NL_ARGMAX 9*/ +#ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ +#define __STDIO_GETC_MACRO +#endif + +#ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ +#define __STDIO_PUTC_MACRO +#endif -/**********************************************************************/ /* These are consistency checks on the different options */ @@ -189,413 +128,408 @@ #endif #ifdef __BCC__ -#undef __STDIO_LARGE_FILES +#undef __UCLIBC_HAS_LFS__ #endif -#ifndef __STDIO_LARGE_FILES -#undef __STDIO_FOPEN_LARGEFILE_MODE +#ifndef __UCLIBC_HAS_LFS__ +#undef __UCLIBC_HAS_FOPEN_LARGEFILE_MODE__ #endif /**********************************************************************/ - -#ifdef __STDIO_THREADSAFE +#ifdef __UCLIBC_HAS_THREADS__ /* Need this for pthread_mutex_t. */ #include -#define __STDIO_THREADLOCK(STREAM) \ - if ((STREAM)->user_locking == 0) { \ - __pthread_mutex_lock(&(STREAM)->lock); \ - } +/* user_locking + * 0 : do auto locking/unlocking + * 1 : user does locking/unlocking + * 2 : initial state prior to thread initialization + * with no auto locking/unlocking + * + * When threading is initialized, walk the stdio open stream list + * and do "if (user_locking == 2) user_locking = 0;". + * + * This way, we avoid calling the weak lock/unlock functions. + */ -#define __STDIO_THREADUNLOCK(STREAM) \ - if ((STREAM)->user_locking == 0) { \ - __pthread_mutex_unlock(&(STREAM)->lock); \ +#define __STDIO_AUTO_THREADLOCK_VAR int __infunc_user_locking + +#define __STDIO_AUTO_THREADLOCK(__stream) \ + if ((__infunc_user_locking = (__stream)->__user_locking) == 0) { \ + __pthread_mutex_lock(&(__stream)->__lock); \ } -#define __STDIO_THREADTRYLOCK(STREAM) \ - if ((STREAM)->user_locking == 0) { \ - __pthread_mutex_trylock(&(STREAM)->lock); \ +#define __STDIO_AUTO_THREADUNLOCK(__stream) \ + if (__infunc_user_locking == 0) { \ + __pthread_mutex_unlock(&(__stream)->__lock); \ } -#define __STDIO_SET_USER_LOCKING(STREAM) ((STREAM)->user_locking = 1) +#define __STDIO_SET_USER_LOCKING(__stream) ((__stream)->__user_locking = 1) + +#define __STDIO_ALWAYS_THREADLOCK(__stream) \ + __pthread_mutex_lock(&(__stream)->__lock) + +#define __STDIO_ALWAYS_THREADTRYLOCK(__stream) \ + __pthread_mutex_trylock(&(__stream)->__lock) + +#define __STDIO_ALWAYS_THREADUNLOCK(__stream) \ + __pthread_mutex_unlock(&(__stream)->__lock) + +#else /* __UCLIBC_HAS_THREADS__ */ -#else /* __STDIO_THREADSAFE */ +#define __STDIO_AUTO_THREADLOCK_VAR ((void)0) -#define __STDIO_THREADLOCK(STREAM) -#define __STDIO_THREADUNLOCK(STREAM) -#define __STDIO_THREADTRYLOCK(STREAM) +#define __STDIO_AUTO_THREADLOCK(__stream) ((void)0) +#define __STDIO_AUTO_THREADUNLOCK(__stream) ((void)0) -#define __STDIO_SET_USER_LOCKING(STREAM) +#define __STDIO_SET_USER_LOCKING(__stream) ((void)0) -#endif /* __STDIO_THREADSAFE */ +#define __STDIO_ALWAYS_THREADLOCK(__stream) ((void)0) +#define __STDIO_ALWAYS_THREADTRYLOCK(__stream) (0) /* Always succeed. */ +#define __STDIO_ALWAYS_THREADUNLOCK(__stream) ((void)0) -/* This file may eventually have two personalities: - 1) core stuff (similar to glibc's libio.h) - 2) extern inlines (for glibc's bits/stdio.h) - Right now, only (1) is implemented. */ +#endif /* __UCLIBC_HAS_THREADS__ */ +/**********************************************************************/ -#define _STDIO_IOFBF 0 /* Fully buffered. */ -#define _STDIO_IOLBF 1 /* Line buffered. */ -#define _STDIO_IONBF 2 /* No buffering. */ +#define __STDIO_IOFBF 0 /* Fully buffered. */ +#define __STDIO_IOLBF 1 /* Line buffered. */ +#define __STDIO_IONBF 2 /* No buffering. */ typedef struct { __off_t __pos; #ifdef __STDIO_MBSTATE __mbstate_t __mbstate; #endif -#ifdef __STDIO_WIDE - int mblen_pending; +#ifdef __UCLIBC_HAS_WCHAR__ + int __mblen_pending; #endif -} __stdio_fpos_t; +} __STDIO_fpos_t; -#ifdef __STDIO_LARGE_FILES +#ifdef __UCLIBC_HAS_LFS__ typedef struct { __off64_t __pos; #ifdef __STDIO_MBSTATE __mbstate_t __mbstate; #endif -#ifdef __STDIO_WIDE - int mblen_pending; +#ifdef __UCLIBC_HAS_WCHAR__ + int __mblen_pending; #endif -} __stdio_fpos64_t; +} __STDIO_fpos64_t; #endif - /**********************************************************************/ -#ifdef __STDIO_LARGE_FILES +#ifdef __UCLIBC_HAS_LFS__ typedef __off64_t __offmax_t; /* TODO -- rename this? */ #else typedef __off_t __offmax_t; /* TODO -- rename this? */ #endif /**********************************************************************/ +#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ -#ifdef __STDIO_GLIBC_CUSTOM_STREAMS - -typedef __ssize_t __io_read_fn(void *cookie, - char *buf, size_t bufsize); -typedef __ssize_t __io_write_fn(void *cookie, - const char *buf, size_t bufsize); +typedef __ssize_t __io_read_fn(void *__cookie, char *__buf, size_t __bufsize); +typedef __ssize_t __io_write_fn(void *__cookie, + __const char *__buf, size_t __bufsize); /* NOTE: GLIBC difference!!! -- fopencookie seek function * For glibc, the type of pos is always (__off64_t *) but in our case * it is type (__off_t *) when the lib is built without large file support. */ -typedef int __io_seek_fn(void *cookie, - __offmax_t *pos, int whence); -typedef int __io_close_fn(void *cookie); +typedef int __io_seek_fn(void *__cookie, __offmax_t *__pos, int __whence); +typedef int __io_close_fn(void *__cookie); typedef struct { - __io_read_fn *read; + __io_read_fn *read; __io_write_fn *write; - __io_seek_fn *seek; + __io_seek_fn *seek; __io_close_fn *close; } _IO_cookie_io_functions_t; #if defined(_LIBC) || defined(_GNU_SOURCE) + typedef __io_read_fn cookie_read_function_t; typedef __io_write_fn cookie_write_function_t; typedef __io_seek_fn cookie_seek_function_t; typedef __io_close_fn cookie_close_function_t; typedef _IO_cookie_io_functions_t cookie_io_functions_t; -#endif /* _GNU_SOURCE */ - -#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */ -/* - * ungot scheme: - * 0 0 none - * 0 1 one user (unused ungot is 1) or one scanf (unused ungot is 0) - * 1 0 must be scanf[0] and user[1] - * 1 1 illegal -- could be used to signal safe for setbuf - * but if used, need to fix _stdio_adjpos at least! - */ +#endif -#ifdef __UCLIBC__ -#define __stdio_file_struct _UC_FILE #endif +/**********************************************************************/ -struct __stdio_file_struct { - unsigned short modeflags; +struct __STDIO_FILE_STRUCT { + unsigned short __modeflags; /* There could be a hole here, but modeflags is used most.*/ -#ifdef __STDIO_WIDE - /* TODO - ungot_width could be combined with ungot. But what about hole? */ - unsigned char ungot_width[2]; /* 0 is current (building) char, 1 is scanf */ - wchar_t ungot[2]; -#else /* __STDIO_WIDE */ - unsigned char ungot[2]; -#endif /* __STDIO_WIDE */ - int filedes; -#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) - struct __stdio_file_struct *nextopen; -#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */ +#ifdef __UCLIBC_HAS_WCHAR__ + unsigned char __ungot_width[2]; /* 0: current (building) char; 1: scanf */ + /* Move the following futher down to avoid problems with getc/putc + * macros breaking shared apps when wchar config support is changed. */ + /* wchar_t ungot[2]; */ +#else /* __UCLIBC_HAS_WCHAR__ */ + unsigned char __ungot[2]; +#endif /* __UCLIBC_HAS_WCHAR__ */ + int __filedes; #ifdef __STDIO_BUFFERS - unsigned char *bufstart; /* pointer to buffer */ - unsigned char *bufend; /* pointer to 1 past end of buffer */ - unsigned char *bufpos; - unsigned char *bufread; /* pointer to 1 past last buffered read char. */ + unsigned char *__bufstart; /* pointer to buffer */ + unsigned char *__bufend; /* pointer to 1 past end of buffer */ + unsigned char *__bufpos; + unsigned char *__bufread; /* pointer to 1 past last buffered read char */ + #ifdef __STDIO_GETC_MACRO - unsigned char *bufgetc; /* 1 past last readable by getc */ + unsigned char *__bufgetc_u; /* 1 past last readable by getc_unlocked */ #endif /* __STDIO_GETC_MACRO */ #ifdef __STDIO_PUTC_MACRO - unsigned char *bufputc; /* 1 past last writeable by putc */ + unsigned char *__bufputc_u; /* 1 past last writeable by putc_unlocked */ #endif /* __STDIO_PUTC_MACRO */ + #endif /* __STDIO_BUFFERS */ -#ifdef __STDIO_GLIBC_CUSTOM_STREAMS - void *cookie; - _IO_cookie_io_functions_t gcs; -#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */ + +#ifdef __STDIO_HAS_OPENLIST + struct __STDIO_FILE_STRUCT *__nextopen; +#endif +#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ + void *__cookie; + _IO_cookie_io_functions_t __gcs; +#endif +#ifdef __UCLIBC_HAS_WCHAR__ + wchar_t __ungot[2]; +#endif #ifdef __STDIO_MBSTATE - __mbstate_t state; + __mbstate_t __state; #endif -#ifdef __STDIO_THREADSAFE - int user_locking; - pthread_mutex_t lock; +#ifdef __UCLIBC_HAS_XLOCALE__ + void *__unused; /* Placeholder for codeset binding. */ +#endif +#ifdef __UCLIBC_HAS_THREADS__ + int __user_locking; + pthread_mutex_t __lock; #endif /* Everything after this is unimplemented... and may be trashed. */ #if __STDIO_BUILTIN_BUF_SIZE > 0 - unsigned char builtinbuf[__STDIO_BUILTIN_BUF_SIZE]; + unsigned char __builtinbuf[__STDIO_BUILTIN_BUF_SIZE]; #endif /* __STDIO_BUILTIN_BUF_SIZE > 0 */ }; /***********************************************************************/ - -#define __MASK_UNGOT (0x0002|0x0001) -#define __MASK_UNGOT1 0x0001 -#define __MASK_UNGOT2 0x0002 -#define __FLAG_EOF 0x0004 /* EOF reached? */ -#define __FLAG_ERROR 0x0008 /* stream in error state? */ -#define __FLAG_WRITEONLY 0x0010 /* unreadable */ -#define __FLAG_READONLY 0x0020 /* unwriteable */ -#define __FLAG_FREEFILE 0x0040 /* free FILE struct after use */ -#define __FLAG_NARROW 0x0080 - -#define __FLAG_FBF 0 /* convenience value */ -#define __FLAG_LBF 0x0100 -#define __FLAG_NBF 0x0200 -#define __MASK_BUFMODE 0x0300 - -#define __FLAG_APPEND 0x0400 -#define __FLAG_WIDE 0x0800 - -#define __FLAG_READING 0x1000 -#define __FLAG_WRITING 0x2000 - -#define __FLAG_FREEBUF 0x4000 /* free buffer after use */ -#define __FLAG_LARGEFILE 0x8000 - -/**********************************************************************/ - -#ifdef __STDIO_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); -#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */ - -/**********************************************************************/ - -#ifdef __STDIO_MBSTATE -#define __COPY_MBSTATE(dest,src) ((dest)->mask = (src)->mask, (dest)->wc = (src)->wc) -#define __INIT_MBSTATE(dest) ((dest)->mask = 0) -#else -#define __COPY_MBSTATE(dest,src) -#define __INIT_MBSTATE(dest) -#endif - -/**********************************************************************/ - -/* TODO -- thread safety issues */ -#define __CLEARERR(stream) \ - ((stream)->modeflags &= ~(__FLAG_EOF|__FLAG_ERROR), (void)0) -#define __FEOF(stream) ((stream)->modeflags & __FLAG_EOF) -#define __FERROR(stream) ((stream)->modeflags & __FLAG_ERROR) - -#define __FEOF_OR_FERROR(stream) \ - ((stream)->modeflags & (__FLAG_EOF|__FLAG_ERROR)) - - -/* TODO: check this - * If we want to implement the getc and putc macros, we need to take - * into account wide streams. So... would need two additional variables - * if we have wide streams (bufread and bufwrite), and one otherwise - * (bufwrite). getc would be effective for FBF streams. It isn't for - * LBF streams because other LBF streams need to be flushed. putc - * thouch is only effective for FBF streams. Of course, to support - * threads, we have to use functions. +/* Having ungotten characters implies the stream is reading. + * The scheme used here treats the least significant 2 bits of + * the stream's modeflags member as follows: + * 0 0 Not currently reading. + * 0 1 Reading, but no ungetc() or scanf() push back chars. + * 1 0 Reading with one ungetc() char (ungot[1] is 1) + * or one scanf() pushed back char (ungot[1] is 0). + * 1 1 Reading with both an ungetc() char and a scanf() + * pushed back char. Note that this must be the result + * of a scanf() push back (in ungot[0]) _followed_ by + * an ungetc() call (in ungot[1]). + * + * Notes: + * scanf() can NOT use ungetc() to push back characters. + * (See section 7.19.6.2 of the C9X rationale -- WG14/N897.) */ -#ifdef __STDIO_GETC_MACRO -#define __GETC(stream) ( ((stream)->bufpos < (stream)->bufgetc) \ - ? (*(stream)->bufpos++) \ - : fgetc_unlocked(stream) ) -#else /* __STDIO_GETC_MACRO */ -#define __GETC(stream) fgetc_unlocked(stream) -#endif /* __STDIO_GETC_MACRO */ - -#ifdef __STDIO_PUTC_MACRO -#define __PUTC(c, stream) ( ((stream)->bufpos < (stream)->bufputc) \ - ? (*(stream)->bufpos++) = (c) \ - : fputc_unlocked((c),(stream)) ) -#else /* __STDIO_PUTC_MACRO */ -#define __PUTC(c, stream) fputc_unlocked(c, stream) -#endif /* __STDIO_PUTC_MACRO */ - - -#if 0 -/* TODO: disabled for now */ -/* Masking macros for the above _are_ allowed by the standard. */ -#define clearerr(stream) __CLEARERR(stream) -#define feof(stream) __FEOF(stream) -#define ferror(stream) __FERROR(stream) -#endif - -#if 0 -/* TODO -- what about custom streams!!! */ -/* Only use the macro below if you know fp is a valid FILE for a valid fd. */ -#define __fileno(fp) ((fp)->filedes) -#endif - +#define __MASK_READING 0x0003U /* (0x0001 | 0x0002) */ +#define __FLAG_READING 0x0001U +#define __FLAG_UNGOT 0x0002U +#define __FLAG_EOF 0x0004U +#define __FLAG_ERROR 0x0008U +#define __FLAG_WRITEONLY 0x0010U +#define __FLAG_READONLY 0x0020U /* (__FLAG_WRITEONLY << 1) */ +#define __FLAG_WRITING 0x0040U +#define __FLAG_NARROW 0x0080U + +#define __FLAG_FBF 0x0000U /* must be 0 */ +#define __FLAG_LBF 0x0100U +#define __FLAG_NBF 0x0200U /* (__FLAG_LBF << 1) */ +#define __MASK_BUFMODE 0x0300U /* (__FLAG_LBF|__FLAG_NBF) */ +#define __FLAG_APPEND 0x0400U /* fixed! == O_APPEND for linux */ +#define __FLAG_WIDE 0x0800U +/* available slot 0x1000U */ +#define __FLAG_FREEFILE 0x2000U +#define __FLAG_FREEBUF 0x4000U +#define __FLAG_LARGEFILE 0x8000U /* fixed! == 0_LARGEFILE for linux */ + +/* Note: In no-buffer mode, it would be possible to pack the necessary + * flags into one byte. Since we wouldn't be buffering and there would + * be no support for wchar, the only flags we would need would be: + * 2 bits : ungot count + * 2 bits : eof + error + * 2 bits : readonly + writeonly + * 1 bit : freefile + * 1 bit : appending + * So, for a very small system (< 128 files) we might have a + * 4-byte FILE struct of: + * unsigned char flags; + * signed char filedes; + * unsigned char ungot[2]; + */ /********************************************************************** * PROTOTYPES OF INTERNAL FUNCTIONS **********************************************************************/ +#ifdef _LIBC + +extern void _stdio_init(void); +extern void _stdio_term(void); + +#ifdef __STDIO_HAS_OPENLIST -extern FILE *_stdio_openlist; +extern struct __STDIO_FILE_STRUCT *_stdio_openlist; -#ifdef __STDIO_THREADSAFE +#ifdef __UCLIBC_HAS_THREADS__ extern pthread_mutex_t _stdio_openlist_lock; +extern int _stdio_openlist_delflag; +extern int _stdio_user_locking; extern void __stdio_init_mutex(pthread_mutex_t *m); #endif -extern int _stdio_adjpos(FILE * __restrict stream, __offmax_t * pos); -extern int _stdio_lseek(FILE *stream, __offmax_t *pos, int whence); -/* TODO: beware of signals with _stdio_fwrite!!!! */ -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(const char * __restrict filename, - const char * __restrict mode, - FILE * __restrict stream, int filedes); - -extern FILE *_stdio_fsfopen(const char * __restrict filename, - const char * __restrict mode, - register FILE * __restrict stream); - -extern void _stdio_init(void); -extern void _stdio_term(void); - -#ifndef NDEBUG -extern void __stdio_validate_FILE(FILE *stream); -#else -#define __stdio_validate_FILE(stream) ((void)0) #endif -#ifdef __STDIO_WIDE -extern size_t _wstdio_fwrite(const wchar_t *__restrict ws, size_t n, - register FILE *__restrict stream); #endif +/**********************************************************************/ -/********************************************************************** - * UTILITY functions - **********************************************************************/ -#ifdef _STDIO_UTILITY - -#include -#include -#include +#define __CLEARERR_UNLOCKED(__stream) \ + ((void)((__stream)->__modeflags &= ~(__FLAG_EOF|__FLAG_ERROR))) +#define __FEOF_UNLOCKED(__stream) ((__stream)->__modeflags & __FLAG_EOF) +#define __FERROR_UNLOCKED(__stream) ((__stream)->__modeflags & __FLAG_ERROR) -#if INTMAX_MAX <= 2147483647L -#define __UIM_BUFLEN 12 /* 10 digits + 1 nul + 1 sign */ -#elif INTMAX_MAX <= 9223372036854775807LL -#define __UIM_BUFLEN 22 /* 20 digits + 1 nul + 1 sign */ +#ifdef __UCLIBC_HAS_THREADS__ +# define __CLEARERR(__stream) (clearerr)(__stream) +# define __FERROR(__stream) (ferror)(__stream) +# define __FEOF(__stream) (feof)(__stream) #else -#error unknown number of digits for intmax_t! +# define __CLEARERR(__stream) __CLEARERR_UNLOCKED(__stream) +# define __FERROR(__stream) __FERROR_UNLOCKED(__stream) +# define __FEOF(__stream) __FEOF_UNLOCKED(__stream) #endif -#ifdef LLONG_MAX /* --------------- */ -#if LLONG_MAX <= 2147483647L -#define __UIM_BUFLEN_LLONG 12 /* 10 digits + 1 nul + 1 sign */ -#elif LLONG_MAX <= 9223372036854775807LL -#define __UIM_BUFLEN_LLONG 22 /* 20 digits + 1 nul + 1 sign */ -#else -#error unknown number of digits for long long! -#endif -#endif /* ULLONG_MAX ----------------------------- */ +extern int __fgetc_unlocked(FILE *__stream); +extern int __fputc_unlocked(int __c, FILE *__stream); -#if LONG_MAX <= 2147483647L -#define __UIM_BUFLEN_LONG 12 /* 10 digits + 1 nul + 1 sign */ -#elif LONG_MAX <= 9223372036854775807LL -#define __UIM_BUFLEN_LONG 22 /* 20 digits + 1 nul + 1 sign */ -#else -#error unknown number of digits for long! -#endif +/* First define the default definitions. They overriden below as necessary. */ +#define __FGETC_UNLOCKED(__stream) (__fgetc_unlocked)((__stream)) +#define __FGETC(__stream) (fgetc)((__stream)) +#define __GETC_UNLOCKED(__stream) (__fgetc_unlocked)((__stream)) +#define __GETC(__stream) (fgetc)((__stream)) -#if INT_MAX <= 32767 -#define __UIM_BUFLEN_INT 7 /* 10 digits + 1 nul + 1 sign */ -#elif INT_MAX <= 2147483647L -#define __UIM_BUFLEN_INT 12 /* 10 digits + 1 nul + 1 sign */ -#else -#error unknown number of digits for int! -#endif +#define __FPUTC_UNLOCKED(__c, __stream) (__fputc_unlocked)((__c),(__stream)) +#define __FPUTC(__c, __stream) (fputc)((__c),(__stream)) +#define __PUTC_UNLOCKED(__c, __stream) (__fputc_unlocked)((__c),(__stream)) +#define __PUTC(__c, __stream) (fputc)((__c),(__stream)) -typedef enum { - __UIM_DECIMAL = 0, - __UIM_GROUP = ',', /* Base 10 locale-dependent grouping. */ - __UIM_LOWER = 'a' - 10, - __UIM_UPPER = 'A' - 10, -} __UIM_CASE; -/* Write a NULL-terminated list of "char *" args to file descriptor fd. - * For an example of usage, see __assert.c. - */ -extern void _stdio_fdout(int fd, ...); +#ifdef __STDIO_GETC_MACRO -/* Convert the int val to a string in base abs(base). val is treated as - * an unsigned ??? int type if base > 0, and signed if base < 0. This - * is an internal function with _no_ error checking done unless assert()s - * are enabled. - * - * Note: bufend is a pointer to the END of the buffer passed. - * Call like this: - * char buf[SIZE], *p; - * p = _xltostr(buf + sizeof(buf) - 1, {unsigned int}, 10, __UIM_DECIMAL) - * p = _xltostr(buf + sizeof(buf) - 1, {int}, -10, __UIM_DECIMAL) - * - * WARNING: If base > 10, case _must_be_ either __UIM_LOWER or __UIM_UPPER - * for lower and upper case alphas respectively. - * WARNING: If val is really a signed type, make sure base is negative! - * Otherwise, you could overflow your buffer. - */ -extern char *_uintmaxtostr(char * __restrict bufend, uintmax_t uval, - int base, __UIM_CASE alphacase); - -/* TODO -- make this either a (possibly inline) function? */ -#ifndef __BCC__ -#define _int10tostr(bufend, intval) \ - _uintmaxtostr((bufend), (intval), -10, __UIM_DECIMAL) -#else /* bcc doesn't do prototypes, we need to explicitly cast */ -#define _int10tostr(bufend, intval) \ - _uintmaxtostr((bufend), (uintmax_t)(intval), -10, __UIM_DECIMAL) -#endif +extern FILE *__stdin; /* For getchar() macro. */ + +# define __GETC_UNLOCKED_MACRO(__stream) \ + ( ((__stream)->__bufpos < (__stream)->__bufgetc_u) \ + ? (*(__stream)->__bufpos++) \ + : __fgetc_unlocked(__stream) ) + +# if 0 + /* Classic macro approach. getc{_unlocked} can have side effects. */ +# undef __GETC_UNLOCKED +# define __GETC_UNLOCKED(__stream) __GETC_UNLOCKED_MACRO((__stream)) +# ifndef __UCLIBC_HAS_THREADS__ +# undef __GETC +# define __GETC(__stream) __GETC_UNLOCKED_MACRO((__stream)) +# endif + +# else + /* Using gcc extension for safety and additional inlining. */ +# undef __FGETC_UNLOCKED +# define __FGETC_UNLOCKED(__stream) \ + (__extension__ ({ \ + FILE *__S = (__stream); \ + __GETC_UNLOCKED_MACRO(__S); \ + }) ) + +# undef __GETC_UNLOCKED +# define __GETC_UNLOCKED(__stream) __FGETC_UNLOCKED((__stream)) + +# ifdef __UCLIBC_HAS_THREADS__ +# undef __FGETC +# define __FGETC(__stream) \ + (__extension__ ({ \ + FILE *__S = (__stream); \ + ((__S->__user_locking ) \ + ? __GETC_UNLOCKED_MACRO(__S) \ + : (fgetc)(__S)); \ + }) ) + +# undef __GETC +# define __GETC(__stream) __FGETC((__stream)) + +# else + +# undef __FGETC +# define __FGETC(__stream) __FGETC_UNLOCKED((__stream)) +# undef __GETC +# define __GETC(__stream) __FGETC_UNLOCKED((__stream)) + +# endif +# endif -#define __BUFLEN_INT10TOSTR __UIM_BUFLEN_INT +#else -#endif /* _STDIO_UTILITY */ -/**********************************************************************/ -/* uClibc translations */ -/**********************************************************************/ +#endif /* __STDIO_GETC_MACRO */ -/* TODO: note done above.. typedef struct __stdio_file_struct _UC_FILE; */ -typedef __stdio_fpos_t _UC_fpos_t; -#ifdef __STDIO_LARGE_FILES -typedef __stdio_fpos64_t _UC_fpos64_t; -#endif -#define _UC_IOFBF _STDIO_IOFBF /* Fully buffered. */ -#define _UC_IOLBF _STDIO_IOLBF /* Line buffered. */ -#define _UC_IONBF _STDIO_IONBF /* No buffering. */ +#ifdef __STDIO_PUTC_MACRO -#define _UC_BUFSIZ _STDIO_BUFSIZ +extern FILE *__stdout; /* For putchar() macro. */ + +# define __PUTC_UNLOCKED_MACRO(__c, __stream) \ + ( ((__stream)->__bufpos < (__stream)->__bufputc_u) \ + ? (*(__stream)->__bufpos++) = (__c) \ + : __fputc_unlocked((__c),(__stream)) ) + +# if 0 + /* Classic macro approach. putc{_unlocked} can have side effects.*/ +# undef __PUTC_UNLOCKED +# define __PUTC_UNLOCKED(__c, __stream) \ + __PUTC_UNLOCKED_MACRO((__c), (__stream)) +# ifndef __UCLIBC_HAS_THREADS__ +# undef __PUTC +# define __PUTC(__c, __stream) __PUTC_UNLOCKED_MACRO((__c), (__stream)) +# endif + +# else + /* Using gcc extension for safety and additional inlining. */ + +# undef __FPUTC_UNLOCKED +# define __FPUTC_UNLOCKED(__c, __stream) \ + (__extension__ ({ \ + FILE *__S = (__stream); \ + __PUTC_UNLOCKED_MACRO((__c),__S); \ + }) ) + +# undef __PUTC_UNLOCKED +# define __PUTC_UNLOCKED(__c, __stream) __FPUTC_UNLOCKED((__c), (__stream)) + +# ifdef __UCLIBC_HAS_THREADS__ +# undef __FPUTC +# define __FPUTC(__c, __stream) \ + (__extension__ ({ \ + FILE *__S = (__stream); \ + ((__S->__user_locking) \ + ? __PUTC_UNLOCKED_MACRO((__c),__S) \ + : (fputc)((__c),__S)); \ + }) ) + +# undef __PUTC +# define __PUTC(__c, __stream) __FPUTC((__c), (__stream)) + +# else + +# undef __FUTC +# define __FPUTC(__c, __stream) __FPUTC_UNLOCKED((__c),(__stream)) +# undef __PUTC +# define __PUTC(__c, __stream) __FPUTC_UNLOCKED((__c),(__stream)) + +# endif +# endif + +#endif /* __STDIO_PUTC_MACRO */ -- cgit v1.2.3