/**************************************************************************** * * Open Watcom Project * * Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved. * * ======================================================================== * * This file contains Original Code and/or Modifications of Original * Code as defined in and that are subject to the Sybase Open Watcom * Public License version 1.0 (the 'License'). You may not use this file * except in compliance with the License. BY USING THIS FILE YOU AGREE TO * ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is * provided with the Original Code and Modifications, and is also * available at www.sybase.com/developer/opensource. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR * NON-INFRINGEMENT. Please see the License for the specific language * governing rights and limitations under the License. * * ======================================================================== * * Description: __prtf() - low level string formatter. * ****************************************************************************/ #define __LONG_LONG_SUPPORT__ #if !defined( __NETWARE__ ) && !defined( __UNIX__ ) #define USE_MBCS_TRANSLATION #endif #include "variety.h" #ifdef SAFE_PRINTF #include "saferlib.h" #endif #include "widechar.h" #include #include #include #include #include #if defined( __WIDECHAR__ ) || defined( USE_MBCS_TRANSLATION ) #include #endif #include "ftos.h" #include "farsupp.h" #include "printf.h" #include "prtscncf.h" #include "fixpoint.h" #include "myvalist.h" #define BUF_SIZE 72 /* 64-bit ints formatted as binary can get big */ #define TRUE 1 #define FALSE 0 #define PASCAL_STRING 'S' /* for Novell */ #define WIDE_CHAR_STRING 'S' #if defined( __QNX_386__ ) /* for use in QNX 32-bit shared library */ #pragma aux __prtf "_sl_*" far; #endif #if defined( __QNX__ ) #define EFG_PRINTF __EFG_Format #else #define EFG_PRINTF (*__EFG_printf) #endif extern FAR_STRING EFG_PRINTF( char *buffer, my_va_list *args, _mbcs_SPECS __SLIB *specs ); #if defined( __WIDECHAR__ ) #define _FAR_OTHER_STRING FAR_ASCII_STRING #else #define _FAR_OTHER_STRING FAR_UNI_STRING #endif #if defined( __WINDOWS_386__ ) #ifdef __SW_3S #pragma aux slib_callback_t modify [eax edx ecx fs gs]; #else #pragma aux slib_callback_t modify [fs gs]; #endif #endif /* forward references */ static const CHAR_TYPE *evalflags( const CHAR_TYPE *, SPECS __SLIB * ); static FAR_STRING formstring( CHAR_TYPE *, my_va_list *, SPECS __SLIB *, CHAR_TYPE * ); static const CHAR_TYPE * getprintspecs( const CHAR_TYPE *, my_va_list *, SPECS __SLIB * ); #ifdef USE_MBCS_TRANSLATION static void write_wide_string( FAR_UNI_STRING str, SPECS *specs, slib_callback_t *out_putc ); static void write_skinny_string( FAR_ASCII_STRING str, SPECS *specs, slib_callback_t *out_putc ); #endif #ifdef SAFE_PRINTF int __F_NAME(__prtf_s,__wprtf_s) #else int __F_NAME(__prtf,__wprtf) #endif ( void __SLIB *dest, /* parm for use by out_putc */ const CHAR_TYPE *format, /* pointer to format string */ va_list args, /* pointer to pointer to args*/ #ifdef SAFE_PRINTF const char **msg, /* rt-constraint message */ #endif slib_callback_t *out_putc ) /* char output routine */ { CHAR_TYPE buffer[ BUF_SIZE ]; CHAR_TYPE null_char = '\0'; CHAR_TYPE *a; FAR_STRING arg; const CHAR_TYPE *ctl; SPECS specs; specs._dest = dest; specs._flags = 0; specs._version = SPECS_VERSION; specs._output_count = 0; ctl = format; while( *ctl != NULLCHAR ) { if( *ctl != '%' ) { (out_putc)( &specs, *ctl++ ); } else { ++ctl; { my_va_list pargs; pargs = MY_VA_LIST( args ); ctl = getprintspecs( ctl, &pargs, &specs ); MY_VA_LIST( args ) = pargs; } specs._character = *ctl++; if( specs._character == NULLCHAR ) break; /* 05-jan-89 */ if( specs._character == 'n' ) { #ifdef SAFE_PRINTF /* The %n specifier is not allowed - too dangerous. */ *msg = "%n"; break; #else FAR_INT iptr; #if defined( __FAR_SUPPORT__ ) if( specs._flags & SPF_FAR ) { iptr = va_arg( args, int _WCFAR * ); } else if( specs._flags & SPF_NEAR ) { iptr = va_arg( args, int _WCNEAR * ); } else { iptr = va_arg( args, int * ); } #else iptr = va_arg( args, int * ); #endif if( specs._flags & SPF_CHAR ) { *((FAR_CHAR)iptr) = specs._output_count; } else if( specs._flags & SPF_SHORT ) { *((FAR_SHORT)iptr) = specs._output_count; } else if( specs._flags & SPF_LONG ) { *((FAR_LONG)iptr) = specs._output_count; #if defined( __LONG_LONG_SUPPORT__ ) } else if( specs._flags & SPF_LONG_LONG ) { *((FAR_INT64)iptr) = specs._output_count; #endif } else { *iptr = specs._output_count; } #endif /* SAFE_PRINTF */ } else { #ifdef SAFE_PRINTF if( specs._character == 's' || specs._character == 'S' ) { FAR_STRING str; va_list args_copy; /* Make sure %s argument is not NULL. Note that near pointers * in segmented models need special handling because only * offset will be NULL, not segment. */ va_copy( args_copy, args ); #if defined( __FAR_SUPPORT__ ) if( specs._flags & SPF_FAR ) { str = va_arg( args_copy, CHAR_TYPE _WCFAR * ); } else if( specs._flags & SPF_NEAR ) { CHAR_TYPE _WCNEAR *ptr; ptr = va_arg( args_copy, CHAR_TYPE _WCNEAR * ); if( ptr == NULL ) { str = NULL; } else { str = ptr; } } else { CHAR_TYPE *ptr; ptr = va_arg( args_copy, CHAR_TYPE * ); if( ptr == NULL ) { str = NULL; } else { str = ptr; } } #else str = va_arg( args_copy, CHAR_TYPE * ); #endif va_end( args_copy ); if( str == NULL ) { *msg = "%s -> NULL"; break; /* bail out */ } } #endif /* SAFE_PRINTF */ { my_va_list pargs; pargs = MY_VA_LIST( args ); arg = formstring( buffer, &pargs, &specs, &null_char ); MY_VA_LIST( args ) = pargs; } specs._fld_width -= specs._n0 + specs._nz0 + specs._n1 + specs._nz1 + specs._n2 + specs._nz2; if( !(specs._flags & SPF_LEFT_ADJUST) ) { if( specs._pad_char == ' ' ) { while( specs._fld_width > 0 ) { (out_putc)( &specs, ' ' ); --specs._fld_width; } } } a = buffer; while( specs._n0 > 0 ) { (out_putc)( &specs, *a ); ++a; --specs._n0; } while( specs._nz0 > 0 ) { (out_putc)( &specs, '0' ); --specs._nz0; } if( specs._character == 's' ) { #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) if( specs._flags & SPF_SHORT ) { write_skinny_string( (FAR_ASCII_STRING)arg, &specs, out_putc ); } else #elif !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) if( specs._flags & SPF_LONG ) { write_wide_string( (FAR_UNI_STRING)arg, &specs, out_putc ); } else #endif { while( specs._n1 > 0 ) { (out_putc)( &specs, *arg++ ); --specs._n1; } } } #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) else if( specs._character == WIDE_CHAR_STRING ) { write_wide_string( (FAR_UNI_STRING)arg, &specs, out_putc ); } else #elif !defined( __WIDECHAR__ ) && defined( __NETWARE__ ) else if( specs._character == WIDE_CHAR_STRING ) { } else #endif { while( specs._n1 > 0 ) { (out_putc)( &specs, *arg++ ); --specs._n1; } } while( specs._nz1 > 0 ) { (out_putc)( &specs, '0' ); --specs._nz1; } while( specs._n2 > 0 ) { (out_putc)( &specs, *arg ); ++arg; --specs._n2; } while( specs._nz2 > 0 ) { (out_putc)( &specs, '0' ); --specs._nz2; } if( specs._flags & SPF_LEFT_ADJUST ) { while( specs._fld_width > 0 ) { (out_putc)( &specs, ' ' ); --specs._fld_width; } } } } } return( specs._output_count ); } static const CHAR_TYPE * getprintspecs( const CHAR_TYPE *ctl, my_va_list *pargs, SPECS __SLIB *specs ) { specs->_pad_char = ' '; ctl = evalflags( ctl, specs ); specs->_fld_width = 0; if( *ctl == '*' ) { specs->_fld_width = va_arg( pargs->v, int ); if( specs->_fld_width < 0 ) { specs->_fld_width = - specs->_fld_width; specs->_flags |= SPF_LEFT_ADJUST; } ctl++; } else { while(( *ctl >= '0' ) && ( *ctl <= '9' )) { specs->_fld_width = specs->_fld_width * 10 + ( *ctl++ - '0' ); } } specs->_prec = -1; if( *ctl == '.' ) { specs->_prec = 0; ctl++; if( *ctl == '*' ) { specs->_prec = va_arg( pargs->v, int ); if( specs->_prec < 0 ) specs->_prec = -1; /* 19-jul-90 */ ctl++; } else { while(( *ctl >= '0' ) && ( *ctl <= '9' )) { specs->_prec = specs->_prec * 10 + ( *ctl++ - '0' ); } } /* "For b, d, i, o, u, x, X, e, E, f, g and G conversions, leading zeros (following any indication of sign or base) are used to pad the field width; no space padding is performed. If the 0 or - flags both appear, the 0 flag is ignored. For b, d, i, o, u, x or X conversions, if a precision is specified, the 0 flag is ignored. For other conversions, the behaviour is undefined." */ // if( specs->_prec != -1 ) specs->_pad_char = ' '; /* 30-jul-95 *//*removed by JBS*/ } switch( *ctl ) { case 'l': #if defined( __LONG_LONG_SUPPORT__ ) if( ctl[1] == 'l' ) { specs->_flags |= SPF_LONG_LONG; ctl += 2; break; } #endif /* fall through */ ZSPEC_CASE_LONG TSPEC_CASE_LONG case 'w': specs->_flags |= SPF_LONG; ctl++; break; case 'h': if( ctl[1] == 'h' ) { specs->_flags |= SPF_CHAR; ctl += 2; break; } specs->_flags |= SPF_SHORT; ctl++; break; #if defined( __LONG_LONG_SUPPORT__ ) case 'I': if(( ctl[1] == '6' ) && ( ctl[2] == '4' )) { specs->_flags |= SPF_LONG_LONG; ctl += 3; } break; JSPEC_CASE_LLONG /* fall through */ #endif case 'L': specs->_flags |= SPF_LONG_DOUBLE | SPF_LONG_LONG; ctl++; break; #if defined( __FAR_SUPPORT__ ) case 'F': /* conflicts with ISO-defined 'F' conversion */ /* fall through */ #endif case 'W': /* 8086 specific flag for FAR pointer */ specs->_flags |= SPF_FAR; ctl++; break; case 'N': /* 8086 specific flag for NEAR pointer */ specs->_flags |= SPF_NEAR; ctl++; break; #if defined( TSPEC_IS_INT ) || defined( ZSPEC_IS_INT ) TSPEC_CASE_INT /* If either 't' or 'z' spec corresponds to 'int', */ ZSPEC_CASE_INT /* we need to parse and ignore the spec. */ ctl++; break; #endif } return( ctl ); } static const CHAR_TYPE *evalflags( const CHAR_TYPE *ctl, SPECS __SLIB *specs ) { specs->_flags = 0; for( ; ; ctl++ ) { if( *ctl == '-' ) { specs->_flags |= SPF_LEFT_ADJUST; } else if( *ctl == '#' ) { specs->_flags |= SPF_ALT; } else if( *ctl == '+' ) { specs->_flags |= SPF_FORCE_SIGN; specs->_flags &= ~SPF_BLANK; } else if( *ctl == ' ' ) { if( ( specs->_flags & SPF_FORCE_SIGN ) == 0 ) { specs->_flags |= SPF_BLANK; } } else if( *ctl == '0' ) { specs->_pad_char = '0'; #ifdef __QNX__ specs->_flags |= SPF_ZERO_PAD; #endif } else { break; } } return( ctl ); } static int far_strlen( FAR_STRING s, int precision ) { int len; len = 0; while(( len != precision ) && ( *s++ != NULLCHAR )) ++len; return( len ); } /* * far_other_strlen - calculates the length of an ascii string * for the unicode version * - calculates the length of a unicode string for * the standard version */ static int far_other_strlen( FAR_STRING s, int precision ) { int len = 0; _FAR_OTHER_STRING ptr = (_FAR_OTHER_STRING)s; #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) char mbBuf[MB_CUR_MAX]; int chBytes; if( precision == -1 ) { while( *ptr ) { chBytes = wctomb( mbBuf, *ptr++ ); if( chBytes != -1 ) { len += chBytes; } } return( len ); } while( *ptr && ( len <= precision )) { chBytes = wctomb( mbBuf, *ptr++ ); if( chBytes != -1 ) { len += chBytes; } } return(( len <= precision ) ? len : precision ); #else while( *ptr++ && ( len != precision )) ++len; return( len ); #endif } static void fmt4hex( unsigned value, CHAR_TYPE *buf, int maxlen ) { int i, len; __F_NAME(itoa,_itow)( value, buf, 16 ); len = __F_NAME(strlen,wcslen)( buf ); for( i = maxlen - 1; len; --i ) { --len; buf[i] = buf[len]; } while( i >= 0 ) { buf[i] = '0'; --i; } buf[maxlen] = NULLCHAR; } static void FixedPoint_Format( CHAR_TYPE *buf, long value, SPECS __SLIB *specs ) { T32 at; int i; CHAR_TYPE *bufp; at.sWhole = value; if( at.sWhole < 0 ) { at.sWhole = - at.sWhole; *buf++ = '-'; } if( specs->_prec == -1 ) specs->_prec = 4; __F_NAME(itoa,_itow)( at.wd.hi, buf, 10 ); bufp = buf; /* remember start address of buffer */ while( *buf ) ++buf; if( specs->_prec != 0 ) { *buf++ = '.'; for( i = 0; i < specs->_prec; i++ ) { at.wd.hi = 0; at.uWhole *= 10; *buf++ = at.bite.b3 + '0'; } *buf = NULLCHAR; } if( at.wd.lo & 0x8000 ) { /* fraction >= .5, need to round */ for(;;) { /* 22-dec-91 */ if( buf == bufp ) { *buf++ = '1'; while( *buf == '0' ) ++buf; if( *buf == '.' ) { *buf++ = '0'; *buf++ = '.'; while( *buf == '0' ) { ++buf; } } *buf++ = '0'; *buf = NULLCHAR; break; } --buf; if( *buf == '.' ) --buf; if( *buf != '9' ) { ++ *buf; break; } *buf = '0'; } } } static void float_format( CHAR_TYPE *buffer, my_va_list *pargs, SPECS __SLIB *specs ) { #ifdef __WIDECHAR__ char mbBuffer[BUF_SIZE*MB_CUR_MAX]; _mbcs_SPECS mbSpecs; int count; size_t rc; char *p; #endif // __WIDECHAR__ #ifdef __WIDECHAR__ /* * EFG_PRINTF can only handle MBCS buffers and the MBCS version of the * SPECS structure. So, make a _mbcs_SPECS structure equivalent to the * _wide_SPECS one, and use that instead. Note that we can't use * memcpy() because some field sizes are different. */ mbSpecs._dest = NULL; /* this field isn't actually used */ mbSpecs._flags = specs->_flags; mbSpecs._version = specs->_version; mbSpecs._fld_width = specs->_fld_width; mbSpecs._prec = specs->_prec; mbSpecs._output_count = specs->_output_count; mbSpecs._n0 = specs->_n0; mbSpecs._nz0 = specs->_nz0; mbSpecs._n1 = specs->_n1; mbSpecs._nz1 = specs->_nz1; mbSpecs._n2 = specs->_n2; mbSpecs._nz2 = specs->_nz2; mbSpecs._character = (char)specs->_character; mbSpecs._pad_char = (char)specs->_pad_char; #endif #ifdef __WIDECHAR__ EFG_PRINTF( mbBuffer, pargs, &mbSpecs ); #else EFG_PRINTF( buffer, pargs, specs ); #endif #ifdef __WIDECHAR__ /* * Now convert the returned information back into our _wide_SPECS * structure. We can't just use mbstowcs because it's an array of * characters, not a string. */ p = mbBuffer; for( count = 0; count < BUF_SIZE; count++ ) { rc = mbtowc( &(buffer[count]), p, MB_CUR_MAX ); if( rc == -1 ) { buffer[count] = L'?'; } p = _mbsinc( p ); } specs->_flags = mbSpecs._flags; specs->_version = mbSpecs._version; specs->_fld_width = mbSpecs._fld_width; specs->_prec = mbSpecs._prec; specs->_output_count = mbSpecs._output_count; specs->_n0 = mbSpecs._n0; specs->_nz0 = mbSpecs._nz0; specs->_n1 = mbSpecs._n1; specs->_nz1 = mbSpecs._nz1; specs->_n2 = mbSpecs._n2; specs->_nz2 = mbSpecs._nz2; specs->_character = (wchar_t) mbSpecs._character; specs->_pad_char = (wchar_t) mbSpecs._pad_char; #endif } static void SetZeroPad( SPECS __SLIB *specs ) { int n; if( !(specs->_flags & SPF_LEFT_ADJUST) ) { if( specs->_pad_char == '0' ) { n = specs->_fld_width - specs->_n0 - specs->_nz0 - specs->_n1 - specs->_nz1 - specs->_n2 - specs->_nz2; if( n > 0 ) { specs->_nz0 += n; } } } } #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) static void write_wide_string( FAR_UNI_STRING str, SPECS *specs, slib_callback_t *out_putc ) { int bytes; char mbBuf[MB_CUR_MAX]; char *mbBufPtr; while( specs->_n1 > 0 ) { bytes = wctomb( mbBuf, *str++ ); if( bytes != -1 ) { if( bytes <= specs->_n1 ) { mbBufPtr = mbBuf; while( bytes-- ) { (out_putc)( specs, *mbBufPtr++ ); --specs->_n1; } } else { specs->_n1 = 0; } } } } #endif #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) static void write_skinny_string( FAR_ASCII_STRING str, SPECS *specs, slib_callback_t *out_putc ) { int bytes; wchar_t wc; FAR_ASCII_STRING mbPtr = str; char mbBuf[MB_CUR_MAX]; while( specs->_n1 > 0 ) { mbBuf[0] = *mbPtr++; if( _ismbblead( mbBuf[0] ) ) mbBuf[1] = *mbPtr++; bytes = mbtowc( &wc, mbBuf, MB_CUR_MAX ); if( bytes <= specs->_n1 ) { if( bytes != -1 ) { (out_putc)( specs, wc ); specs->_n1 -= bytes; } } else { specs->_n1 = 0; } } } #endif static FAR_STRING formstring( CHAR_TYPE *buffer, my_va_list *pargs, SPECS __SLIB *specs, CHAR_TYPE *null_string ) { FAR_STRING arg; int length; int radix; #if defined( __LONG_LONG_SUPPORT__ ) unsigned long long long_long_value; #endif unsigned long long_value; unsigned int int_value; #if defined( __FAR_SUPPORT__ ) unsigned int seg_value; #endif #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) int bytes; #endif arg = buffer; specs->_n0 = specs->_nz0 = specs->_n1 = specs->_nz1 = specs->_n2 = specs->_nz2 = 0; if( ( specs->_character == 'b' ) || ( specs->_character == 'o' ) || ( specs->_character == 'u' ) || ( specs->_character == 'x' ) || ( specs->_character == 'X' ) ) { #if defined( __LONG_LONG_SUPPORT__ ) if( specs->_flags & SPF_LONG_LONG ) { long_long_value = va_arg( pargs->v, unsigned long long ); } else #endif if( specs->_flags & SPF_LONG ) { long_value = va_arg( pargs->v, unsigned long ); } else { long_value = va_arg( pargs->v, unsigned ); if( specs->_flags & SPF_SHORT ) { /* JBS 92/02/12 */ long_value = (unsigned short) long_value; } else if( specs->_flags & SPF_CHAR ) { long_value = (unsigned char)long_value; } } } else if( ( specs->_character == 'd' ) || ( specs->_character == 'i' ) ) { #if defined( __LONG_LONG_SUPPORT__ ) if( specs->_flags & SPF_LONG_LONG ) { long_long_value = va_arg( pargs->v, long long ); } else #endif if( specs->_flags & SPF_LONG ) { long_value = va_arg( pargs->v, long ); } else { long_value = va_arg( pargs->v, int ); if( specs->_flags & SPF_SHORT ) { /* JBS 92/02/12 */ long_value = (short) long_value; } else if( specs->_flags & SPF_CHAR ) { long_value = (signed char)long_value; } } { int negative = FALSE; #if defined( __LONG_LONG_SUPPORT__ ) if( specs->_flags & SPF_LONG_LONG ) { if( (long long)long_long_value < 0 ) { negative = TRUE; } } else #endif if( (long)long_value < 0 ) { negative = TRUE; } if( negative ) { buffer[specs->_n0++] = '-'; #if defined( __LONG_LONG_SUPPORT__ ) if( specs->_flags & SPF_LONG_LONG ) { long_long_value = -long_long_value; } else #endif long_value = - long_value; } else if( specs->_flags & SPF_FORCE_SIGN ) { buffer[specs->_n0++] = '+'; } else if( specs->_flags & SPF_BLANK ) { buffer[specs->_n0++] = ' '; } } } radix = 10; /* base 10 for 'd', 'i' and 'u' */ switch( specs->_character ) { case 'f': case 'F': if( specs->_flags & SPF_SHORT ) { /* "%hf" 13-jun-91 */ long_value = va_arg( pargs->v, long ); FixedPoint_Format( buffer, long_value, specs ); specs->_n1 = far_strlen( buffer, -1 ); break; } /* types f & F fall through */ case 'g': case 'G': case 'e': case 'E': float_format( buffer, pargs, specs ); SetZeroPad( specs ); arg++; // = &buffer[1]; break; case 's': #ifndef __NETWARE__ case WIDE_CHAR_STRING: #else case PASCAL_STRING: #endif // arg has been initialized to point to buffer // set buffer[0] to a null character assuming pointer will be NULL // If pointer is not null, then arg will be assigned the pointer buffer[0] = '\0'; // assume null pointer #if defined( __FAR_SUPPORT__ ) if( specs->_flags & SPF_FAR ) { CHAR_TYPE _WCFAR *temp = va_arg( pargs->v, CHAR_TYPE _WCFAR * ); if( temp ) { arg = temp; } } else if( specs->_flags & SPF_NEAR ) { CHAR_TYPE _WCNEAR *temp = va_arg( pargs->v, CHAR_TYPE _WCNEAR * ); if( temp ) { arg = (void *)temp; } } else { CHAR_TYPE *temp = va_arg( pargs->v, CHAR_TYPE * ); if( temp ) { arg = temp; } } #else { CHAR_TYPE *temp = va_arg( pargs->v, CHAR_TYPE * ); if( temp ) { arg = temp; } } #endif #ifdef __NETWARE__ if( specs->_character == PASCAL_STRING ) { #ifdef __WIDECHAR__ if( specs->_flags & SPF_SHORT ) #else if( specs->_flags & SPF_LONG ) #endif { length = *( (_FAR_OTHER_STRING)arg ); arg = (FAR_STRING)( (_FAR_OTHER_STRING)arg + 1 ); } else { length = *arg++; } } else #elif !defined( __NETWARE__ ) && !defined( __WIDECHAR__ ) if( specs->_character == WIDE_CHAR_STRING ) { if( specs->_flags & SPF_SHORT ) { length = far_strlen( arg, specs->_prec ); } else { length = far_other_strlen( arg, specs->_prec ); } } else #endif #ifdef __WIDECHAR__ if( specs->_flags & SPF_SHORT ) { #else if( specs->_flags & SPF_LONG ) { #endif length = far_other_strlen( arg, specs->_prec ); } else { length = far_strlen( arg, specs->_prec ); } specs->_n1 = length; if(( specs->_prec >= 0 ) && ( specs->_prec < length )) { specs->_n1 = specs->_prec; } break; case 'x': case 'X': if( specs->_flags & SPF_ALT ) { #if defined( __LONG_LONG_SUPPORT__ ) if( specs->_flags & SPF_LONG_LONG ) { if( long_long_value != 0 ) { buffer[specs->_n0++] = '0'; buffer[specs->_n0++] = specs->_character; } } else #endif if( long_value != 0 ) { buffer[specs->_n0++] = '0'; buffer[specs->_n0++] = specs->_character; } } radix = 16; /* base 16 */ goto processNumericTypes; case 'b': /* CDH 2003 Apr 23 *//* Add binary mode */ radix = 2; /* base 2 */ goto processNumericTypes; case 'o': radix = 8; /* base 8 */ /* 'o' conversion falls through */ case 'd': case 'i': case 'u': // 'x' and 'X' jumps here processNumericTypes: if( specs->_prec != -1 ) specs->_pad_char = ' '; /* 30-jul-95, 11-may-99 */ /* radix contains the base; 8 for 'o', 10 for 'd' and 'i' and 'u', 16 for 'x' and 'X', and 2 for 'b' */ arg = &buffer[ specs->_n0 ]; #if defined( __LONG_LONG_SUPPORT__ ) if( specs->_flags & SPF_LONG_LONG ) { if(( specs->_prec == 0 ) && ( long_long_value == 0 )) { *arg = '\0'; length = 0; } else { __F_NAME(ulltoa,_ulltow)( long_long_value, &buffer[specs->_n0], radix ); if( specs->_character == 'X' ) { __F_NAME(strupr,_wcsupr)( buffer ); } length = far_strlen( arg, -1 ); } } else #endif if(( specs->_prec == 0 ) && ( long_value == 0 )) { *arg = '\0'; length = 0; } else { __F_NAME(ultoa,_ultow)( long_value, &buffer[specs->_n0], radix ); if( specs->_character == 'X' ) { __F_NAME(strupr,_wcsupr)( buffer ); } length = far_strlen( arg, -1 ); } specs->_n1 = length; if( specs->_n1 < specs->_prec ) { specs->_nz0 = specs->_prec - specs->_n1; } else if( specs->_flags & SPF_ALT && radix < 10 && (!length || (arg[0] != '0')) ) { /* For 'b' and 'o' conversions, alternate format forces the number to * start with a zero (effectively increases precision by one), but * only if it doesn't start with a zero already. */ ++specs->_nz0; } if( specs->_prec == -1 ) { SetZeroPad( specs ); } break; case 'p': case 'P': #if defined( __FAR_SUPPORT__ ) #if defined( __BIG_DATA__ ) if( !( specs->_flags & (SPF_NEAR|SPF_FAR) ) ) { specs->_flags |= SPF_FAR; } if( specs->_fld_width == 0 ) { if( specs->_flags & SPF_NEAR ) { specs->_fld_width = sizeof( unsigned ) * 2; } else { specs->_fld_width = sizeof( CHAR_TYPE _WCFAR * ) * 2 + 1; } } #else if( specs->_fld_width == 0 ) { if( specs->_flags & SPF_FAR ) { specs->_fld_width = sizeof( CHAR_TYPE _WCFAR * ) * 2 + 1; } else { specs->_fld_width = sizeof( unsigned ) * 2; } } #endif #else if( specs->_fld_width == 0 ) { specs->_fld_width = sizeof( unsigned ) * 2; } #endif specs->_flags &= ~( SPF_BLANK | SPF_FORCE_SIGN ); int_value = va_arg( pargs->v, unsigned ); /* offset */ #if defined( __FAR_SUPPORT__ ) if( specs->_flags & SPF_FAR ) { seg_value = va_arg( pargs->v, unsigned ) & 0xFFFF; /* segment */ /* use "unsigned short" for 386 instead of "unsigned" 21-jul-89 */ fmt4hex( seg_value, buffer, sizeof( unsigned short ) * 2 ); buffer[sizeof(unsigned short)*2] = ':'; fmt4hex( int_value, buffer + sizeof( unsigned short ) * 2 + 1, sizeof( unsigned ) * 2 ); } else { fmt4hex( int_value, buffer, sizeof( unsigned ) * 2 ); } #else fmt4hex( int_value, buffer, sizeof( unsigned ) * 2 ); #endif if( specs->_character == 'P' ) { __F_NAME(strupr,_wcsupr)( buffer ); } specs->_n0 = far_strlen( arg, -1 ); break; case 'c': #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) if( specs->_flags & SPF_SHORT ) { char * mbPtr; char mbBuf[MB_CUR_MAX]; wchar_t wc; mbPtr = va_arg( pargs->v, char* ); mbBuf[0] = mbPtr[0]; if( _ismbblead( mbBuf[0] ) ) mbBuf[1] = mbPtr[1]; if( mbtowc( &wc, mbBuf, MB_CUR_MAX ) != -1 ) { buffer[0] = wc; } } else { buffer[0] = va_arg( pargs->v, int ); } specs->_n0 = 1; #elif !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) specs->_n0 = 1; if( specs->_flags & SPF_LONG ) { char mbBuf[MB_CUR_MAX]; wchar_t wc; wc = va_arg( pargs->v, int ); if( wctomb( mbBuf, wc ) != -1 ) { buffer[0] = mbBuf[0]; if( _ismbblead( mbBuf[0] ) ) { buffer[1] = mbBuf[1]; specs->_n0++; } } } else { buffer[0] = va_arg( pargs->v, int ); } #else specs->_n0 = 1; buffer[0] = va_arg( pargs->v, int ); #endif break; #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) case 'C': bytes = wctomb( buffer, va_arg( pargs->v, int ) ); // if( bytes != -1 && bytes <= specs->_prec ) { if( bytes != -1 ) { /* Normative Addendum 4.5.3.3.1: no precision */ specs->_n0 = bytes; } else { specs->_n0 = 0; } break; #endif default: specs->_fld_width = 0; buffer[ 0 ] = specs->_character; specs->_n0 = 1; break; } return( arg ); }