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