int hb_vsnprintf( char * buffer, size_t bufsize, const char * format, va_list ap ) { va_list args; size_t size; char c; #ifndef __NO_ARGPOS__ const char * fmt_start = format; v_param argbuf[ _ARGBUF_SIZE ]; v_paramlst params; params.size = _ARGBUF_SIZE; params.maxarg = 0; params.arglst = argbuf; #endif #ifndef __NO_ARGPOS__ do { params.repeat = HB_FALSE; if( params.maxarg > 0 ) { va_copy( args, ap ); va_arg_fill( ¶ms, args ); va_end( args ); } format = fmt_start; #endif va_copy( args, ap ); size = 0; do { c = *format++; if( c == '%' ) { const char * pattern = format; c = *format++; if( c != 0 && c != '%' ) { /* decode pattern */ v_param argval; int param = 0, flags = 0, width = -1, precision = -1, length, value, stop = 0; /* parameter position */ if( c >= '0' && c <= '9' ) { c = get_decimal( c, &format, &value ); if( c == '$' ) param = value; else format = pattern; c = *format++; } /* flags */ while( ! stop ) { switch( c ) { case '#': flags |= _F_ALTERNATE; c = *format++; break; case '0': flags |= _F_ZEROPADED; c = *format++; break; case '-': flags |= _F_LEFTADJUSTED; c = *format++; break; case ' ': flags |= _F_SPACE; c = *format++; break; case '+': flags |= _F_SIGN; c = *format++; break; #ifdef _SUSV2_COMPAT_ case '\'': /* group with locale thousands' grouping characters */ c = *format++; break; #endif default: stop = 1; break; } } /* field width */ if( c == '*' ) { c = *format++; if( c >= '0' && c <= '9' ) { c = get_decimal( c, &format, &value ); if( c == '$' ) { width = va_arg_n( args, _x_int, value ); c = *format++; } /* else error, wrong format */ } else width = va_arg_n( args, _x_int, 0 ); } else if( c >= '0' && c <= '9' ) c = get_decimal( c, &format, &width ); /* precision */ if( c == '.' ) { precision = 0; c = *format++; if( c == '*' ) { c = *format++; if( c >= '0' && c <= '9' ) { c = get_decimal( c, &format, &value ); if( c == '$' ) { precision = va_arg_n( args, _x_int, value ); c = *format++; } /* else error, wrong format */ } else precision = va_arg_n( args, _x_int, 0 ); } else if( c >= '0' && c <= '9' ) c = get_decimal( c, &format, &precision ); } /* length modifier */ switch( c ) { case 'h': c = *format++; if( c == 'h' ) { length = _L_CHAR_; c = *format++; } else length = _L_SHORT_; break; case 'l': c = *format++; if( c == 'l' ) { length = _L_LONGLONG_; c = *format++; } else length = _L_LONG_; break; case 'L': length = _L_LONGDOUBLE_; c = *format++; break; case 'j': length = _L_INTMAX_; c = *format++; break; case 'z': length = _L_SIZE_; c = *format++; break; case 't': length = _L_PTRDIFF_; c = *format++; break; case 'I': /* MS-Windows extension */ if( format[ 0 ] == '6' && format[ 1 ] == '4' ) { length = _L_LONGLONG_; format += 2; c = *format++; break; } else if( format[ 0 ] == '1' && format[ 1 ] == '6' ) { length = _L_SHORT_; format += 2; c = *format++; break; } else if( format[ 0 ] == '3' && format[ 1 ] == '2' ) { format += 2; c = *format++; } /* no break; */ default: length = _L_UNDEF_; break; } /* conversion specifier */ switch( c ) { #ifndef __NO_DOUBLE__ case 'a': case 'A': case 'e': case 'E': case 'g': case 'G': /* redirect above conversion to 'f' or 'F' type to keep * valid parameters order */ c = ( c == 'a' || c == 'e' || c == 'g' ) ? 'f' : 'F'; /* no break; */ case 'f': /* double decimal notation */ case 'F': /* double decimal notation */ if( length == _L_LONGDOUBLE_ ) { argval.value.as_x_long_dbl = va_arg_n( args, _x_long_dbl, param ); HB_NUMTYPEL( value, argval.value.as_x_long_dbl ); } else { double d = va_arg_n( args, _x_double, param ); HB_NUMTYPE( value, d ); argval.value.as_x_long_dbl = ( value & ( _HB_NUM_NAN | _HB_NUM_PINF | _HB_NUM_NINF ) ) == 0 ? d : 0; } if( value & _HB_NUM_NAN ) size = put_str( buffer, bufsize, size, c == 'f' ? ( flags & _F_SIGN ? "+nan": "nan" ) : ( flags & _F_SIGN ? "+NAN": "NAN" ) , flags, width, -1 ); else if( value & _HB_NUM_PINF ) size = put_str( buffer, bufsize, size, c == 'f' ? ( flags & _F_SIGN ? "+inf": "inf" ) : ( flags & _F_SIGN ? "+INF": "INF" ), flags, width, -1 ); else if( value & _HB_NUM_NINF ) size = put_str( buffer, bufsize, size, c == 'f' ? "-inf" : "-INF", flags, width, -1 ); else size = put_dbl( buffer, bufsize, size, argval.value.as_x_long_dbl, flags, width, precision ); continue; #endif case 'd': case 'i': /* signed int decimal conversion */ if( length == _L_CHAR_ ) argval.value.as_x_intmax_t = ( unsigned char ) va_arg_n( args, _x_int, param ); else if( length == _L_SHORT_ ) argval.value.as_x_intmax_t = ( unsigned short ) va_arg_n( args, _x_int, param ); else if( length == _L_LONG_ ) argval.value.as_x_intmax_t = va_arg_n( args, _x_long, param ); else if( length == _L_LONGLONG_ ) argval.value.as_x_intmax_t = va_arg_n( args, _x_longlong, param ); else if( length == _L_INTMAX_ ) argval.value.as_x_intmax_t = va_arg_n( args, _x_intmax_t, param ); else if( length == _L_SIZE_ ) argval.value.as_x_intmax_t = va_arg_n( args, _x_size_t, param ); else if( length == _L_PTRDIFF_ ) argval.value.as_x_intmax_t = va_arg_n( args, _x_ptrdiff_t, param ); else argval.value.as_x_intmax_t = va_arg_n( args, _x_int, param ); value = argval.value.as_x_intmax_t < 0; argval.value.as_x_uintmax_t = value ? -argval.value.as_x_intmax_t : argval.value.as_x_intmax_t; size = put_dec( buffer, bufsize, size, argval.value.as_x_uintmax_t, flags, width, precision, value ); continue; case 'o': /* unsigned int octal conversion */ case 'u': /* unsigned int decimal conversion */ case 'x': /* unsigned int hexadecimal conversion */ case 'X': /* unsigned int hexadecimal conversion */ if( length == _L_CHAR_ ) argval.value.as_x_uintmax_t = ( unsigned char ) va_arg_n( args, _x_int, param ); else if( length == _L_SHORT_ ) argval.value.as_x_uintmax_t = ( unsigned short ) va_arg_n( args, _x_int, param ); else if( length == _L_LONG_ ) argval.value.as_x_uintmax_t = va_arg_n( args, _x_ulong, param ); else if( length == _L_LONGLONG_ ) argval.value.as_x_uintmax_t = va_arg_n( args, _x_ulonglong, param ); else if( length == _L_INTMAX_ ) argval.value.as_x_uintmax_t = va_arg_n( args, _x_uintmax_t, param ); else if( length == _L_SIZE_ ) argval.value.as_x_uintmax_t = va_arg_n( args, _x_size_t, param ); else if( length == _L_PTRDIFF_ ) argval.value.as_x_uintmax_t = va_arg_n( args, _x_ptrdiff_t, param ); else argval.value.as_x_uintmax_t = va_arg_n( args, _x_uint, param ); if( c == 'o' ) size = put_octal( buffer, bufsize, size, argval.value.as_x_uintmax_t, flags, width, precision ); else if( c == 'u' ) size = put_dec( buffer, bufsize, size, argval.value.as_x_uintmax_t, flags & ~( _F_SPACE | _F_SIGN ), width, precision, 0 ); else size = put_hex( buffer, bufsize, size, argval.value.as_x_uintmax_t, flags, width, precision, c == 'X' ); continue; case 'p': /* void * pointer */ argval.value.as_x_ptr = va_arg_n( args, _x_ptr, param ); if( argval.value.as_x_ptr ) size = put_hex( buffer, bufsize, size, ( HB_PTRUINT ) argval.value.as_x_ptr, flags | _F_ALTERNATE, width, precision, 0 ); else size = put_str( buffer, bufsize, size, "(nil)", flags, width, -1 ); continue; case 'c': /* signed int casted to unsigned char */ if( ( flags & _F_LEFTADJUSTED ) == 0 ) { while( --width > 0 ) { if( size < bufsize ) buffer[ size ] = ' '; ++size; } } c = ( unsigned char ) va_arg_n( args, _x_int, param ); if( size < bufsize ) buffer[ size ] = c; ++size; while( --width > 0 ) { if( size < bufsize ) buffer[ size ] = ' '; ++size; } continue; case 's': /* const char * */ if( length == _L_LONG_ ) { argval.value.as_x_wstr = va_arg_n( args, _x_wstr, param ); size = put_wstr( buffer, bufsize, size, argval.value.as_x_wstr, flags, width, precision ); } else { argval.value.as_x_str = va_arg_n( args, _x_str, param ); size = put_str( buffer, bufsize, size, argval.value.as_x_str, flags, width, precision ); } continue; case 'n': /* store current result size in int * arg */ /* This is very danger feature in *printf() functions * family very often used by hackers to create buffer * overflows. It can also cause unintentional memory * corruption by programmers typo in pattern so if it's * not strictly necessary it's good to disable it. */ *( va_arg_n( args, _x_intptr, param ) ) = ( int ) size; continue; case '%': /* store % consuming arguments % */ break; default: /* error, wrong format, store pattern */ format = pattern; c = '%'; break; } } } /* ISO C99 defines that when size is 0 and buffer is NULL we should * return number of characters that would have been written in case * the output string has been large enough without trailing 0. * Many implementations always returns number of characters necessary * to hold the string even if the above condition is not true so the * returned value can be used to check if buffer was large enough * and if not to allocate bigger buffer. Let's do the same. */ if( size < bufsize ) buffer[ size ] = c; ++size; } while( c != 0 ); va_end( args ); #ifndef __NO_ARGPOS__ } while( params.repeat ); if( params.arglst != argbuf ) hb_xfree( params.arglst ); #endif /* always set trailing \0 !!! */ if( bufsize ) buffer[ bufsize - 1 ] = 0; return ( int ) ( size - 1 ); }
HB_BOOL hb_mathGetError( HB_MATH_EXCEPTION * phb_exc, const char * szFunc, double arg1, double arg2, double dResult ) { #if defined( HB_MATH_ERRNO ) int errCode, v; HB_TRACE( HB_TR_DEBUG, ( "hb_mathGetError(%p,%s,%lf,%lf,%lf)", ( void * ) phb_exc, szFunc, arg1, arg2, dResult ) ); switch( errno ) { case 0: return HB_FALSE; case EDOM: case ERANGE: #if defined( EOVERFLOW ) case EOVERFLOW: #endif errCode = errno; break; default: HB_NUMTYPE( v, dResult ); if( ( v & _HB_NUM_NAN ) != 0 ) errCode = EDOM; else if( ( v & ( _HB_NUM_NINF | _HB_NUM_PINF ) ) != 0 ) errCode = ERANGE; else errCode = errno; } /* map math error types */ switch( errCode ) { case EDOM: phb_exc->type = HB_MATH_ERR_DOMAIN; phb_exc->error = "Argument not in domain of function"; break; case ERANGE: phb_exc->type = HB_MATH_ERR_SING; phb_exc->error = "Calculation results in singularity"; break; #if defined( EOVERFLOW ) case EOVERFLOW: phb_exc->type = HB_MATH_ERR_OVERFLOW; phb_exc->error = "Calculation result too large to represent"; break; #endif default: phb_exc->type = HB_MATH_ERR_UNKNOWN; phb_exc->error = "Unknown math error"; break; } phb_exc->funcname = szFunc; phb_exc->arg1 = arg1; phb_exc->arg2 = arg2; phb_exc->retval = dResult; phb_exc->handled = 0; phb_exc->retvalwidth = -1; /* we don't know */ phb_exc->retvaldec = -1; /* use standard SET DECIMALS */ { HB_MATH_HANDLERPROC mathHandler = hb_mathGetHandler(); if( mathHandler ) ( *mathHandler )( phb_exc ); } return HB_TRUE; #else HB_TRACE( HB_TR_DEBUG, ( "hb_mathGetError(%p,%s,%lf,%lf,%lf)", ( void * ) phb_exc, szFunc, arg1, arg2, dResult ) ); HB_SYMBOL_UNUSED( dResult ); HB_SYMBOL_UNUSED( arg1 ); HB_SYMBOL_UNUSED( arg2 ); HB_SYMBOL_UNUSED( szFunc ); #if defined( HB_MATH_HANDLER ) memcpy( phb_exc, &hb_mathErrData()->exception, sizeof( HB_MATH_EXCEPTION ) ); return phb_exc->type != HB_MATH_ERR_NONE; #else HB_SYMBOL_UNUSED( phb_exc ); return HB_FALSE; #endif #endif }