kolibrios/programs/develop/open watcom/trunk/clib/streamio/prtf.c

1101 lines
34 KiB
C
Raw Normal View History

/****************************************************************************
*
* 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 <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined( __WIDECHAR__ ) || defined( USE_MBCS_TRANSLATION )
#include <mbstring.h>
#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 );
}