| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 | /* 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__#ifdef __USE_STDIO_FUTEXES__#define __STDIO_FILE_INIT_THREADSAFE \	2, _LIBC_LOCK_RECURSIVE_INITIALIZER,#else#define __STDIO_FILE_INIT_THREADSAFE \	2, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,#endif#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____UCLIBC_IO_MUTEX_INIT(_stdio_openlist_add_lock);#  ifdef __STDIO_BUFFERS__UCLIBC_IO_MUTEX_INIT(_stdio_openlist_del_lock);volatile int _stdio_openlist_use_count = 0;int _stdio_openlist_del_count = 0;#  endif# endif#endif/**********************************************************************/#ifdef __UCLIBC_HAS_THREADS__/* 2 if threading not initialized and 0 otherwise; */int _stdio_user_locking = 2;#ifndef __USE_STDIO_FUTEXES__void attribute_hidden __stdio_init_mutex(__UCLIBC_MUTEX_TYPE *m){	const __UCLIBC_MUTEX_STATIC(__stdio_mutex_initializer,		PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);	memcpy(m, &__stdio_mutex_initializer, sizeof(__stdio_mutex_initializer));}#endif#endif/**********************************************************************//* We assume here that we are the only remaining thread. */void attribute_hidden _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_add_lock);#warning check#ifdef __STDIO_BUFFERS	STDIO_INIT_MUTEX(_stdio_openlist_del_lock);#endif	/* 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_CANCEL_UNSAFE(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}#if defined __STDIO_BUFFERS || !defined __UCLIBC__void attribute_hidden _stdio_init(void){#ifdef __STDIO_BUFFERS	int old_errno = errno;	/* stdin and stdout uses line buffering when connected to a tty. */	if (!isatty(0))		_stdio_streams[0].__modeflags ^= __FLAG_LBF;	if (!isatty(1))		_stdio_streams[1].__modeflags ^= __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}#endif/**********************************************************************/#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
 |