diff options
author | Corinna Vinschen <vinschen@redhat.com> | 2006-10-19 08:39:44 +0000 |
---|---|---|
committer | Corinna Vinschen <vinschen@redhat.com> | 2006-10-19 08:39:44 +0000 |
commit | 335ac4f0e9b2cfd42947e1ee20f6cd58a1ff457e (patch) | |
tree | 88fe45768802928d0421520b41af82d3af0423a8 /newlib/libc | |
parent | b688de33249272dfb353ccd61bcf4b681337a0f5 (diff) | |
download | gdb-335ac4f0e9b2cfd42947e1ee20f6cd58a1ff457e.tar.gz |
Apply the following mainline patches to cr-0x5f1 branch:
2006-10-11 Yang Tse <yangsita@gmail.com>
* libc/include/machine/setjmp.h: Use __extension__ keyword for gcc's
braced-groups.
2006-10-11 Corinna Vinschen <corinna@vinschen.de>
* libc/reent/reeent.c (_reclaim_reent): Free _REENT_MP_RESULT.
2006-09-13 Patrick Mansfield <patmans@us.ibm.com>
* libc/include/math.h: Remove _CONST from _LIB_VERSION, as it is
supposed to be writable.
* libm/common/s_lib_ver.c: Ditto.
2006-09-06 Eric Blake <ebb9@byu.net>
* libc/stdio/vfprintf.c (_vfprintf_r, get_arg): Add 'hh', 'j',
't', and 'z' modifiers.
2006-08-22 Eric Blake <ebb9@byu.net>
* libc/posix/popen.c (popen): Don't close output end of pipe in
child if stdout was closed on entry.
[HAVE_FCNTL]: In parent, mark file as close-on-exec, per POSIX.
2006-08-17 Brian Ford <Brian.Ford@FlightSafety.com>
* libc/time/gmtime.c: Correct man page; clock is not a
local time and no conversion occurs.
Diffstat (limited to 'newlib/libc')
-rw-r--r-- | newlib/libc/include/machine/setjmp.h | 293 | ||||
-rw-r--r-- | newlib/libc/include/math.h | 424 | ||||
-rw-r--r-- | newlib/libc/posix/popen.c | 184 | ||||
-rw-r--r-- | newlib/libc/reent/reent.c | 147 | ||||
-rw-r--r-- | newlib/libc/stdio/vfprintf.c | 1875 | ||||
-rw-r--r-- | newlib/libc/time/gmtime.c | 66 |
6 files changed, 2989 insertions, 0 deletions
diff --git a/newlib/libc/include/machine/setjmp.h b/newlib/libc/include/machine/setjmp.h new file mode 100644 index 00000000000..3c9b6be831d --- /dev/null +++ b/newlib/libc/include/machine/setjmp.h @@ -0,0 +1,293 @@ + +_BEGIN_STD_C + +#if defined(__arm__) || defined(__thumb__) +/* + * All callee preserved registers: + * v1 - v7, fp, ip, sp, lr, f4, f5, f6, f7 + */ +#define _JBLEN 23 +#endif + +#if defined(__AVR__) +#define _JBLEN 24 +#endif + +#ifdef __sparc__ +/* + * onsstack,sigmask,sp,pc,npc,psr,g1,o0,wbcnt (sigcontext). + * All else recovered by under/over(flow) handling. + */ +#define _JBLEN 13 +#endif + +/* necv70 was 9 as well. */ + +#ifdef __mc68000__ +/* + * onsstack,sigmask,sp,pc,psl,d2-d7,a2-a6, + * fp2-fp7 for 68881. + * All else recovered by under/over(flow) handling. + */ +#define _JBLEN 34 +#endif + +#if defined(__mc68hc11__) || defined(__mc68hc12__) || defined(__mc68hc1x__) +/* + * D, X, Y are not saved. + * Only take into account the pseudo soft registers (max 32). + */ +#define _JBLEN 32 +#endif + +#if defined(__Z8001__) || defined(__Z8002__) +/* 16 regs + pc */ +#define _JBLEN 20 +#endif + +#ifdef _AM29K +/* + * onsstack,sigmask,sp,pc,npc,psr,g1,o0,wbcnt (sigcontext). + * All else recovered by under/over(flow) handling. + */ +#define _JBLEN 9 +#endif + +#if defined(__CYGWIN__) && !defined (_JBLEN) +#define _JBLEN (13 * 4) +#elif defined (__i386__) +#if defined(__unix__) || defined(__rtems__) +# define _JBLEN 9 +#else +#include "setjmp-dj.h" +#endif +#endif + +#ifdef __i960__ +#define _JBLEN 35 +#endif + +#ifdef __M32R__ +/* Only 8 words are currently needed. 10 gives us some slop if we need + to expand. */ +#define _JBLEN 10 +#endif + +#ifdef __mips__ +#ifdef __mips64 +#define _JBTYPE long long +#endif +#ifdef __mips_soft_float +#define _JBLEN 11 +#else +#define _JBLEN 23 +#endif +#endif + +#ifdef __m88000__ +#define _JBLEN 21 +#endif + +#ifdef __H8300__ +#define _JBLEN 5 +#define _JBTYPE int +#endif + +#ifdef __H8300H__ +/* same as H8/300 but registers are twice as big */ +#define _JBLEN 5 +#define _JBTYPE long +#endif + +#if defined (__H8300S__) || defined (__H8300SX__) +/* same as H8/300 but registers are twice as big */ +#define _JBLEN 5 +#define _JBTYPE long +#endif + +#ifdef __H8500__ +#define _JBLEN 4 +#endif + +#ifdef __sh__ +#if __SH5__ +#define _JBLEN 50 +#define _JBTYPE long long +#else +#define _JBLEN 20 +#endif /* __SH5__ */ +#endif + +#ifdef __v800 +#define _JBLEN 28 +#endif + +#ifdef __PPC__ +#ifdef __ALTIVEC__ +#define _JBLEN 64 +#else +#define _JBLEN 32 +#endif +#define _JBTYPE double +#endif + +#ifdef __hppa__ +/* %r30, %r2-%r18, %r27, pad, %fr12-%fr15. + Note space exists for the FP registers, but they are not + saved. */ +#define _JBLEN 28 +#endif + +#if defined(__mn10300__) || defined(__mn10200__) +#ifdef __AM33_2__ +#define _JBLEN 26 +#else +/* A guess */ +#define _JBLEN 10 +#endif +#endif + +#ifdef __v850 +/* I think our setjmp is saving 15 regs at the moment. Gives us one word + slop if we need to expand. */ +#define _JBLEN 16 +#endif + +#if defined(_C4x) +#define _JBLEN 10 +#endif +#if defined(_C3x) +#define _JBLEN 9 +#endif + +#ifdef __TIC80__ +#define _JBLEN 13 +#endif + +#ifdef __D10V__ +#define _JBLEN 8 +#endif + +#ifdef __D30V__ +#define _JBLEN ((64 /* GPR */ + (2*2) /* ACs */ + 18 /* CRs */) / 2) +#define _JBTYPE double +#endif + +#ifdef __frv__ +#define _JBLEN (68/2) /* room for 68 32-bit regs */ +#define _JBTYPE double +#endif + +#ifdef __CRX__ +#define _JBLEN 9 +#endif + +#ifdef __fr30__ +#define _JBLEN 10 +#endif + +#ifdef __iq2000__ +#define _JBLEN 32 +#endif + +#ifdef __mcore__ +#define _JBLEN 16 +#endif + +#ifdef __MMIX__ +/* Using a layout compatible with GCC's built-in. */ +#define _JBLEN 5 +#define _JBTYPE unsigned long +#endif + +#ifdef __mt__ +#define _JBLEN 16 +#endif + +#ifdef __SPU__ +#define _JBLEN 50 +#define _JBTYPE __attribute__ (( __vector_size__ (16) )) int +#endif + +#ifdef __xstormy16__ +/* 4 GPRs plus SP plus PC. */ +#define _JBLEN 8 +#endif + +#ifdef __CRIS__ +#define _JBLEN 18 +#endif + +#ifdef __m32c__ +#if defined(__r8c_cpu__) || defined(__m16c_cpu__) +#define _JBLEN (22/2) +#else +#define _JBLEN (34/2) +#endif +#define _JBTYPE unsigned short +#endif /* __m32c__ */ + +#ifdef _JBLEN +#ifdef _JBTYPE +typedef _JBTYPE jmp_buf[_JBLEN]; +#else +typedef int jmp_buf[_JBLEN]; +#endif +#endif + +_END_STD_C + +#if defined(__CYGWIN__) || defined(__rtems__) +#include <signal.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX sigsetjmp/siglongjmp macros */ +typedef int sigjmp_buf[_JBLEN+2]; + +#define _SAVEMASK _JBLEN +#define _SIGMASK (_JBLEN+1) + +#ifdef __CYGWIN__ +# define _CYGWIN_WORKING_SIGSETJMP +#endif + +#if defined(__GNUC__) + +#define sigsetjmp(env, savemask) \ + __extension__ \ + ({ \ + sigjmp_buf *_sjbuf = &(env); \ + ((*_sjbuf)[_SAVEMASK] = savemask,\ + sigprocmask (SIG_SETMASK, 0, (sigset_t *)((*_sjbuf) + _SIGMASK)),\ + setjmp (*_sjbuf)); \ + }) + +#define siglongjmp(env, val) \ + __extension__ \ + ({ \ + sigjmp_buf *_sjbuf = &(env); \ + ((((*_sjbuf)[_SAVEMASK]) ? \ + sigprocmask (SIG_SETMASK, (sigset_t *)((*_sjbuf) + _SIGMASK), 0)\ + : 0), \ + longjmp (*_sjbuf, val)); \ + }) + +#else /* !__GNUC__ */ + +#define sigsetjmp(env, savemask) ((env)[_SAVEMASK] = savemask,\ + sigprocmask (SIG_SETMASK, 0, (sigset_t *) ((env) + _SIGMASK)),\ + setjmp (env)) + +#define siglongjmp(env, val) ((((env)[_SAVEMASK])?\ + sigprocmask (SIG_SETMASK, (sigset_t *) ((env) + _SIGMASK), 0):0),\ + longjmp (env, val)) + +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __CYGWIN__ or __rtems__ */ diff --git a/newlib/libc/include/math.h b/newlib/libc/include/math.h new file mode 100644 index 00000000000..2e1533ad8ae --- /dev/null +++ b/newlib/libc/include/math.h @@ -0,0 +1,424 @@ + +#ifndef _MATH_H_ +#define _MATH_H_ + +#include <sys/reent.h> +#include <machine/ieeefp.h> +#include "_ansi.h" + +_BEGIN_STD_C + +union __dmath +{ + __ULong i[2]; + double d; +}; + +union __fmath +{ + __ULong i[1]; + float f; +}; + +union __ldmath +{ + __ULong i[4]; + _LONG_DOUBLE ld; +}; + +#if defined(__GNUC__) && \ + ( (__GNUC__ >= 4) || \ + ( (__GNUC__ >= 3) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 3) ) ) + + /* gcc >= 3.3 implicitly defines builtins for HUGE_VALx values. */ + + #ifndef HUGE_VAL + #define HUGE_VAL (__builtin_huge_val()) + #endif + + #ifndef HUGE_VALF + #define HUGE_VALF (__builtin_huge_valf()) + #endif + + #ifndef HUGE_VALL + #define HUGE_VALL (__builtin_huge_vall()) + #endif + +#else /* !gcc >= 3.3 */ + + /* No builtins. Use floating-point unions instead. Declare as an array + without bounds so no matter what small data support a port and/or + library has, the reference will be via the general method for accessing + globals. */ + + #ifndef HUGE_VAL + extern __IMPORT const union __dmath __infinity[]; + #define HUGE_VAL (__infinity[0].d) + #endif + + #ifndef HUGE_VALF + extern __IMPORT const union __fmath __infinityf[]; + #define HUGE_VALF (__infinityf[0].f) + #endif + + #ifndef HUGE_VALL + extern __IMPORT const union __ldmath __infinityld[]; + #define HUGE_VALL (__infinityld[0].ld) + #endif + +#endif /* !gcc >= 3.3 */ + +/* Reentrant ANSI C functions. */ + +#ifndef __math_68881 +extern double atan _PARAMS((double)); +extern double cos _PARAMS((double)); +extern double sin _PARAMS((double)); +extern double tan _PARAMS((double)); +extern double tanh _PARAMS((double)); +extern double frexp _PARAMS((double, int *)); +extern double modf _PARAMS((double, double *)); +extern double ceil _PARAMS((double)); +extern double fabs _PARAMS((double)); +extern double floor _PARAMS((double)); +#endif /* ! defined (__math_68881) */ + +/* Non reentrant ANSI C functions. */ + +#ifndef _REENT_ONLY +#ifndef __math_6881 +extern double acos _PARAMS((double)); +extern double asin _PARAMS((double)); +extern double atan2 _PARAMS((double, double)); +extern double cosh _PARAMS((double)); +extern double sinh _PARAMS((double)); +extern double exp _PARAMS((double)); +extern double ldexp _PARAMS((double, int)); +extern double log _PARAMS((double)); +extern double log10 _PARAMS((double)); +extern double pow _PARAMS((double, double)); +extern double sqrt _PARAMS((double)); +extern double fmod _PARAMS((double, double)); +#endif /* ! defined (__math_68881) */ +#endif /* ! defined (_REENT_ONLY) */ + +#ifndef __STRICT_ANSI__ + +/* ISO C99 types and macros. */ + +#ifndef FLT_EVAL_METHOD +#define FLT_EVAL_METHOD 0 +typedef float float_t; +typedef double double_t; +#endif /* FLT_EVAL_METHOD */ + +#define FP_NAN 0 +#define FP_INFINITE 1 +#define FP_ZERO 2 +#define FP_SUBNORMAL 3 +#define FP_NORMAL 4 + +extern int __isinff (float x); +extern int __isinfd (double x); +extern int __isnanf (float x); +extern int __isnand (double x); +extern int __fpclassifyf (float x); +extern int __fpclassifyd (double x); +extern int __signbitf (float x); +extern int __signbitd (double x); + +#define fpclassify(x) \ + (__extension__ ({__typeof__(x) __x = (x); \ + (sizeof (__x) == sizeof (float)) ? __fpclassifyf(__x) : __fpclassifyd(__x);})) + +#define isfinite(y) \ + (__extension__ ({__typeof__(y) __y = (y); \ + fpclassify(__y) != FP_INFINITE && fpclassify(__y) != FP_NAN;})) + +/* Note: isinf and isnan were once functions in newlib that took double + * arguments. C99 specifies that these names are reserved for macros + * supporting multiple floating point types. Thus, they are + * now defined as macros. Implementations of the old functions + * taking double arguments still exist for compatibility purposes. */ +#define isinf(x) \ + (__extension__ ({__typeof__(x) __x = (x); \ + (sizeof (__x) == sizeof (float)) ? __isinff(__x) : __isinfd(__x);})) +#define isnan(x) \ + (__extension__ ({__typeof__(x) __x = (x); \ + (sizeof (__x) == sizeof (float)) ? __isnanf(__x) : __isnand(__x);})) +#define isnormal(y) (fpclassify(y) == FP_NORMAL) +#define signbit(x) \ + (__extension__ ({__typeof__(x) __x = (x); \ + (sizeof(__x) == sizeof(float)) ? __signbitf(__x) : __signbitd(__x);})) + +#define isgreater(x,y) \ + (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x,__y) && (__x > __y);})) +#define isgreaterequal(x,y) \ + (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x,__y) && (__x >= __y);})) +#define isless(x,y) \ + (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x,__y) && (__x < __y);})) +#define islessequal(x,y) \ + (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x,__y) && (__x <= __y);})) +#define islessgreater(x,y) \ + (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ + !isunordered(__x,__y) && (__x < __y || __x > __y);})) + +#define isunordered(a,b) \ + (__extension__ ({__typeof__(a) __a = (a); __typeof__(b) __b = (b); \ + fpclassify(__a) == FP_NAN || fpclassify(__b) == FP_NAN;})) + +/* Non ANSI double precision functions. */ + +extern double infinity _PARAMS((void)); +extern double nan _PARAMS((const char *)); +extern int finite _PARAMS((double)); +extern double copysign _PARAMS((double, double)); +extern int ilogb _PARAMS((double)); + +extern double asinh _PARAMS((double)); +extern double cbrt _PARAMS((double)); +extern double nextafter _PARAMS((double, double)); +extern double rint _PARAMS((double)); +extern double scalbn _PARAMS((double, int)); + +extern double exp2 _PARAMS((double)); +extern double scalbln _PARAMS((double, long int)); +extern double tgamma _PARAMS((double)); +extern double nearbyint _PARAMS((double)); +extern long int lrint _PARAMS((double)); +extern double round _PARAMS((double)); +extern long int lround _PARAMS((double)); +extern double trunc _PARAMS((double)); +extern double remquo _PARAMS((double, double, int *)); +extern double copysign _PARAMS((double, double)); +extern double fdim _PARAMS((double, double)); +extern double fmax _PARAMS((double, double)); +extern double fmin _PARAMS((double, double)); +extern double fma _PARAMS((double, double, double)); +extern void sincos _PARAMS((double, double *, double *)); + +#ifndef __math_68881 +extern double log1p _PARAMS((double)); +extern double expm1 _PARAMS((double)); +#endif /* ! defined (__math_68881) */ + +#ifndef _REENT_ONLY +extern double acosh _PARAMS((double)); +extern double atanh _PARAMS((double)); +extern double remainder _PARAMS((double, double)); +extern double gamma _PARAMS((double)); +extern double gamma_r _PARAMS((double, int *)); +extern double lgamma _PARAMS((double)); +extern double lgamma_r _PARAMS((double, int *)); +extern double erf _PARAMS((double)); +extern double erfc _PARAMS((double)); +extern double y0 _PARAMS((double)); +extern double y1 _PARAMS((double)); +extern double yn _PARAMS((int, double)); +extern double j0 _PARAMS((double)); +extern double j1 _PARAMS((double)); +extern double jn _PARAMS((int, double)); +#define log2(x) (log (x) / M_LOG2_E) + +#ifndef __math_68881 +extern double hypot _PARAMS((double, double)); +#endif + +extern double cabs(); +extern double drem _PARAMS((double, double)); + +#endif /* ! defined (_REENT_ONLY) */ + +#endif /* ! defined (__STRICT_ANSI__) */ + +#if !defined(__STRICT_ANSI__) || defined(__cplusplus) + +/* Single precision versions of ANSI functions. */ + +extern float atanf _PARAMS((float)); +extern float cosf _PARAMS((float)); +extern float sinf _PARAMS((float)); +extern float tanf _PARAMS((float)); +extern float tanhf _PARAMS((float)); +extern float frexpf _PARAMS((float, int *)); +extern float modff _PARAMS((float, float *)); +extern float ceilf _PARAMS((float)); +extern float fabsf _PARAMS((float)); +extern float floorf _PARAMS((float)); + +#ifndef _REENT_ONLY +extern float acosf _PARAMS((float)); +extern float asinf _PARAMS((float)); +extern float atan2f _PARAMS((float, float)); +extern float coshf _PARAMS((float)); +extern float sinhf _PARAMS((float)); +extern float expf _PARAMS((float)); +extern float ldexpf _PARAMS((float, int)); +extern float logf _PARAMS((float)); +extern float log10f _PARAMS((float)); +extern float powf _PARAMS((float, float)); +extern float sqrtf _PARAMS((float)); +extern float fmodf _PARAMS((float, float)); +#endif /* ! defined (_REENT_ONLY) */ + +#endif /* !defined(__STRICT_ANSI__) || defined(__cplusplus) */ + +#ifndef __STRICT_ANSI__ + +/* Other single precision functions. */ + +extern float exp2f _PARAMS((float)); +extern float scalblnf _PARAMS((float, long int)); +extern float tgammaf _PARAMS((float)); +extern float nearbyintf _PARAMS((float)); +extern long int lrintf _PARAMS((float)); +extern float roundf _PARAMS((float)); +extern long int lroundf _PARAMS((float)); +extern float truncf _PARAMS((float)); +extern float remquof _PARAMS((float, float, int *)); +extern float copysignf _PARAMS((float, float)); +extern float fdimf _PARAMS((float, float)); +extern float fmaxf _PARAMS((float, float)); +extern float fminf _PARAMS((float, float)); +extern float fmaf _PARAMS((float, float, float)); + +extern float infinityf _PARAMS((void)); +extern float nanf _PARAMS((const char *)); +extern int isnanf _PARAMS((float)); +extern int isinff _PARAMS((float)); +extern int finitef _PARAMS((float)); +extern float copysignf _PARAMS((float, float)); +extern int ilogbf _PARAMS((float)); + +extern float asinhf _PARAMS((float)); +extern float cbrtf _PARAMS((float)); +extern float nextafterf _PARAMS((float, float)); +extern float rintf _PARAMS((float)); +extern float scalbnf _PARAMS((float, int)); +extern float log1pf _PARAMS((float)); +extern float expm1f _PARAMS((float)); +extern void sincosf _PARAMS((float, float *, float *)); + +#ifndef _REENT_ONLY +extern float acoshf _PARAMS((float)); +extern float atanhf _PARAMS((float)); +extern float remainderf _PARAMS((float, float)); +extern float gammaf _PARAMS((float)); +extern float gammaf_r _PARAMS((float, int *)); +extern float lgammaf _PARAMS((float)); +extern float lgammaf_r _PARAMS((float, int *)); +extern float erff _PARAMS((float)); +extern float erfcf _PARAMS((float)); +extern float y0f _PARAMS((float)); +extern float y1f _PARAMS((float)); +extern float ynf _PARAMS((int, float)); +extern float j0f _PARAMS((float)); +extern float j1f _PARAMS((float)); +extern float jnf _PARAMS((int, float)); +#define log2f(x) (logf (x) / (float) M_LOG2_E) +extern float hypotf _PARAMS((float, float)); + +extern float cabsf(); +extern float dremf _PARAMS((float, float)); + +#endif /* ! defined (_REENT_ONLY) */ + +/* The gamma functions use a global variable, signgam. */ +#ifndef _REENT_ONLY +#define signgam (*__signgam()) +extern int *__signgam _PARAMS((void)); +#endif /* ! defined (_REENT_ONLY) */ + +#define __signgam_r(ptr) _REENT_SIGNGAM(ptr) + +/* The exception structure passed to the matherr routine. */ + +#ifdef __cplusplus +struct __exception +#else +struct exception +#endif +{ + int type; + char *name; + double arg1; + double arg2; + double retval; + int err; +}; + +#ifdef __cplusplus +extern int matherr _PARAMS((struct __exception *e)); +#else +extern int matherr _PARAMS((struct exception *e)); +#endif + +/* Values for the type field of struct exception. */ + +#define DOMAIN 1 +#define SING 2 +#define OVERFLOW 3 +#define UNDERFLOW 4 +#define TLOSS 5 +#define PLOSS 6 + +/* Useful constants. */ + +#define MAXFLOAT 3.40282347e+38F + +#define M_E 2.7182818284590452354 +#define M_LOG2E 1.4426950408889634074 +#define M_LOG10E 0.43429448190325182765 +#define M_LN2 0.69314718055994530942 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_TWOPI (M_PI * 2.0) +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.78539816339744830962 +#define M_3PI_4 2.3561944901923448370E0 +#define M_SQRTPI 1.77245385090551602792981 +#define M_1_PI 0.31830988618379067154 +#define M_2_PI 0.63661977236758134308 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT1_2 0.70710678118654752440 +#define M_LN2LO 1.9082149292705877000E-10 +#define M_LN2HI 6.9314718036912381649E-1 +#define M_SQRT3 1.73205080756887719000 +#define M_IVLN10 0.43429448190325182765 /* 1 / log(10) */ +#define M_LOG2_E 0.693147180559945309417 +#define M_INVLN2 1.4426950408889633870E0 /* 1 / log(2) */ + +/* Global control over fdlibm error handling. */ + +enum __fdlibm_version +{ + __fdlibm_ieee = -1, + __fdlibm_svid, + __fdlibm_xopen, + __fdlibm_posix +}; + +#define _LIB_VERSION_TYPE enum __fdlibm_version +#define _LIB_VERSION __fdlib_version + +extern __IMPORT _LIB_VERSION_TYPE _LIB_VERSION; + +#define _IEEE_ __fdlibm_ieee +#define _SVID_ __fdlibm_svid +#define _XOPEN_ __fdlibm_xopen +#define _POSIX_ __fdlibm_posix + +#endif /* ! defined (__STRICT_ANSI__) */ + +_END_STD_C + +#ifdef __FAST_MATH__ +#include <machine/fastmath.h> +#endif + +#endif /* _MATH_H_ */ diff --git a/newlib/libc/posix/popen.c b/newlib/libc/posix/popen.c new file mode 100644 index 00000000000..2d3777133ff --- /dev/null +++ b/newlib/libc/posix/popen.c @@ -0,0 +1,184 @@ +/* $NetBSD: popen.c,v 1.11 1995/06/16 07:05:33 jtc Exp $ */ + +/* + * Copyright (c) 1988, 1993, 2006 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software written by Ken Arnold and + * published in UNIX Review, Vol. 6, No. 8. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: popen.c,v 1.11 1995/06/16 07:05:33 jtc Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <paths.h> +#include <fcntl.h> + +static struct pid { + struct pid *next; + FILE *fp; + pid_t pid; +} *pidlist; + +FILE * +_DEFUN(popen, (program, type), + const char *program _AND + const char *type) +{ + struct pid *cur; + FILE *iop; + int pdes[2], pid; + + if ((*type != 'r' && *type != 'w') + || (type[1] +#ifdef __CYGWIN__ + && (type[2] || (type[1] != 'b' && type[1] != 't')) +#endif + )) { + errno = EINVAL; + return (NULL); + } + + if ((cur = malloc(sizeof(struct pid))) == NULL) + return (NULL); + + if (pipe(pdes) < 0) { + free(cur); + return (NULL); + } + + switch (pid = vfork()) { + case -1: /* Error. */ + (void)close(pdes[0]); + (void)close(pdes[1]); + free(cur); + return (NULL); + /* NOTREACHED */ + case 0: /* Child. */ + if (*type == 'r') { + if (pdes[1] != STDOUT_FILENO) { + (void)dup2(pdes[1], STDOUT_FILENO); + (void)close(pdes[1]); + } + if (pdes[0] != STDOUT_FILENO) { + (void) close(pdes[0]); + } + } else { + if (pdes[0] != STDIN_FILENO) { + (void)dup2(pdes[0], STDIN_FILENO); + (void)close(pdes[0]); + } + (void)close(pdes[1]); + } + execl(_PATH_BSHELL, "sh", "-c", program, NULL); +#ifdef __CYGWIN__ + /* On cygwin32, we may not have /bin/sh. In that + case, try to find sh on PATH. */ + execlp("sh", "sh", "-c", program, NULL); +#endif + _exit(127); + /* NOTREACHED */ + } + + /* Parent; assume fdopen can't fail. */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + (void)close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + (void)close(pdes[0]); + } + +#ifdef HAVE_FCNTL + /* Hide pipe from future popens; assume fcntl can't fail. */ + fcntl (fileno (iop), F_SETFD, + fcntl (fileno (iop), F_GETFD, 0) | FD_CLOEXEC); +#endif /* HAVE_FCNTL */ + + /* Link into list of file descriptors. */ + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; + + return (iop); +} + +/* + * pclose -- + * Pclose returns -1 if stream is not associated with a `popened' command, + * if already `pclosed', or waitpid returns an error. + */ +int +_DEFUN(pclose, (iop), + FILE *iop) +{ + register struct pid *cur, *last; + int pstat; + pid_t pid; + + (void)fclose(iop); + + /* Find the appropriate file pointer. */ + for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) + if (cur->fp == iop) + break; + if (cur == NULL) + return (-1); + + do { + pid = waitpid(cur->pid, &pstat, 0); + } while (pid == -1 && errno == EINTR); + + /* Remove the entry from the linked list. */ + if (last == NULL) + pidlist = cur->next; + else + last->next = cur->next; + free(cur); + + return (pid == -1 ? -1 : pstat); +} diff --git a/newlib/libc/reent/reent.c b/newlib/libc/reent/reent.c new file mode 100644 index 00000000000..5270ef6eb31 --- /dev/null +++ b/newlib/libc/reent/reent.c @@ -0,0 +1,147 @@ +/* +FUNCTION + <<reent>>---definition of impure data. + +INDEX + reent + +DESCRIPTION + This module defines the impure data area used by the + non-reentrant functions, such as strtok. +*/ + +#include <stdlib.h> +#include <reent.h> + +#ifdef _REENT_ONLY +#ifndef REENTRANT_SYSCALLS_PROVIDED +#define REENTRANT_SYSCALLS_PROVIDED +#endif +#endif + +#ifndef REENTRANT_SYSCALLS_PROVIDED + +/* We use the errno variable used by the system dependent layer. */ +#undef errno +int errno; + +#endif + +/* Interim cleanup code */ + +void +_DEFUN (cleanup_glue, (ptr, glue), + struct _reent *ptr _AND + struct _glue *glue) +{ + /* Have to reclaim these in reverse order: */ + if (glue->_next) + cleanup_glue (ptr, glue->_next); + + _free_r (ptr, glue); +} + +void +_DEFUN (_reclaim_reent, (ptr), + struct _reent *ptr) +{ + if (ptr != _impure_ptr) + { + /* used by mprec routines. */ +#ifdef _REENT_SMALL + if (ptr->_mp) /* don't bother allocating it! */ +#endif + if (_REENT_MP_FREELIST(ptr)) + { + int i; + for (i = 0; i < 15 /* _Kmax */; i++) + { + struct _Bigint *thisone, *nextone; + + nextone = _REENT_MP_FREELIST(ptr)[i]; + while (nextone) + { + thisone = nextone; + nextone = nextone->_next; + _free_r (ptr, thisone); + } + } + + _free_r (ptr, _REENT_MP_FREELIST(ptr)); + } + if (_REENT_MP_RESULT(ptr)) + _free_r (ptr, _REENT_MP_RESULT(ptr)); + +#ifdef _REENT_SMALL + if (ptr->_emergency) + _free_r (ptr, ptr->_emergency); + if (ptr->_mp) + _free_r (ptr, ptr->_mp); + if (ptr->_r48) + _free_r (ptr, ptr->_r48); + if (ptr->_localtime_buf) + _free_r (ptr, ptr->_localtime_buf); + if (ptr->_asctime_buf) + _free_r (ptr, ptr->_asctime_buf); + if (ptr->_atexit->_on_exit_args_ptr) + _free_r (ptr, ptr->_atexit->_on_exit_args_ptr); +#else + /* atexit stuff */ + if ((ptr->_atexit) && (ptr->_atexit != &ptr->_atexit0)) + { + struct _atexit *p, *q; + for (p = ptr->_atexit; p != &ptr->_atexit0;) + { + q = p; + p = p->_next; + _free_r (ptr, q); + } + } +#endif + + if (ptr->_cvtbuf) + _free_r (ptr, ptr->_cvtbuf); + + if (ptr->__sdidinit) + { + /* cleanup won't reclaim memory 'coz usually it's run + before the program exits, and who wants to wait for that? */ + ptr->__cleanup (ptr); + + if (ptr->__sglue._next) + cleanup_glue (ptr, ptr->__sglue._next); + } + + /* Malloc memory not reclaimed; no good way to return memory anyway. */ + + } +} + +/* + * Do atexit() processing and cleanup + * + * NOTE: This is to be executed at task exit. It does not tear anything + * down which is used on a global basis. + */ + +void +_DEFUN (_wrapup_reent, (ptr), struct _reent *ptr) +{ + register struct _atexit *p; + register int n; + + if (ptr == 0) + ptr = _REENT; + +#ifdef _REENT_SMALL + for (p = &ptr->_atexit, n = p->_ind; --n >= 0;) + (*p->_fns[n]) (); +#else + for (p = ptr->_atexit; p; p = p->_next) + for (n = p->_ind; --n >= 0;) + (*p->_fns[n]) (); +#endif + if (ptr->__cleanup) + (*ptr->__cleanup) (ptr); +} + diff --git a/newlib/libc/stdio/vfprintf.c b/newlib/libc/stdio/vfprintf.c new file mode 100644 index 00000000000..9e5477aa6fc --- /dev/null +++ b/newlib/libc/stdio/vfprintf.c @@ -0,0 +1,1875 @@ +/* + * Copyright (c) 1990, 2006 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* +FUNCTION +<<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list + +INDEX + vprintf +INDEX + vfprintf +INDEX + vsprintf +INDEX + vsnprintf + +ANSI_SYNOPSIS + #include <stdio.h> + #include <stdarg.h> + int vprintf(const char *<[fmt]>, va_list <[list]>); + int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>); + int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>); + int vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>); + int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>, + va_list <[list]>); + + int _vprintf_r(struct _reent *<[reent]>, const char *<[fmt]>, + va_list <[list]>); + int _vfprintf_r(struct _reent *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, + va_list <[list]>); + int _vasprintf_r(struct _reent *<[reent]>, char **<[str]>, + const char *<[fmt]>, va_list <[list]>); + int _vsprintf_r(struct _reent *<[reent]>, char *<[str]>, + const char *<[fmt]>, va_list <[list]>); + int _vsnprintf_r(struct _reent *<[reent]>, char *<[str]>, size_t <[size]>, + const char *<[fmt]>, va_list <[list]>); + +TRAD_SYNOPSIS + #include <stdio.h> + #include <varargs.h> + int vprintf( <[fmt]>, <[list]>) + char *<[fmt]>; + va_list <[list]>; + + int vfprintf(<[fp]>, <[fmt]>, <[list]>) + FILE *<[fp]>; + char *<[fmt]>; + va_list <[list]>; + + int vasprintf(<[strp]>, <[fmt]>, <[list]>) + char **<[strp]>; + char *<[fmt]>; + va_list <[list]>; + + int vsprintf(<[str]>, <[fmt]>, <[list]>) + char *<[str]>; + char *<[fmt]>; + va_list <[list]>; + + int vsnprintf(<[str]>, <[size]>, <[fmt]>, <[list]>) + char *<[str]>; + size_t <[size]>; + char *<[fmt]>; + va_list <[list]>; + + int _vprintf_r(<[reent]>, <[fmt]>, <[list]>) + struct _reent *<[reent]>; + char *<[fmt]>; + va_list <[list]>; + + int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>) + struct _reent *<[reent]>; + FILE *<[fp]>; + char *<[fmt]>; + va_list <[list]>; + + int _vasprintf_r(<[reent]>, <[strp]>, <[fmt]>, <[list]>) + struct _reent *<[reent]>; + char **<[strp]>; + char *<[fmt]>; + va_list <[list]>; + + int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>) + struct _reent *<[reent]>; + char *<[str]>; + char *<[fmt]>; + va_list <[list]>; + + int _vsnprintf_r(<[reent]>, <[str]>, <[size]>, <[fmt]>, <[list]>) + struct _reent *<[reent]>; + char *<[str]>; + size_t <[size]>; + char *<[fmt]>; + va_list <[list]>; + +DESCRIPTION +<<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>> and <<vsnprintf>> are +(respectively) variants of <<printf>>, <<fprintf>>, <<asprintf>>, <<sprintf>>, +and <<snprintf>>. They differ only in allowing their caller to pass the +variable argument list as a <<va_list>> object (initialized by <<va_start>>) +rather than directly accepting a variable number of arguments. + +RETURNS +The return values are consistent with the corresponding functions: +<<vasprintf>>/<<vsprintf>> returns the number of bytes in the output string, +save that the concluding <<NULL>> is not counted. +<<vprintf>> and <<vfprintf>> return the number of characters transmitted. +If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>> and +<<vasprintf>> returns -1. No error returns occur for <<vsprintf>>. + +PORTABILITY +ANSI C requires all three functions. + +Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, +<<lseek>>, <<read>>, <<sbrk>>, <<write>>. +*/ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/ +static char *rcsid = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Actual printf innards. + * + * This code is large and complicated... + */ +#include <newlib.h> + +#ifdef INTEGER_ONLY +#define VFPRINTF vfiprintf +#define _VFPRINTF_R _vfiprintf_r +#else +#define VFPRINTF vfprintf +#define _VFPRINTF_R _vfprintf_r +#ifndef NO_FLOATING_POINT +#define FLOATING_POINT +#endif +#endif + +#define _NO_POS_ARGS +#if defined _WANT_IO_POS_ARGS +# undef _NO_POS_ARGS +#endif + +#include <_ansi.h> +#include <reent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> +#include <wchar.h> +#include <string.h> +#include <sys/lock.h> +#ifdef _HAVE_STDC +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include "local.h" +#include "fvwrite.h" +#include "vfieeefp.h" + +/* Currently a test is made to see if long double processing is warranted. + This could be changed in the future should the _ldtoa_r code be + preferred over _dtoa_r. */ +#define _NO_LONGDBL +#if defined _WANT_IO_LONG_DOUBLE && (LDBL_MANT_DIG > DBL_MANT_DIG) +#undef _NO_LONGDBL +#endif + +#define _NO_LONGLONG +#if defined _WANT_IO_LONG_LONG && defined __GNUC__ +# undef _NO_LONGLONG +#endif + +/* + * Flush out all the vectors defined by the given uio, + * then reset it so that it can be reused. + */ +static int +_DEFUN(__sprint_r, (ptr, fp, uio), + struct _reent *ptr _AND + FILE *fp _AND + register struct __suio *uio) +{ + register int err; + + if (uio->uio_resid == 0) { + uio->uio_iovcnt = 0; + return (0); + } + err = __sfvwrite_r(ptr, fp, uio); + uio->uio_resid = 0; + uio->uio_iovcnt = 0; + return (err); +} + +/* + * Helper function for `fprintf to unbuffered unix file': creates a + * temporary buffer. We only work on write-only files; this avoids + * worries about ungetc buffers and so forth. + */ +static int +_DEFUN(__sbprintf, (rptr, fp, fmt, ap), + struct _reent *rptr _AND + register FILE *fp _AND + _CONST char *fmt _AND + va_list ap) +{ + int ret; + FILE fake; + unsigned char buf[BUFSIZ]; + + /* copy the important variables */ + fake._flags = fp->_flags & ~__SNBF; + fake._file = fp->_file; + fake._cookie = fp->_cookie; + fake._write = fp->_write; + + /* set up the buffer */ + fake._bf._base = fake._p = buf; + fake._bf._size = fake._w = sizeof (buf); + fake._lbfsize = 0; /* not actually used, but Just In Case */ +#ifndef __SINGLE_THREAD__ + __lock_init_recursive (fake._lock); +#endif + + /* do the work, then copy any error status */ + ret = _VFPRINTF_R (rptr, &fake, fmt, ap); + if (ret >= 0 && fflush(&fake)) + ret = EOF; + if (fake._flags & __SERR) + fp->_flags |= __SERR; + +#ifndef __SINGLE_THREAD__ + __lock_close_recursive (fake._lock); +#endif + return (ret); +} + + +#ifdef FLOATING_POINT +#include <locale.h> +#include <math.h> +#include "floatio.h" + +#if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX) +# define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ +#else +# define BUF MB_LEN_MAX +#endif + +#define DEFPREC 6 + +#ifdef _NO_LONGDBL +static char * +_EXFUN(cvt, (struct _reent *, double, int, int, char *, int *, int, int *)); +#else +static char * +_EXFUN(cvt, (struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *)); +extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *)); +#endif + +static int _EXFUN(exponent, (char *, int, int)); + +#else /* no FLOATING_POINT */ + +#define BUF 40 + +#endif /* FLOATING_POINT */ + +#ifndef _NO_LONGLONG +#define quad_t long long +#define u_quad_t unsigned long long +#else +#define quad_t long +#define u_quad_t unsigned long +#endif + +typedef quad_t * quad_ptr_t; +typedef _PTR void_ptr_t; +typedef char * char_ptr_t; +typedef long * long_ptr_t; +typedef int * int_ptr_t; +typedef short * short_ptr_t; + +#ifndef _NO_POS_ARGS +#define MAX_POS_ARGS 32 + +union arg_val +{ + int val_int; + u_int val_u_int; + long val_long; + u_long val_u_long; + float val_float; + double val_double; + _LONG_DOUBLE val__LONG_DOUBLE; + int_ptr_t val_int_ptr_t; + short_ptr_t val_short_ptr_t; + long_ptr_t val_long_ptr_t; + char_ptr_t val_char_ptr_t; + quad_ptr_t val_quad_ptr_t; + void_ptr_t val_void_ptr_t; + quad_t val_quad_t; + u_quad_t val_u_quad_t; + wint_t val_wint_t; +}; + +static union arg_val * +_EXFUN(get_arg, (struct _reent *data, int n, char *fmt, + va_list *ap, int *numargs, union arg_val *args, + int *arg_type, char **last_fmt)); +#endif /* !_NO_POS_ARGS */ + +/* + * Macros for converting digits to letters and vice versa + */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit (c) <= 9) +#define to_char(n) ((n) + '0') + +/* + * Flags used during conversion. + */ +#define ALT 0x001 /* alternate form */ +#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ +#define LADJUST 0x004 /* left adjustment */ +#define LONGDBL 0x008 /* long double */ +#define LONGINT 0x010 /* long integer */ +#ifndef _NO_LONGLONG +#define QUADINT 0x020 /* quad integer */ +#else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so + that %lld behaves the same as %ld, not as %d, as expected if: + sizeof (long long) = sizeof long > sizeof int */ +#define QUADINT LONGINT +#endif +#define SHORTINT 0x040 /* short integer */ +#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ +#define FPT 0x100 /* Floating point number */ +#define CHARINT 0x200 /* char as integer */ + +int _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list)); + +int +_DEFUN(VFPRINTF, (fp, fmt0, ap), + FILE * fp _AND + _CONST char *fmt0 _AND + va_list ap) +{ + int result; + result = _VFPRINTF_R (_REENT, fp, fmt0, ap); + return result; +} + +int +_DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap), + struct _reent *data _AND + FILE * fp _AND + _CONST char *fmt0 _AND + va_list ap) +{ + register char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int n, m; /* handy integers (short term usage) */ + register char *cp; /* handy char pointer (short term usage) */ + register struct __siov *iovp;/* for PRINT macro */ + register int flags; /* flags as above */ + char *fmt_anchor; /* current format spec being processed */ + int N; /* arg number */ + int arg_index; /* index into args processed directly */ +#ifndef _NO_POS_ARGS + int numargs; /* number of varargs read */ + char *saved_fmt; /* saved fmt pointer */ + union arg_val args[MAX_POS_ARGS]; + int arg_type[MAX_POS_ARGS]; + int is_pos_arg; /* is current format positional? */ + int old_is_pos_arg; /* is current format positional? */ +#endif + int ret; /* return value accumulator */ + int width; /* width from format (%8d), or 0 */ + int prec; /* precision from format (%.3d), or -1 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ +#ifdef FLOATING_POINT + char *decimal_point = localeconv()->decimal_point; + char softsign; /* temporary negative sign for floats */ +#ifdef _NO_LONGDBL + union { int i; double d; } _double_ = {0}; + #define _fpvalue (_double_.d) +#else + union { int i; _LONG_DOUBLE ld; } _long_double_ = {0}; + #define _fpvalue (_long_double_.ld) + int tmp; +#endif + int expt; /* integer value of exponent */ + int expsize = 0; /* character count for expstr */ + int ndig = 0; /* actual number of digits returned by cvt */ + char expstr[7]; /* buffer for exponent string */ +#endif + u_quad_t _uquad; /* integer arguments %[diouxX] */ + enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ + int dprec; /* a copy of prec if [diouxX], 0 otherwise */ + int realsz; /* field size expanded by dprec */ + int size; /* size of converted field or string */ + char *xdigs = NULL; /* digits for [xX] conversion */ +#define NIOV 8 + struct __suio uio; /* output information: summary */ + struct __siov iov[NIOV];/* ... and individual io vectors */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + char ox[2]; /* space for 0x hex-prefix */ +#ifdef _MB_CAPABLE + wchar_t wc; + mbstate_t state; /* mbtowc calls from library must not change state */ +#endif + char *malloc_buf = NULL;/* handy pointer for malloced buffers */ + + /* + * Choose PADSIZE to trade efficiency vs. size. If larger printf + * fields occur frequently, increase PADSIZE and make the initialisers + * below longer. + */ +#define PADSIZE 16 /* pad chunk size */ + static _CONST char blanks[PADSIZE] = + {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; + static _CONST char zeroes[PADSIZE] = + {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + +#ifdef _MB_CAPABLE + memset (&state, '\0', sizeof (state)); +#endif + /* + * BEWARE, these `goto error' on error, and PAD uses `n'. + */ +#define PRINT(ptr, len) { \ + iovp->iov_base = (ptr); \ + iovp->iov_len = (len); \ + uio.uio_resid += (len); \ + iovp++; \ + if (++uio.uio_iovcnt >= NIOV) { \ + if (__sprint_r(data, fp, &uio)) \ + goto error; \ + iovp = iov; \ + } \ +} +#define PAD(howmany, with) { \ + if ((n = (howmany)) > 0) { \ + while (n > PADSIZE) { \ + PRINT (with, PADSIZE); \ + n -= PADSIZE; \ + } \ + PRINT (with, n); \ + } \ +} +#define FLUSH() { \ + if (uio.uio_resid && __sprint_r(data, fp, &uio)) \ + goto error; \ + uio.uio_iovcnt = 0; \ + iovp = iov; \ +} + + /* Macros to support positional arguments */ +#ifndef _NO_POS_ARGS +#define GET_ARG(n, ap, type) \ + ( is_pos_arg \ + ? n < numargs \ + ? args[n].val_##type \ + : get_arg (data, n, fmt_anchor, &ap, &numargs, args, arg_type, &saved_fmt)->val_##type \ + : arg_index++ < numargs \ + ? args[n].val_##type \ + : numargs < MAX_POS_ARGS \ + ? args[numargs++].val_##type = va_arg (ap, type) \ + : va_arg (ap, type) \ + ) +#else +#define GET_ARG(n, ap, type) (va_arg (ap, type)) +#endif + + /* + * To extend shorts properly, we need both signed and unsigned + * argument extraction methods. + */ +#ifndef _NO_LONGLONG +#define SARG() \ + (flags&QUADINT ? GET_ARG (N, ap, quad_t) : \ + flags&LONGINT ? GET_ARG (N, ap, long) : \ + flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \ + flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \ + (long)GET_ARG (N, ap, int)) +#define UARG() \ + (flags&QUADINT ? GET_ARG (N, ap, u_quad_t) : \ + flags&LONGINT ? GET_ARG (N, ap, u_long) : \ + flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \ + flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \ + (u_long)GET_ARG (N, ap, u_int)) +#else +#define SARG() \ + (flags&LONGINT ? GET_ARG (N, ap, long) : \ + flags&SHORTINT ? (long)(short)GET_ARG (N, ap, int) : \ + flags&CHARINT ? (long)(signed char)GET_ARG (N, ap, int) : \ + (long)GET_ARG (N, ap, int)) +#define UARG() \ + (flags&LONGINT ? GET_ARG (N, ap, u_long) : \ + flags&SHORTINT ? (u_long)(u_short)GET_ARG (N, ap, int) : \ + flags&CHARINT ? (u_long)(unsigned char)GET_ARG (N, ap, int) : \ + (u_long)GET_ARG (N, ap, u_int)) +#endif + + CHECK_INIT (data); + _flockfile (fp); + + /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ + if (cantwrite (fp)) { + _funlockfile (fp); + return (EOF); + } + + /* optimise fprintf(stderr) (and other unbuffered Unix files) */ + if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && + fp->_file >= 0) { + _funlockfile (fp); + return (__sbprintf (data, fp, fmt0, ap)); + } + + fmt = (char *)fmt0; + uio.uio_iov = iovp = iov; + uio.uio_resid = 0; + uio.uio_iovcnt = 0; + ret = 0; + arg_index = 0; +#ifndef _NO_POS_ARGS + saved_fmt = NULL; + arg_type[0] = -1; + numargs = 0; + is_pos_arg = 0; +#endif + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + cp = fmt; +#ifdef _MB_CAPABLE + while ((n = _mbtowc_r (data, &wc, fmt, MB_CUR_MAX, &state)) > 0) { + if (wc == '%') + break; + fmt += n; + } +#else + while (*fmt != '\0' && *fmt != '%') + fmt += 1; +#endif + if ((m = fmt - cp) != 0) { + PRINT (cp, m); + ret += m; + } +#ifdef _MB_CAPABLE + if (n <= 0) + goto done; +#else + if (*fmt == '\0') + goto done; +#endif + fmt_anchor = fmt; + fmt++; /* skip over '%' */ + + flags = 0; + dprec = 0; + width = 0; + prec = -1; + sign = '\0'; + N = arg_index; +#ifndef _NO_POS_ARGS + is_pos_arg = 0; +#endif + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + n = N; +#ifndef _NO_POS_ARGS + /* we must check for positional arg used for dynamic width */ + old_is_pos_arg = is_pos_arg; + is_pos_arg = 0; + if (is_digit (*fmt)) { + char *old_fmt = fmt; + + n = 0; + ch = *fmt++; + do { + n = 10 * n + to_digit (ch); + ch = *fmt++; + } while (is_digit (ch)); + + if (ch == '$') { + if (n <= MAX_POS_ARGS) { + n -= 1; + is_pos_arg = 1; + } + else + goto error; + } + else { + fmt = old_fmt; + goto rflag; + } + } +#endif /* !_NO_POS_ARGS */ + + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + width = GET_ARG (n, ap, int); +#ifndef _NO_POS_ARGS + is_pos_arg = old_is_pos_arg; +#endif + if (width >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + n = N; +#ifndef _NO_POS_ARGS + /* we must check for positional arg used for dynamic width */ + old_is_pos_arg = is_pos_arg; + is_pos_arg = 0; + if (is_digit (*fmt)) { + char *old_fmt = fmt; + + n = 0; + ch = *fmt++; + do { + n = 10 * n + to_digit (ch); + ch = *fmt++; + } while (is_digit (ch)); + + if (ch == '$') { + if (n <= MAX_POS_ARGS) { + n -= 1; + is_pos_arg = 1; + } + else + goto error; + } + else { + fmt = old_fmt; + goto rflag; + } + } +#endif /* !_NO_POS_ARGS */ + prec = GET_ARG (n, ap, int); +#ifndef _NO_POS_ARGS + is_pos_arg = old_is_pos_arg; +#endif + if (prec < 0) + prec = -1; + goto rflag; + } + n = 0; + while (is_digit (ch)) { + n = 10 * n + to_digit (ch); + ch = *fmt++; + } + prec = n < 0 ? -1 : n; + goto reswitch; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit (ch); + ch = *fmt++; + } while (is_digit (ch)); +#ifndef _NO_POS_ARGS + if (ch == '$') { + if (n <= MAX_POS_ARGS) { + N = n - 1; + is_pos_arg = 1; + goto rflag; + } + else + goto error; + } +#endif /* !_NO_POS_ARGS */ + width = n; + goto reswitch; +#ifdef FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + if (*fmt == 'h') { + fmt++; + flags |= CHARINT; + } else { + flags |= SHORTINT; + } + goto rflag; + case 'l': + if (*fmt == 'l') { + fmt++; + flags |= QUADINT; + } else { + flags |= LONGINT; + } + goto rflag; + case 'q': + flags |= QUADINT; + goto rflag; + case 'j': + if (sizeof (intmax_t) == sizeof (long)) + flags |= LONGINT; + else + flags |= QUADINT; + goto rflag; + case 'z': + if (sizeof (size_t) < sizeof (int)) + /* POSIX states size_t is 16 or more bits, as is short. */ + flags |= SHORTINT; + else if (sizeof (size_t) == sizeof (int)) + /* no flag needed */; + else if (sizeof (size_t) <= sizeof (long)) + flags |= LONGINT; + else + /* POSIX states that at least one programming + environment must support size_t no wider than + long, but that means other environments can + have size_t as wide as long long. */ + flags |= QUADINT; + goto rflag; + case 't': + if (sizeof (ptrdiff_t) < sizeof (int)) + /* POSIX states ptrdiff_t is 16 or more bits, as + is short. */ + flags |= SHORTINT; + else if (sizeof (ptrdiff_t) == sizeof (int)) + /* no flag needed */; + else if (sizeof (ptrdiff_t) <= sizeof (long)) + flags |= LONGINT; + else + /* POSIX states that at least one programming + environment must support ptrdiff_t no wider than + long, but that means other environments can + have ptrdiff_t as wide as long long. */ + flags |= QUADINT; + goto rflag; + case 'c': + case 'C': + cp = buf; + if (ch == 'C' || (flags & LONGINT)) { + mbstate_t ps; + + memset ((_PTR)&ps, '\0', sizeof (mbstate_t)); + if ((size = (int)_wcrtomb_r (data, cp, + (wchar_t)GET_ARG (N, ap, wint_t), + &ps)) == -1) { + fp->_flags |= __SERR; + goto error; + } + } + else { + *cp = GET_ARG (N, ap, int); + size = 1; + } + sign = '\0'; + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + _uquad = SARG (); +#ifndef _NO_LONGLONG + if ((quad_t)_uquad < 0) +#else + if ((long) _uquad < 0) +#endif + { + + _uquad = -_uquad; + sign = '-'; + } + base = DEC; + goto number; +#ifdef FLOATING_POINT + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + if (prec == -1) { + prec = DEFPREC; + } else if ((ch == 'g' || ch == 'G') && prec == 0) { + prec = 1; + } + +#ifdef _NO_LONGDBL + if (flags & LONGDBL) { + _fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE); + } else { + _fpvalue = GET_ARG (N, ap, double); + } + + /* do this before tricky precision changes */ + if (isinf (_fpvalue)) { + if (_fpvalue < 0) + sign = '-'; + if (ch == 'E' || ch == 'F' || ch == 'G') + cp = "INF"; + else + cp = "inf"; + size = 3; + break; + } + if (isnan (_fpvalue)) { + if (ch == 'E' || ch == 'F' || ch == 'G') + cp = "NAN"; + else + cp = "nan"; + size = 3; + break; + } + +#else /* !_NO_LONGDBL */ + + if (flags & LONGDBL) { + _fpvalue = GET_ARG (N, ap, _LONG_DOUBLE); + } else { + _fpvalue = (_LONG_DOUBLE)GET_ARG (N, ap, double); + } + + /* do this before tricky precision changes */ + tmp = _ldcheck (&_fpvalue); + if (tmp == 2) { + if (_fpvalue < 0) + sign = '-'; + if (ch == 'E' || ch == 'F' || ch == 'G') + cp = "INF"; + else + cp = "inf"; + size = 3; + break; + } + if (tmp == 1) { + if (ch == 'E' || ch == 'F' || ch == 'G') + cp = "NAN"; + else + cp = "nan"; + size = 3; + break; + } +#endif /* !_NO_LONGDBL */ + + flags |= FPT; + + cp = cvt (data, _fpvalue, prec, flags, &softsign, + &expt, ch, &ndig); + + if (ch == 'g' || ch == 'G') { + if (expt <= -4 || expt > prec) + ch = (ch == 'g') ? 'e' : 'E'; + else + ch = 'g'; + } + if (ch <= 'e') { /* 'e' or 'E' fmt */ + --expt; + expsize = exponent (expstr, expt, ch); + size = expsize + ndig; + if (ndig > 1 || flags & ALT) + ++size; + } else if (ch == 'f') { /* f fmt */ + if (expt > 0) { + size = expt; + if (prec || flags & ALT) + size += prec + 1; + } else /* "0.X" */ + size = (prec || flags & ALT) + ? prec + 2 + : 1; + } else if (expt >= ndig) { /* fixed g fmt */ + size = expt; + if (flags & ALT) + ++size; + } else + size = ndig + (expt > 0 ? + 1 : 2 - expt); + + if (softsign) + sign = '-'; + break; +#endif /* FLOATING_POINT */ + case 'n': +#ifndef _NO_LONGLONG + if (flags & QUADINT) + *GET_ARG (N, ap, quad_ptr_t) = ret; + else +#endif + if (flags & LONGINT) + *GET_ARG (N, ap, long_ptr_t) = ret; + else if (flags & SHORTINT) + *GET_ARG (N, ap, short_ptr_t) = ret; + else if (flags & CHARINT) + *GET_ARG (N, ap, char_ptr_t) = ret; + else + *GET_ARG (N, ap, int_ptr_t) = ret; + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + _uquad = UARG (); + base = OCT; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _uquad = (u_long)(unsigned _POINTER_INT)GET_ARG (N, ap, void_ptr_t); + base = HEX; + xdigs = "0123456789abcdef"; + flags |= HEXPREFIX; + ch = 'x'; + goto nosign; + case 's': + case 'S': + sign = '\0'; + if ((cp = GET_ARG (N, ap, char_ptr_t)) == NULL) { + cp = "(null)"; + size = 6; + } + else if (ch == 'S' || (flags & LONGINT)) { + mbstate_t ps; + _CONST wchar_t *wcp; + + wcp = (_CONST wchar_t *)cp; + size = m = 0; + memset ((_PTR)&ps, '\0', sizeof (mbstate_t)); + + /* Count number of bytes needed for multibyte + string that will be produced from widechar + string. */ + if (prec >= 0) { + while (1) { + if (wcp[m] == L'\0') + break; + if ((n = (int)_wcrtomb_r (data, + buf, wcp[m], &ps)) == -1) { + fp->_flags |= __SERR; + goto error; + } + if (n + size > prec) + break; + m += 1; + size += n; + if (size == prec) + break; + } + } + else { + if ((size = (int)_wcsrtombs_r (data, + NULL, &wcp, 0, &ps)) == -1) { + fp->_flags |= __SERR; + goto error; + } + wcp = (_CONST wchar_t *)cp; + } + + if (size == 0) + break; + + if ((malloc_buf = + (char *)_malloc_r (data, size + 1)) == NULL) { + fp->_flags |= __SERR; + goto error; + } + + /* Convert widechar string to multibyte string. */ + memset ((_PTR)&ps, '\0', sizeof (mbstate_t)); + if (_wcsrtombs_r (data, malloc_buf, + &wcp, size, &ps) != size) { + fp->_flags |= __SERR; + goto error; + } + cp = malloc_buf; + cp[size] = '\0'; + } + else if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen () will go further. + */ + char *p = memchr (cp, 0, prec); + + if (p != NULL) { + size = p - cp; + if (size > prec) + size = prec; + } else + size = prec; + } else + size = strlen (cp); + + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + _uquad = UARG (); + base = DEC; + goto nosign; + case 'X': + xdigs = "0123456789ABCDEF"; + goto hex; + case 'x': + xdigs = "0123456789abcdef"; +hex: _uquad = UARG (); + base = HEX; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _uquad != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + cp = buf + BUF; + if (_uquad != 0 || prec != 0) { + /* + * Unsigned mod is hard, and unsigned mod + * by a constant is easier than that by + * a variable; hence this switch. + */ + switch (base) { + case OCT: + do { + *--cp = to_char (_uquad & 7); + _uquad >>= 3; + } while (_uquad); + /* handle octal leading 0 */ + if (flags & ALT && *cp != '0') + *--cp = '0'; + break; + + case DEC: + /* many numbers are 1 digit */ + while (_uquad >= 10) { + *--cp = to_char (_uquad % 10); + _uquad /= 10; + } + *--cp = to_char (_uquad); + break; + + case HEX: + do { + *--cp = xdigs[_uquad & 15]; + _uquad >>= 4; + } while (_uquad); + break; + + default: + cp = "bug in vfprintf: bad base"; + size = strlen (cp); + goto skipsize; + } + } + /* + * ...result is to be converted to an 'alternate form'. + * For o conversion, it increases the precision to force + * the first digit of the result to be a zero." + * -- ANSI X3J11 + * + * To demonstrate this case, compile and run: + * printf ("%#.0o",0); + */ + else if (base == OCT && (flags & ALT)) + *--cp = '0'; + + size = buf + BUF - cp; + skipsize: + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + /* pretend it was %c with argument ch */ + cp = buf; + *cp = ch; + size = 1; + sign = '\0'; + break; + } + + /* + * All reasonable formats wind up here. At this point, `cp' + * points to a string which (if not flags&LADJUST) should be + * padded out to `width' places. If flags&ZEROPAD, it should + * first be prefixed by any sign or other prefix; otherwise, + * it should be blank padded before the prefix is emitted. + * After any left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print the + * string proper, then emit zeroes required by any leftover + * floating precision; finally, if LADJUST, pad with blanks. + * + * Compute actual size, so we know how much to pad. + * size excludes decimal prec; realsz includes it. + */ + realsz = dprec > size ? dprec : size; + if (sign) + realsz++; + else if (flags & HEXPREFIX) + realsz+= 2; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0) + PAD (width - realsz, blanks); + + /* prefix */ + if (sign) { + PRINT (&sign, 1); + } else if (flags & HEXPREFIX) { + ox[0] = '0'; + ox[1] = ch; + PRINT (ox, 2); + } + + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + PAD (width - realsz, zeroes); + + /* leading zeroes from decimal precision */ + PAD (dprec - size, zeroes); + + /* the string or number proper */ +#ifdef FLOATING_POINT + if ((flags & FPT) == 0) { + PRINT (cp, size); + } else { /* glue together f_p fragments */ + if (ch >= 'f') { /* 'f' or 'g' */ + if (_fpvalue == 0) { + /* kludge for __dtoa irregularity */ + PRINT ("0", 1); + if (expt < ndig || (flags & ALT) != 0) { + PRINT (decimal_point, 1); + PAD (ndig - 1, zeroes); + } + } else if (expt <= 0) { + PRINT ("0", 1); + if(expt || ndig) { + PRINT (decimal_point, 1); + PAD (-expt, zeroes); + PRINT (cp, ndig); + } + } else if (expt >= ndig) { + PRINT (cp, ndig); + PAD (expt - ndig, zeroes); + if (flags & ALT) + PRINT (".", 1); + } else { + PRINT (cp, expt); + cp += expt; + PRINT (".", 1); + PRINT (cp, ndig-expt); + } + } else { /* 'e' or 'E' */ + if (ndig > 1 || flags & ALT) { + ox[0] = *cp++; + ox[1] = '.'; + PRINT (ox, 2); + if (_fpvalue) { + PRINT (cp, ndig-1); + } else /* 0.[0..] */ + /* __dtoa irregularity */ + PAD (ndig - 1, zeroes); + } else /* XeYYY */ + PRINT (cp, 1); + PRINT (expstr, expsize); + } + } +#else + PRINT (cp, size); +#endif + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + PAD (width - realsz, blanks); + + /* finally, adjust ret */ + ret += width > realsz ? width : realsz; + + FLUSH (); /* copy out the I/O vectors */ + + if (malloc_buf != NULL) { + _free_r (data, malloc_buf); + malloc_buf = NULL; + } + } +done: + FLUSH (); +error: + if (malloc_buf != NULL) + _free_r (data, malloc_buf); + _funlockfile (fp); + return (__sferror (fp) ? EOF : ret); + /* NOTREACHED */ +} + +#ifdef FLOATING_POINT + +#ifdef _NO_LONGDBL +extern char *_dtoa_r _PARAMS((struct _reent *, double, int, + int, int *, int *, char **)); +#else +extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int, + int, int *, int *, char **)); +#undef word0 +#define word0(x) ldword0(x) +#endif + +#ifdef _NO_LONGDBL +static char * +_DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length), + struct _reent *data _AND + double value _AND + int ndigits _AND + int flags _AND + char *sign _AND + int *decpt _AND + int ch _AND + int *length) +#else +static char * +_DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length), + struct _reent *data _AND + _LONG_DOUBLE value _AND + int ndigits _AND + int flags _AND + char *sign _AND + int *decpt _AND + int ch _AND + int *length) +#endif +{ + int mode, dsgn; + char *digits, *bp, *rve; +#ifdef _NO_LONGDBL + union double_union tmp; +#else + union + { + struct ldieee ieee; + _LONG_DOUBLE val; + } ld; +#endif + + if (ch == 'f') { + mode = 3; /* ndigits after the decimal point */ + } else { + /* To obtain ndigits after the decimal point for the 'e' + * and 'E' formats, round to ndigits + 1 significant + * figures. + */ + if (ch == 'e' || ch == 'E') { + ndigits++; + } + mode = 2; /* ndigits significant digits */ + } + +#ifdef _NO_LONGDBL + tmp.d = value; + + if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */ + value = -value; + *sign = '-'; + } else + *sign = '\000'; + + digits = _dtoa_r (data, value, mode, ndigits, decpt, &dsgn, &rve); +#else /* !_NO_LONGDBL */ + ld.val = value; + if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */ + value = -value; + *sign = '-'; + } else + *sign = '\000'; + + digits = _ldtoa_r (data, value, mode, ndigits, decpt, &dsgn, &rve); +#endif /* !_NO_LONGDBL */ + + if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ + bp = digits + ndigits; + if (ch == 'f') { + if (*digits == '0' && value) + *decpt = -ndigits + 1; + bp += *decpt; + } + if (value == 0) /* kludge for __dtoa irregularity */ + rve = bp; + while (rve < bp) + *rve++ = '0'; + } + *length = rve - digits; + return (digits); +} + +static int +_DEFUN(exponent, (p0, exp, fmtch), + char *p0 _AND + int exp _AND + int fmtch) +{ + register char *p, *t; + char expbuf[40]; + + p = p0; + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } + else + *p++ = '+'; + t = expbuf + 40; + if (exp > 9) { + do { + *--t = to_char (exp % 10); + } while ((exp /= 10) > 9); + *--t = to_char (exp); + for (; t < expbuf + 40; *p++ = *t++); + } + else { + *p++ = '0'; + *p++ = to_char (exp); + } + return (p - p0); +} +#endif /* FLOATING_POINT */ + + +#ifndef _NO_POS_ARGS + +/* Positional argument support. + Written by Jeff Johnston + + Copyright (c) 2002 Red Hat Incorporated. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + The name of Red Hat Incorporated may not be used to endorse + or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +typedef enum { + ZERO, /* '0' */ + DIGIT, /* '1-9' */ + DOLLAR, /* '$' */ + MODFR, /* spec modifier */ + SPEC, /* format specifier */ + DOT, /* '.' */ + STAR, /* '*' */ + FLAG, /* format flag */ + OTHER, /* all other chars */ + MAX_CH_CLASS /* place-holder */ +} CH_CLASS; + +typedef enum { + START, /* start */ + SFLAG, /* seen a flag */ + WDIG, /* seen digits in width area */ + WIDTH, /* processed width */ + SMOD, /* seen spec modifier */ + SDOT, /* seen dot */ + VARW, /* have variable width specifier */ + VARP, /* have variable precision specifier */ + PREC, /* processed precision */ + VWDIG, /* have digits in variable width specification */ + VPDIG, /* have digits in variable precision specification */ + DONE, /* done */ + MAX_STATE, /* place-holder */ +} STATE; + +typedef enum { + NOOP, /* do nothing */ + NUMBER, /* build a number from digits */ + SKIPNUM, /* skip over digits */ + GETMOD, /* get and process format modifier */ + GETARG, /* get and process argument */ + GETPW, /* get variable precision or width */ + GETPWB, /* get variable precision or width and pushback fmt char */ + GETPOS, /* get positional parameter value */ + PWPOS, /* get positional parameter value for variable width or precision */ +} ACTION; + +_CONST static CH_CLASS chclass[256] = { + /* 00-07 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 08-0f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 10-17 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 18-1f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 20-27 */ FLAG, OTHER, OTHER, FLAG, DOLLAR, OTHER, OTHER, OTHER, + /* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER, + /* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, + /* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 40-47 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, OTHER, SPEC, + /* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, + /* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, SPEC, + /* 58-5f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC, + /* 68-6f */ MODFR, SPEC, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, + /* 70-77 */ SPEC, MODFR, OTHER, SPEC, OTHER, SPEC, OTHER, OTHER, + /* 78-7f */ SPEC, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 80-87 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 88-8f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 90-97 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* 98-9f */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* a0-a7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* a8-af */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* b0-b7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* b8-bf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* c0-c7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* c8-cf */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* d0-d7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* d8-df */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* e0-e7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* e8-ef */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* f0-f7 */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, + /* f8-ff */ OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, +}; + +_CONST static STATE state_table[MAX_STATE][MAX_CH_CLASS] = { + /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */ + /* START */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE }, + /* SFLAG */ { SFLAG, WDIG, DONE, SMOD, DONE, SDOT, VARW, SFLAG, DONE }, + /* WDIG */ { DONE, DONE, WIDTH, SMOD, DONE, SDOT, DONE, DONE, DONE }, + /* WIDTH */ { DONE, DONE, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE }, + /* SMOD */ { DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE }, + /* SDOT */ { SDOT, PREC, DONE, SMOD, DONE, DONE, VARP, DONE, DONE }, + /* VARW */ { DONE, VWDIG, DONE, SMOD, DONE, SDOT, DONE, DONE, DONE }, + /* VARP */ { DONE, VPDIG, DONE, SMOD, DONE, DONE, DONE, DONE, DONE }, + /* PREC */ { DONE, DONE, DONE, SMOD, DONE, DONE, DONE, DONE, DONE }, + /* VWDIG */ { DONE, DONE, WIDTH, DONE, DONE, DONE, DONE, DONE, DONE }, + /* VPDIG */ { DONE, DONE, PREC, DONE, DONE, DONE, DONE, DONE, DONE }, +}; + +_CONST static ACTION action_table[MAX_STATE][MAX_CH_CLASS] = { + /* '0' '1-9' '$' MODFR SPEC '.' '*' FLAG OTHER */ + /* START */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, + /* SFLAG */ { NOOP, NUMBER, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, + /* WDIG */ { NOOP, NOOP, GETPOS, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, + /* WIDTH */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, + /* SMOD */ { NOOP, NOOP, NOOP, NOOP, GETARG, NOOP, NOOP, NOOP, NOOP }, + /* SDOT */ { NOOP, SKIPNUM, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, + /* VARW */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, GETPW, NOOP, NOOP, NOOP }, + /* VARP */ { NOOP, NUMBER, NOOP, GETPW, GETPWB, NOOP, NOOP, NOOP, NOOP }, + /* PREC */ { NOOP, NOOP, NOOP, GETMOD, GETARG, NOOP, NOOP, NOOP, NOOP }, + /* VWDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP }, + /* VPDIG */ { NOOP, NOOP, PWPOS, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP }, +}; + +/* function to get positional parameter N where n = N - 1 */ +static union arg_val * +_DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt), + struct _reent *data _AND + int n _AND + char *fmt _AND + va_list *ap _AND + int *numargs_p _AND + union arg_val *args _AND + int *arg_type _AND + char **last_fmt) +{ + int ch; + int number, flags; + int spec_type; + int numargs = *numargs_p; + CH_CLASS chtype; + STATE state, next_state; + ACTION action; + int pos, last_arg; + int max_pos_arg = n; + enum types { INT, LONG_INT, SHORT_INT, CHAR_INT, QUAD_INT, CHAR, CHAR_PTR, DOUBLE, LONG_DOUBLE, WIDE_CHAR }; +#ifdef _MB_CAPABLE + wchar_t wc; + mbstate_t wc_state; + int nbytes; +#endif + + /* if this isn't the first call, pick up where we left off last time */ + if (*last_fmt != NULL) + fmt = *last_fmt; + +#ifdef _MB_CAPABLE + memset (&wc_state, '\0', sizeof (wc_state)); +#endif + + /* we need to process either to end of fmt string or until we have actually + read the desired parameter from the vararg list. */ + while (*fmt && n >= numargs) + { +#ifdef _MB_CAPABLE + while ((nbytes = _mbtowc_r (data, &wc, fmt, MB_CUR_MAX, &wc_state)) > 0) + { + fmt += nbytes; + if (wc == '%') + break; + } + + if (nbytes <= 0) + break; +#else + while (*fmt != '\0' && *fmt != '%') + fmt += 1; + + if (*fmt == '\0') + break; +#endif + state = START; + flags = 0; + pos = -1; + number = 0; + spec_type = INT; + + /* Use state/action table to process format specifiers. We ignore invalid + formats and we are only interested in information that tells us how to + read the vararg list. */ + while (state != DONE) + { + ch = *fmt++; + chtype = chclass[ch]; + next_state = state_table[state][chtype]; + action = action_table[state][chtype]; + state = next_state; + + switch (action) + { + case GETMOD: /* we have format modifier */ + switch (ch) + { + case 'h': + if (*fmt == 'h') + { + flags |= CHARINT; + ++fmt; + } + else + flags |= SHORTINT; + break; + case 'L': + flags |= LONGDBL; + break; + case 'q': + flags |= QUADINT; + break; + case 'j': + if (sizeof (intmax_t) == sizeof (long)) + flags |= LONGINT; + else + flags |= QUADINT; + break; + case 'z': + if (sizeof (size_t) < sizeof (int)) + /* POSIX states size_t is 16 or more bits, as is short. */ + flags |= SHORTINT; + else if (sizeof (size_t) == sizeof (int)) + /* no flag needed */; + else if (sizeof (size_t) <= sizeof (long)) + flags |= LONGINT; + else + /* POSIX states that at least one programming + environment must support size_t no wider than + long, but that means other environments can + have size_t as wide as long long. */ + flags |= QUADINT; + break; + case 't': + if (sizeof (ptrdiff_t) < sizeof (int)) + /* POSIX states ptrdiff_t is 16 or more bits, as + is short. */ + flags |= SHORTINT; + else if (sizeof (ptrdiff_t) == sizeof (int)) + /* no flag needed */; + else if (sizeof (ptrdiff_t) <= sizeof (long)) + flags |= LONGINT; + else + /* POSIX states that at least one programming + environment must support ptrdiff_t no wider than + long, but that means other environments can + have ptrdiff_t as wide as long long. */ + flags |= QUADINT; + break; + case 'l': + default: + if (*fmt == 'l') + { + flags |= QUADINT; + ++fmt; + } + else + flags |= LONGINT; + break; + } + break; + case GETARG: /* we have format specifier */ + { + numargs &= (MAX_POS_ARGS - 1); + /* process the specifier and translate it to a type to fetch from varargs */ + switch (ch) + { + case 'd': + case 'i': + case 'o': + case 'x': + case 'X': + case 'u': + if (flags & LONGINT) + spec_type = LONG_INT; + else if (flags & SHORTINT) + spec_type = SHORT_INT; + else if (flags & CHARINT) + spec_type = CHAR_INT; +#ifndef _NO_LONGLONG + else if (flags & QUADINT) + spec_type = QUAD_INT; +#endif + else + spec_type = INT; + break; + case 'D': + case 'U': + case 'O': + spec_type = LONG_INT; + break; + case 'f': + case 'g': + case 'G': + case 'E': + case 'e': +#ifndef _NO_LONGDBL + if (flags & LONGDBL) + spec_type = LONG_DOUBLE; + else +#endif + spec_type = DOUBLE; + break; + case 's': + case 'S': + case 'p': + spec_type = CHAR_PTR; + break; + case 'c': + spec_type = CHAR; + break; + case 'C': + spec_type = WIDE_CHAR; + break; + } + + /* if we have a positional parameter, just store the type, otherwise + fetch the parameter from the vararg list */ + if (pos != -1) + arg_type[pos] = spec_type; + else + { + switch (spec_type) + { + case LONG_INT: + args[numargs++].val_long = va_arg (*ap, long); + break; + case QUAD_INT: + args[numargs++].val_quad_t = va_arg (*ap, quad_t); + break; + case WIDE_CHAR: + args[numargs++].val_wint_t = va_arg (*ap, wint_t); + break; + case CHAR: + case CHAR_INT: + case SHORT_INT: + case INT: + args[numargs++].val_int = va_arg (*ap, int); + break; + case CHAR_PTR: + args[numargs++].val_char_ptr_t = va_arg (*ap, char *); + break; + case DOUBLE: + args[numargs++].val_double = va_arg (*ap, double); + break; + case LONG_DOUBLE: + args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE); + break; + } + } + } + break; + case GETPOS: /* we have positional specifier */ + if (arg_type[0] == -1) + memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS); + pos = number - 1; + max_pos_arg = (max_pos_arg > pos ? max_pos_arg : pos); + break; + case PWPOS: /* we have positional specifier for width or precision */ + if (arg_type[0] == -1) + memset (arg_type, 0, sizeof (int) * MAX_POS_ARGS); + number -= 1; + arg_type[number] = INT; + max_pos_arg = (max_pos_arg > number ? max_pos_arg : number); + break; + case GETPWB: /* we require format pushback */ + --fmt; + /* fallthrough */ + case GETPW: /* we have a variable precision or width to acquire */ + args[numargs++].val_int = va_arg (*ap, int); + break; + case NUMBER: /* we have a number to process */ + number = (ch - '0'); + while ((ch = *fmt) != '\0' && is_digit (ch)) + { + number = number * 10 + (ch - '0'); + ++fmt; + } + break; + case SKIPNUM: /* we have a number to skip */ + while ((ch = *fmt) != '\0' && is_digit (ch)) + ++fmt; + break; + case NOOP: + default: + break; /* do nothing */ + } + } + } + + /* process all arguments up to at least the one we are looking for and if we + have seen the end of the string, then process up to the max argument needed */ + if (*fmt == '\0') + last_arg = max_pos_arg; + else + last_arg = n; + + while (numargs <= last_arg) + { + switch (arg_type[numargs]) + { + case LONG_INT: + args[numargs++].val_long = va_arg (*ap, long); + break; + case QUAD_INT: + args[numargs++].val_quad_t = va_arg (*ap, quad_t); + break; + case CHAR_PTR: + args[numargs++].val_char_ptr_t = va_arg (*ap, char *); + break; + case DOUBLE: + args[numargs++].val_double = va_arg (*ap, double); + break; + case LONG_DOUBLE: + args[numargs++].val__LONG_DOUBLE = va_arg (*ap, _LONG_DOUBLE); + break; + case WIDE_CHAR: + args[numargs++].val_wint_t = va_arg (*ap, wint_t); + break; + case INT: + case CHAR_INT: + case SHORT_INT: + case CHAR: + default: + args[numargs++].val_int = va_arg (*ap, int); + break; + } + } + + /* alter the global numargs value and keep a reference to the last bit of the fmt + string we processed here because the caller will continue processing where we started */ + *numargs_p = numargs; + *last_fmt = fmt; + return &args[n]; +} +#endif /* !_NO_POS_ARGS */ diff --git a/newlib/libc/time/gmtime.c b/newlib/libc/time/gmtime.c new file mode 100644 index 00000000000..40116c28589 --- /dev/null +++ b/newlib/libc/time/gmtime.c @@ -0,0 +1,66 @@ +/* + * gmtime.c + * Original Author: G. Haley + * + * Converts the calendar time pointed to by tim_p into a broken-down time + * expressed as Greenwich Mean Time (GMT). Returns a pointer to a structure + * containing the broken-down time, or a null pointer if GMT is not + * available. + */ + +/* +FUNCTION +<<gmtime>>---convert time to UTC traditional form + +INDEX + gmtime + +ANSI_SYNOPSIS + #include <time.h> + struct tm *gmtime(const time_t *<[clock]>); + struct tm *gmtime_r(const time_t *<[clock]>, struct tm *<[res]>); + +TRAD_SYNOPSIS + #include <time.h> + struct tm *gmtime(<[clock]>) + const time_t *<[clock]>; + struct tm *gmtime_r(<[clock]>, <[res]>) + const time_t *<[clock]>; + struct tm *<[res]>; + +DESCRIPTION +<<gmtime>> takes the time at <[clock]> representing the number +of elapsed seconds since 00:00:00 on January 1, 1970, Universal +Coordinated Time (UTC, also known in some countries as GMT, +Greenwich Mean time) and converts it to a <<struct tm>> +representation. + +<<gmtime>> constructs the traditional time representation in static +storage; each call to <<gmtime>> or <<localtime>> will overwrite the +information generated by previous calls to either function. + +RETURNS +A pointer to the traditional time representation (<<struct tm>>). + +PORTABILITY +ANSI C requires <<gmtime>>. + +<<gmtime>> requires no supporting OS subroutines. +*/ + +#include <stdlib.h> +#include <time.h> + +#define _GMT_OFFSET 0 + +#ifndef _REENT_ONLY + +struct tm * +_DEFUN (gmtime, (tim_p), + _CONST time_t * tim_p) +{ + _REENT_CHECK_TM(_REENT); + return gmtime_r (tim_p, (struct tm *)_REENT_TM(_REENT)); +} + +#endif |