1101 lines
34 KiB
C
1101 lines
34 KiB
C
|
/****************************************************************************
|
||
|
*
|
||
|
* 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 );
|
||
|
}
|