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 + -
显示快捷键?