1 /*
2  * Copyright (c) 1990, 2007 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * and/or other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	%W% (UofMD/Berkeley) %G%
18  */
19 
20 /*
21  * Information local to this implementation of stdio,
22  * in particular, macros and private variables.
23  */
24 
25 #include <_ansi.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <stdio.h>
30 #ifdef __SCLE
31 # include <io.h>
32 #endif
33 
34 /* The following define determines if the per-reent stdin, stdout and stderr
35    streams are closed during _reclaim_reent().  The stdin, stdout and stderr
36    streams are initialized to use file descriptors 0, 1 and 2 respectively.  In
37    case _STDIO_CLOSE_PER_REENT_STD_STREAMS is defined these file descriptors
38    will be closed via close() provided the owner of the reent structure
39    triggerd the on demand reent initilization, see CHECK_INIT(). */
40 #if !defined(__tirtos__)
41 #define _STDIO_CLOSE_PER_REENT_STD_STREAMS
42 #endif
43 
44 /* The following macros are supposed to replace calls to _flockfile/_funlockfile
45    and __sfp_lock_acquire/__sfp_lock_release.  In case of multi-threaded
46    environments using pthreads, it's not sufficient to lock the stdio functions
47    against concurrent threads accessing the same data, the locking must also be
48    secured against thread cancellation.
49 
50    The below macros have to be used in pairs.  The _newlib_XXX_start macro
51    starts with a opening curly brace, the _newlib_XXX_end macro ends with a
52    closing curly brace, so the start macro and the end macro mark the code
53    start and end of a critical section.  In case the code leaves the critical
54    section before reaching the end of the critical section's code end, use
55    the appropriate _newlib_XXX_exit macro. */
56 
57 #if !defined (__SINGLE_THREAD__) && defined (_POSIX_THREADS) \
58     && !defined (__rtems__)
59 #define _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
60 #endif
61 
62 #if defined(__SINGLE_THREAD__) || defined(__IMPL_UNLOCKED__)
63 
64 # define _newlib_flockfile_start(_fp)
65 # define _newlib_flockfile_exit(_fp)
66 # define _newlib_flockfile_end(_fp)
67 # define _newlib_sfp_lock_start()
68 # define _newlib_sfp_lock_exit()
69 # define _newlib_sfp_lock_end()
70 
71 #elif defined(_STDIO_WITH_THREAD_CANCELLATION_SUPPORT)
72 #include <pthread.h>
73 
74 /* Start a stream oriented critical section: */
75 # define _newlib_flockfile_start(_fp) \
76 	{ \
77 	  int __oldfpcancel; \
78 	  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &__oldfpcancel); \
79 	  if (!(_fp->_flags2 & __SNLK)) \
80 	    _flockfile (_fp)
81 
82 /* Exit from a stream oriented critical section prematurely: */
83 # define _newlib_flockfile_exit(_fp) \
84 	  if (!(_fp->_flags2 & __SNLK)) \
85 	    _funlockfile (_fp); \
86 	  pthread_setcancelstate (__oldfpcancel, &__oldfpcancel);
87 
88 /* End a stream oriented critical section: */
89 # define _newlib_flockfile_end(_fp) \
90 	  if (!(_fp->_flags2 & __SNLK)) \
91 	    _funlockfile (_fp); \
92 	  pthread_setcancelstate (__oldfpcancel, &__oldfpcancel); \
93 	}
94 
95 /* Start a stream list oriented critical section: */
96 # define _newlib_sfp_lock_start() \
97 	{ \
98 	  int __oldsfpcancel; \
99 	  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &__oldsfpcancel); \
100 	  __sfp_lock_acquire ()
101 
102 /* Exit from a stream list oriented critical section prematurely: */
103 # define _newlib_sfp_lock_exit() \
104 	  __sfp_lock_release (); \
105 	  pthread_setcancelstate (__oldsfpcancel, &__oldsfpcancel);
106 
107 /* End a stream list oriented critical section: */
108 # define _newlib_sfp_lock_end() \
109 	  __sfp_lock_release (); \
110 	  pthread_setcancelstate (__oldsfpcancel, &__oldsfpcancel); \
111 	}
112 
113 #else /* !__SINGLE_THREAD__ && !__IMPL_UNLOCKED__ && !_STDIO_WITH_THREAD_CANCELLATION_SUPPORT */
114 
115 # define _newlib_flockfile_start(_fp) \
116 	{ \
117 		if (!(_fp->_flags2 & __SNLK)) \
118 		  _flockfile (_fp)
119 
120 # define _newlib_flockfile_exit(_fp) \
121 		if (!(_fp->_flags2 & __SNLK)) \
122 		  _funlockfile(_fp); \
123 
124 # define _newlib_flockfile_end(_fp) \
125 		if (!(_fp->_flags2 & __SNLK)) \
126 		  _funlockfile(_fp); \
127 	}
128 
129 # define _newlib_sfp_lock_start() \
130 	{ \
131 		__sfp_lock_acquire ()
132 
133 # define _newlib_sfp_lock_exit() \
134 		__sfp_lock_release ();
135 
136 # define _newlib_sfp_lock_end() \
137 		__sfp_lock_release (); \
138 	}
139 
140 #endif /* __SINGLE_THREAD__ || __IMPL_UNLOCKED__ */
141 
142 extern wint_t __fgetwc (FILE *);
143 extern wint_t __fputwc (wchar_t, FILE *);
144 extern unsigned char *__sccl (char *, unsigned char *fmt);
145 extern int    _svfscanf (FILE *, const char *,va_list);
146 extern int    _ssvfscanf (FILE *, const char *,va_list);
147 extern int    _svfiscanf (FILE *, const char *,va_list);
148 extern int    _ssvfiscanf (FILE *, const char *,va_list);
149 extern int    _svfwscanf (FILE *, const wchar_t *,va_list);
150 extern int    _ssvfwscanf (FILE *, const wchar_t *,va_list);
151 extern int    _svfiwscanf (FILE *, const wchar_t *,va_list);
152 extern int    _ssvfiwscanf (FILE *, const wchar_t *,va_list);
153 int	      svfprintf ( FILE *, const char *,
154 				  va_list)
155                			_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
156 int	      svfiprintf ( FILE *, const char *,
157 				  va_list)
158                			_ATTRIBUTE ((__format__ (__printf__, 2, 0)));
159 int	      svfwprintf ( FILE *, const wchar_t *,
160 				  va_list);
161 int	      svfiwprintf ( FILE *, const wchar_t *,
162 				  va_list);
163 extern FILE  *__sfp (void);
164 extern int    __sflags (const char*, int*);
165 extern int    _sflush (FILE *);
166 #ifdef _STDIO_BSD_SEMANTICS
167 extern int    _sflushw (FILE *);
168 #endif
169 extern int    _srefill (FILE *);
170 extern ssize_t __sread (void *, char *,
171 					       size_t);
172 extern ssize_t __seofread (void *,
173 						  char *,
174 						  size_t);
175 extern ssize_t __swrite (void *,
176 						const char *,
177 						size_t);
178 extern _fpos_t __sseek (void *, _fpos_t, int);
179 extern int    __sclose (void *);
180 extern int    __stextmode (int);
181 extern void   __sinit (void);
182 extern void   _smakebuf ( FILE *);
183 extern int    _swhatbuf ( FILE *, size_t *, int *);
184 extern int __submore (FILE *);
185 
186 #ifdef __LARGE64_FILES
187 extern _fpos64_t __sseek64 (void *, _fpos64_t, int);
188 extern ssize_t __swrite64 (void *,
189 						  const char *,
190 						  size_t);
191 #endif
192 
193 extern NEWLIB_THREAD_LOCAL void (*_tls_cleanup)(void);
194 #define _REENT_CLEANUP(_ptr) (_tls_cleanup)
195 extern NEWLIB_THREAD_LOCAL struct _Bigint **_tls_mp_freelist;
196 #define _REENT_MP_FREELIST(_ptr) (_tls_mp_freelist)
197 extern NEWLIB_THREAD_LOCAL struct _Bigint *_tls_mp_p5s;
198 #define _REENT_MP_P5S(_ptr) (_tls_mp_p5s)
199 extern NEWLIB_THREAD_LOCAL struct _Bigint *_tls_mp_result;
200 #define _REENT_MP_RESULT(_ptr) (_tls_mp_result)
201 extern NEWLIB_THREAD_LOCAL int _tls_mp_result_k;
202 #define _REENT_MP_RESULT_K(_ptr) (_tls_mp_result_k)
203 
204 void _reclaim_reent (void *);
205 
206 /* Called by the main entry point fns to ensure stdio has been initialized.  */
207 
208 #define CHECK_INIT(ptr, fp) \
209   do								\
210     {								\
211       if (!_tls_cleanup)			                \
212 	__sinit ();				                \
213     }								\
214   while (0)
215 
216 /* Return true and set errno and stream error flag iff the given FILE
217    cannot be written now.  */
218 
219 #define	cantwrite(ptr, fp)                                     \
220   ((((fp)->_flags & __SWR) == 0 || (fp)->_bf._base == NULL) && \
221    _swsetup( fp))
222 
223 /* Test whether the given stdio file has an active ungetc buffer;
224    release such a buffer, without restoring ordinary unread data.  */
225 
226 #define	HASUB(fp) ((fp)->_ub._base != NULL)
227 #define	FREEUB(ptr, fp) {                    \
228 	if ((fp)->_ub._base != (fp)->_ubuf) \
229 		free((char *)(fp)->_ub._base); \
230 	(fp)->_ub._base = NULL; \
231 }
232 
233 /* Test for an fgetline() buffer.  */
234 
235 #define	HASLB(fp) ((fp)->_lb._base != NULL)
236 #define	FREELB(ptr, fp) { free((char *)(fp)->_lb._base);	\
237       (fp)->_lb._base = NULL; }
238 
239 #ifdef _WIDE_ORIENT
240 /*
241  * Set the orientation for a stream. If o > 0, the stream has wide-
242  * orientation. If o < 0, the stream has byte-orientation.
243  */
244 #ifndef __clang__
245 #pragma GCC diagnostic ignored "-Wunused-value"
246 #endif
247 #define ORIENT(fp,ori)			\
248   (					\
249     (					\
250       ((fp)->_flags & __SORD) ?		\
251 	0				\
252       :					\
253 	(				\
254 	  ((fp)->_flags |= __SORD),	\
255 	  (ori > 0) ?			\
256 	    ((fp)->_flags2 |= __SWID)	\
257 	  :				\
258 	    ((fp)->_flags2 &= ~__SWID)	\
259 	)				\
260     ),					\
261     ((fp)->_flags2 & __SWID) ? 1 : -1	\
262   )
263 #else
264 #define ORIENT(fp,ori) (-1)
265 #endif
266 
267 /* Same thing as the functions in stdio.h, but these are to be called
268    from inside the wide-char functions. */
269 int	__swbufw (int, FILE *);
270 #ifdef __GNUC__
__swputc(int _c,FILE * _p)271 _ELIDABLE_INLINE int __swputc(int _c, FILE *_p) {
272 #ifdef __SCLE
273 	if ((_p->_flags & __SCLE) && _c == '\n')
274 	  __swputc ('\r', _p);
275 #endif
276 	if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
277 		return (*_p->_p++ = _c);
278 	else
279 		return (__swbufw(_c, _p));
280 }
281 #else
282 #define       __swputc_raw(__c, __p) \
283 	(--(__p)->_w < 0 ? \
284 		(__p)->_w >= (__p)->_lbfsize ? \
285 			(*(__p)->_p = (__c)), *(__p)->_p != '\n' ? \
286 				(int)*(__p)->_p++ : \
287 				__swbufw('\n', __p) : \
288 			__swbufw((int)(__c), __p) : \
289 		(*(__p)->_p = (__c), (int)*(__p)->_p++))
290 #ifdef __SCLE
291 #define __swputc(__c, __p) \
292         ((((__p)->_flags & __SCLE) && ((__c) == '\n')) \
293           ? __swputc_raw('\r', (__p)) : 0 , \
294         __swputc_raw((__c), (__p)))
295 #else
296 #define __swputc(__c, __p) __swputc_raw(__c, __p)
297 #endif
298 #endif
299 
300 /* WARNING: _dcvt is defined in the stdlib directory, not here!  */
301 
302 char *_dcvt (char *, double, int, int, char, int);
303 char *_sicvt (char *, short, char);
304 char *_icvt (char *, int, char);
305 char *_licvt (char *, long, char);
306 #ifdef __GNUC__
307 char *_llicvt (char *, long long, char);
308 #endif
309 
310 #define CVT_BUF_SIZE 128
311 
312 #define	NDYNAMIC 4	/* add four more whenever necessary */
313 
314 #ifdef __SINGLE_THREAD__
315 #define __sfp_lock_acquire()
316 #define __sfp_lock_release()
317 #define __sinit_lock_acquire()
318 #define __sinit_lock_release()
319 #else
320 #define __sfp_lock_acquire() __LIBC_LOCK()
321 #define __sfp_lock_release() __LIBC_UNLOCK()
322 #define __sinit_lock_acquire() __LIBC_LOCK()
323 #define __sinit_lock_release() __LIBC_UNLOCK()
324 #endif
325 
326 /* Types used in positional argument support in vfprinf/vfwprintf.
327    The implementation is char/wchar_t dependent but the class and state
328    tables are only defined once in vfprintf.c. */
329 typedef enum __packed {
330   ZERO,   /* '0' */
331   DIGIT,  /* '1-9' */
332   DOLLAR, /* '$' */
333   MODFR,  /* spec modifier */
334   SPEC,   /* format specifier */
335   DOT,    /* '.' */
336   STAR,   /* '*' */
337   FLAG,   /* format flag */
338   OTHER,  /* all other chars */
339   MAX_CH_CLASS /* place-holder */
340 } __CH_CLASS;
341 
342 typedef enum __packed {
343   START,  /* start */
344   SFLAG,  /* seen a flag */
345   WDIG,   /* seen digits in width area */
346   WIDTH,  /* processed width */
347   SMOD,   /* seen spec modifier */
348   SDOT,   /* seen dot */
349   VARW,   /* have variable width specifier */
350   VARP,   /* have variable precision specifier */
351   PREC,   /* processed precision */
352   VWDIG,  /* have digits in variable width specification */
353   VPDIG,  /* have digits in variable precision specification */
354   DONE,   /* done */
355   MAX_STATE, /* place-holder */
356 } __STATE;
357 
358 typedef enum __packed {
359   NOOP,  /* do nothing */
360   NUMBER, /* build a number from digits */
361   SKIPNUM, /* skip over digits */
362   GETMOD,  /* get and process format modifier */
363   GETARG,  /* get and process argument */
364   GETPW,   /* get variable precision or width */
365   GETPWB,  /* get variable precision or width and pushback fmt char */
366   GETPOS,  /* get positional parameter value */
367   PWPOS,   /* get positional parameter value for variable width or precision */
368 } __ACTION;
369 
370 extern const __CH_CLASS __chclass[256];
371 extern const __STATE __state_table[MAX_STATE][MAX_CH_CLASS];
372 extern const __ACTION __action_table[MAX_STATE][MAX_CH_CLASS];
373