summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/common/bits/uClibc_stdio.h
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2004-02-11 23:48:50 +0000
committerManuel Novoa III <mjn3@codepoet.org>2004-02-11 23:48:50 +0000
commit082e680bd54e999f2bb4eb77141958938b1e9ee9 (patch)
tree203c45b85ca608e1550d8ffc459456fc9cf0b30b /libc/sysdeps/linux/common/bits/uClibc_stdio.h
parent17c21765b4a97c6f0b74ba8466073e5a3f97cdee (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/sysdeps/linux/common/bits/uClibc_stdio.h')
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h716
1 files changed, 325 insertions, 391 deletions
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 <stddef.h>
+
/* 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 <wchar.h>
-#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 <bits/pthreadtypes.h>
-#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 <features.h>
-#include <limits.h>
-#include <stdint.h>
+#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 */