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