📄 _stdio.c
字号:
/* 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. */#include "_stdio.h"/* This is pretty much straight from uClibc, but with one important * difference. * * We now initialize the locking flag to user locking instead of * auto locking (i.e. FSETLOCKING_BYCALLER vs FSETLOCKING_INTERNAL). * This greatly benefits non-threading applications linked to a * shared thread-enabled library. In threading applications, we * walk the stdio open file list and reset the locking mode * appropriately when the thread subsystem is initialized. *//**********************************************************************/#ifdef __UCLIBC_HAS_WCHAR__#define __STDIO_FILE_INIT_WUNGOT { 0, 0 },#else#define __STDIO_FILE_INIT_WUNGOT#endif#ifdef __STDIO_GETC_MACRO# define __STDIO_FILE_INIT_BUFGETC(x) x,#else# define __STDIO_FILE_INIT_BUFGETC(x)#endif#ifdef __STDIO_PUTC_MACRO# define __STDIO_FILE_INIT_BUFPUTC(x) x,#else# define __STDIO_FILE_INIT_BUFPUTC(x)#endif#ifdef __STDIO_HAS_OPENLIST#define __STDIO_FILE_INIT_NEXT(next) (next),#else#define __STDIO_FILE_INIT_NEXT(next)#endif#ifdef __STDIO_BUFFERS#define __STDIO_FILE_INIT_BUFFERS(buf,bufsize) \ (buf), (buf)+(bufsize), (buf), (buf),#else#define __STDIO_FILE_INIT_BUFFERS(buf,bufsize)#endif#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__#define __STDIO_FILE_INIT_CUSTOM_STREAM(stream) \ &((stream).__filedes), { _cs_read, _cs_write, _cs_seek, _cs_close },#else#define __STDIO_FILE_INIT_CUSTOM_STREAM(stream)#endif#ifdef __STDIO_MBSTATE#define __STDIO_FILE_INIT_MBSTATE \ { 0, 0 },#else#define __STDIO_FILE_INIT_MBSTATE#endif#ifdef __UCLIBC_HAS_XLOCALE__#define __STDIO_FILE_INIT_UNUSED \ NULL,#else#define __STDIO_FILE_INIT_UNUSED#endif#ifdef __UCLIBC_HAS_THREADS__#define __STDIO_FILE_INIT_THREADSAFE \ 2, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,#else#define __STDIO_FILE_INIT_THREADSAFE#endif#define __STDIO_INIT_FILE_STRUCT(stream, flags, filedes, next, buf, bufsize) \ { (flags), \ { 0, 0 }, /* ungot[2] (no wchar) or ungot_width[2] (wchar)*/ \ (filedes), \ __STDIO_FILE_INIT_BUFFERS(buf,bufsize) \ __STDIO_FILE_INIT_BUFGETC((buf)) \ __STDIO_FILE_INIT_BUFPUTC((buf)) \ __STDIO_FILE_INIT_NEXT(next) \ __STDIO_FILE_INIT_CUSTOM_STREAM(stream) \ __STDIO_FILE_INIT_WUNGOT \ __STDIO_FILE_INIT_MBSTATE \ __STDIO_FILE_INIT_UNUSED \ __STDIO_FILE_INIT_THREADSAFE \} /* TODO: builtin buf *//**********************************************************************//* First we need the standard files. */#ifdef __STDIO_BUFFERSstatic unsigned char _fixed_buffers[2 * BUFSIZ];#endifstatic FILE _stdio_streams[] = { __STDIO_INIT_FILE_STRUCT(_stdio_streams[0], \ __FLAG_LBF|__FLAG_READONLY, \ 0, \ _stdio_streams + 1, \ _fixed_buffers, \ BUFSIZ ), __STDIO_INIT_FILE_STRUCT(_stdio_streams[1], \ __FLAG_LBF|__FLAG_WRITEONLY, \ 1, \ _stdio_streams + 2, \ _fixed_buffers + BUFSIZ, \ BUFSIZ ), __STDIO_INIT_FILE_STRUCT(_stdio_streams[2], \ __FLAG_NBF|__FLAG_WRITEONLY, \ 2, \ NULL, \ NULL, \ 0 )};FILE *stdin = _stdio_streams;FILE *stdout = _stdio_streams + 1;FILE *stderr = _stdio_streams + 2;#ifdef __STDIO_GETC_MACROFILE *__stdin = _stdio_streams; /* For getchar() macro. */#endif#ifdef __STDIO_PUTC_MACROFILE *__stdout = _stdio_streams + 1; /* For putchar() macro. *//* FILE *__stderr = _stdio_streams + 2; */#endif/**********************************************************************/#ifdef __STDIO_HAS_OPENLIST/* In certain configurations, we need to keep a list of open files. * 1) buffering enabled - We need to initialize the buffering mode * (full or line buffering) of stdin and stdout. We also * need to flush all write buffers prior to normal termination. * 2) custom streams - Even if we aren't buffering in the library * itself, we need to fclose() all custom streams when terminating * so that any special cleanup is done. * 3) threads enabled - We need to be able to reset the locking mode * of all open streams when the threading system is initialized. */FILE *_stdio_openlist = _stdio_streams;# ifdef __UCLIBC_HAS_THREADS__pthread_mutex_t _stdio_openlist_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;int _stdio_openlist_delflag = 0;# endif#endif/**********************************************************************/#ifdef __UCLIBC_HAS_THREADS__/* 2 if threading not initialized and 0 otherwise; */int _stdio_user_locking = 2;void __stdio_init_mutex(pthread_mutex_t *m){ static const pthread_mutex_t __stdio_mutex_initializer = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; memcpy(m, &__stdio_mutex_initializer, sizeof(__stdio_mutex_initializer));}#endif/**********************************************************************//* We assume here that we are the only remaining thread. */void _stdio_term(void){#if defined(__STDIO_BUFFERS) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__) register FILE *ptr;#ifdef __UCLIBC_HAS_THREADS__ /* First, make sure the open file list is unlocked. If it was * locked, then I suppose there is a chance that a pointer in the * chain might be corrupt due to a partial store. */ __stdio_init_mutex(&_stdio_openlist_lock); /* Next we need to worry about the streams themselves. If a stream * is currently locked, then it may be in an invalid state. So we * 'disable' it in case a custom stream is stacked on top of it. * Then we reinitialize the locks. */ for (ptr = _stdio_openlist ; ptr ; ptr = ptr->__nextopen ) { if (__STDIO_ALWAYS_THREADTRYLOCK(ptr)) { /* The stream is already locked, so we don't want to touch it. * However, if we have custom streams, we can't just close it * or leave it locked since a custom stream may be stacked * on top of it. So we do unlock it, while also disabling it. */ ptr->__modeflags = (__FLAG_READONLY|__FLAG_WRITEONLY); __STDIO_STREAM_DISABLE_GETC(ptr); __STDIO_STREAM_DISABLE_PUTC(ptr); __STDIO_STREAM_INIT_BUFREAD_BUFPOS(ptr); } ptr->__user_locking = 1; /* Set locking mode to "by caller". */ __stdio_init_mutex(&ptr->__lock); /* Shouldn't be necessary, but... */ }#endif /* Finally, flush all writing streams and shut down all custom streams. * NOTE: We assume that any stacking by custom streams is done on top * of streams previously allocated, and hence further down the * list. Otherwise we have no way of knowing the order in which * to shut them down. * Remember that freopen() counts as a new allocation here, even * though the stream is reused. That's because it moves the * stream to the head of the list. */ for (ptr = _stdio_openlist ; ptr ; ptr = ptr->__nextopen ) {#ifdef __STDIO_BUFFERS /* Write any pending buffered chars. */ if (__STDIO_STREAM_IS_WRITING(ptr)) { __STDIO_COMMIT_WRITE_BUFFER(ptr); }#endif#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ /* Actually close all custom streams to perform any special cleanup. */ if (ptr->__cookie != &ptr->__filedes) { __CLOSE(ptr); }#endif }#endif}void _stdio_init(void){#ifdef __STDIO_BUFFERS int old_errno = errno; /* stdin and stdout uses line buffering when connected to a tty. */ _stdio_streams[0].__modeflags ^= (1-isatty(0)) * __FLAG_LBF; _stdio_streams[1].__modeflags ^= (1-isatty(1)) * __FLAG_LBF; __set_errno(old_errno);#endif#ifndef __UCLIBC__ /* _stdio_term is done automatically when exiting if stdio is used. * See misc/internals/__uClibc_main.c and and stdlib/atexit.c. */ atexit(_stdio_term);#endif /* __UCLIBC__ */}/**********************************************************************/#if !(__MASK_READING & __FLAG_UNGOT)#error Assumption violated about __MASK_READING and __FLAG_UNGOT#endif#ifdef __UCLIBC_HAS_THREADS__#include <pthread.h>#endif#ifndef NDEBUGvoid _stdio_validate_FILE(const FILE *stream){#ifdef __UCLIBC_HAS_THREADS__ assert(((unsigned int)(stream->__user_locking)) <= 2);#endif#warning Define a constant for minimum possible valid __filedes? assert(stream->__filedes >= -3); if (stream->__filedes < 0) {/* assert((stream->__filedes != -1) *//* #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ *//* || (stream->__cookie == &stream->__filedes) /\* custom *\/ *//* #endif *//* ); *//* assert((stream->__filedes == -1) || __STDIO_STREAM_IS_FBF(stream)); */ assert(!__STDIO_STREAM_IS_FAKE_VSNPRINTF(stream) || __STDIO_STREAM_IS_NARROW(stream)); assert(!__STDIO_STREAM_IS_FAKE_VSSCANF(stream) || __STDIO_STREAM_IS_NARROW(stream));#ifdef __STDIO_STREAM_IS_FAKE_VSWPRINTF assert(!__STDIO_STREAM_IS_FAKE_VSWPRINTF(stream) || __STDIO_STREAM_IS_WIDE(stream));#endif#ifdef __STDIO_STREAM_IS_FAKE_VSWSCANF assert(!__STDIO_STREAM_IS_FAKE_VSWSCANF(stream) || __STDIO_STREAM_IS_WIDE(stream));#endif }#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ if (stream->__cookie != &stream->__filedes) { /* custom */ assert(stream->__filedes == -1); }#endif /* Can not be both narrow and wide oriented at the same time. */ assert(!(__STDIO_STREAM_IS_NARROW(stream) && __STDIO_STREAM_IS_WIDE(stream))); /* The following impossible case is used to disable a stream. */ if ((stream->__modeflags & (__FLAG_READONLY|__FLAG_WRITEONLY)) == (__FLAG_READONLY|__FLAG_WRITEONLY) ) { assert(stream->__modeflags == (__FLAG_READONLY|__FLAG_WRITEONLY)); assert(stream->__filedes == -1);#ifdef __STDIO_BUFFERS assert(stream->__bufpos == stream->__bufstart); assert(stream->__bufread == stream->__bufstart);# ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u == stream->__bufstart);# endif# ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u == stream->__bufstart);# endif#endif } if (__STDIO_STREAM_IS_READONLY(stream)) {/* assert(!__STDIO_STREAM_IS_WRITEONLY(stream)); */ assert(!__STDIO_STREAM_IS_WRITING(stream)); if (stream->__modeflags & __FLAG_UNGOT) { assert(((unsigned)(stream->__ungot[1])) <= 1); assert(!__FEOF_UNLOCKED(stream)); } } if (__STDIO_STREAM_IS_WRITEONLY(stream)) {/* assert(!__STDIO_STREAM_IS_READONLY(stream)); */ assert(!__STDIO_STREAM_IS_READING(stream)); assert(!(stream->__modeflags & __FLAG_UNGOT)); } if (__STDIO_STREAM_IS_NBF(stream)) { /* We require that all non buffered streams have no buffer. */ assert(!__STDIO_STREAM_BUFFER_SIZE(stream)); } assert((stream->__modeflags & __MASK_BUFMODE) <= __FLAG_NBF);#ifdef __STDIO_BUFFERS /* Ensure __bufstart <= __bufpos <= __bufend. */ assert(stream->__bufpos >= stream->__bufstart); assert(stream->__bufpos <= stream->__bufend); /* Ensure __bufstart <= __bufread <= __bufend. */ assert(stream->__bufread >= stream->__bufstart); assert(stream->__bufread <= stream->__bufend);#endif /* If EOF, then we must have no buffered readable or ungots. */ if (__FEOF_UNLOCKED(stream)) {#ifdef __STDIO_BUFFERS assert(stream->__bufpos == stream->__bufread);#endif assert(!(stream->__modeflags & __FLAG_UNGOT)); } if (!__STDIO_STREAM_IS_WRITING(stream)) {#ifdef __STDIO_BUFFERS /* If not writing, then putc macro must be disabled. */# ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u == stream->__bufstart);# endif#endif } if (!__STDIO_STREAM_IS_READING(stream)) { /* If not reading, then can not have ungots. */ assert(!(stream->__modeflags & __FLAG_UNGOT));#ifdef __STDIO_BUFFERS /* Ensure __bufread == __bufstart. */ assert(stream->__bufread == stream->__bufstart); /* If not reading, then getc macro must be disabled. */# ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u == stream->__bufstart);# endif#endif } if (__STDIO_STREAM_IS_READING(stream)) { assert(!__STDIO_STREAM_IS_WRITING(stream));#ifdef __STDIO_BUFFERS /* Ensure __bufpos <= __bufread. */ assert(stream->__bufpos <= stream->__bufread); /* Ensure __bufgetc_u is valid. */# ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u >= stream->__bufstart); assert(stream->__bufgetc_u <= stream->__bufread);# endif#endif } if (__STDIO_STREAM_IS_WRITING(stream)) { assert(!__STDIO_STREAM_IS_READING(stream));#ifdef __STDIO_BUFFERS# ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u >= stream->__bufstart); assert(stream->__bufputc_u <= stream->__bufend);# endif#endif } /* If have an ungotten char, then getc (and putc) must be disabled. */ /* Also, wide streams must have the getc/putc macros disabled. */ if ((stream->__modeflags & __FLAG_UNGOT) || __STDIO_STREAM_IS_WIDE(stream) ) {#ifdef __STDIO_BUFFERS# ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__ assert(stream->__bufputc_u == stream->__bufstart);# endif# ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ assert(stream->__bufgetc_u == stream->__bufstart);# endif#endif } /* TODO -- filepos? ungot_width? filedes? nextopen? */}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -