prtf.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,101 行 · 第 1/3 页
C
1,101 行
/****************************************************************************
*
* 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?