scnf.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,117 行 · 第 1/3 页

C
1,117
字号
/****************************************************************************
*
*                            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:  Platform independent worker routines for scanf().
*
****************************************************************************/


#define __LONG_LONG_SUPPORT__

#if !defined( __NETWARE__ ) && !defined( __UNIX__ )
    #define USE_MBCS_TRANSLATION
#endif

#include "variety.h"
#ifdef SAFE_SCANF
    #include "saferlib.h"
#endif
#include "widechar.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WIDECHAR__
    #include <wctype.h>
#else
    #include <ctype.h>
#endif
#include <stdarg.h>
#include "scanf.h"
#include "prtscncf.h"
#include "fixpoint.h"
#include "ftos.h"
#include "farsupp.h"
#include "myvalist.h"
#if defined( __WIDECHAR__ ) || defined( USE_MBCS_TRANSLATION )
    #include <mbstring.h>
#endif

#define TRUE    1
#define FALSE   0

#define STOP_CHR 0xFFFFFFFF

#define EFG_SCANF (*__EFG_scanf)

/* internal file/string get, unget routines */
#ifdef __WINDOWS_386__
    #ifdef __SW_3S
        #pragma aux cget modify [eax edx ecx fs gs]
        #pragma aux uncget modify [eax edx ecx fs gs]
    #else
        #pragma aux cget modify [fs gs]
        #pragma aux uncget modify [fs gs]
    #endif
#endif

#if defined(__HUGE__)
    #define SCNF_FAR    _WCFAR
#else
    #define SCNF_FAR
#endif


/* Macros to reduce the already large number of ifdefs in the code */
#ifdef SAFE_SCANF

    #define GET_MAXELEM(x)      x = va_arg( arg->v, size_t )
    #define DEFINE_VARS(x,y)    size_t x, y = 0
    #define CHECK_ELEMS(x,y,z)  if( x < ++y ) return( z )
#else

    #define GET_MAXELEM(x)
    #define DEFINE_VARS(x,y)
    #define CHECK_ELEMS(x,y,z)

#endif

static int cget( PTR_SCNF_SPECS specs )
{
    return( (*((specs)->cget_rtn))( specs ) );
}


static void uncget( int c, PTR_SCNF_SPECS specs )
{
    ((*((specs)->uncget_rtn))( c, specs ));
}


/*
 * get_opt -- get option string for current conversion directive
 *            and fills in the SCNF_SPECS structure.
 *            returns advanced format string pointer.
 */
static const CHAR_TYPE *get_opt( const CHAR_TYPE *opt_str, PTR_SCNF_SPECS specs )
{
    int     c, width;

    specs->assign           = TRUE;
    specs->far_ptr          = 0;
    specs->near_ptr         = 0;
    specs->char_var         = 0;
    specs->short_var        = 0;
    specs->long_var         = 0;
    specs->long_long_var    = 0;
    specs->long_double_var  = 0;
    specs->p_format         = 0;                    /* 21-nov-89 */
    specs->width            = -1;
    if( *opt_str == '*' ) {
        specs->assign = FALSE;
        ++opt_str;
    }
    c = *opt_str;
    if( __F_NAME(isdigit,iswdigit)( c ) ) {
        width = 0;
        do {
            width *= 10;
            width += ( c - '0' );
            c = *++opt_str;
        } while( __F_NAME(isdigit,iswdigit)( c ) );
        specs->width = width;
    }
    switch( *opt_str ) {
    case 'N':
        specs->near_ptr = 1;
        ++opt_str;
        break;
#if defined( __FAR_SUPPORT__ )
    case 'F':   /* conflicts with ISO-defined 'F' conversion */
        /* fall through */
#endif
    case 'W':
        specs->far_ptr = 1;
        ++opt_str;
        break;
    }
    switch( *opt_str ) {
    case 'h':
        if( opt_str[1] == 'h' ) {
            specs->char_var = 1;
            opt_str += 2;
            break;
        }
        specs->short_var = 1;
        ++opt_str;
        break;
    case 'l':
#if defined( __LONG_LONG_SUPPORT__ )
        if( opt_str[1] == 'l' ) {
            specs->long_long_var = 1;
            opt_str += 2;
            break;
        }
#endif
        /* fall through */
    ZSPEC_CASE_LONG
    TSPEC_CASE_LONG
    case 'w':
        specs->long_var = 1;
        ++opt_str;
        break;
#if defined( __LONG_LONG_SUPPORT__ )
    JSPEC_CASE_LLONG
        /* fall through */
#endif
    case 'L':
        specs->long_double_var = 1;
        specs->long_long_var = 1;
        ++opt_str;
        break;
#if defined( __LONG_LONG_SUPPORT__ )
    case 'I':
        if( opt_str[1] == '6' && opt_str[2] == '4' ) {
            specs->long_long_var = 1;
            opt_str += 3;
        }
        break;
#endif
#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.            */
        ++opt_str;
        break;
#endif
    }
    return( opt_str );
}


/*
 * scan_white -- scan white space from input stream
 */
static int scan_white( PTR_SCNF_SPECS specs )
{
    int     c, len;

    len = 0;
    for( ;; ) {
        c = cget( specs );
        if( !__F_NAME(isspace,iswspace)( c ) )
            break;
        ++len;
    }
    if( !specs->eoinp )
        uncget( c, specs );
    return( len );
}

/*
 * scan_char -- handles %c and %C
 */
static int scan_char( PTR_SCNF_SPECS specs, my_va_list *arg )
{
    int             len;
    int             width;
    FAR_STRING      str;
    int             c;
    DEFINE_VARS( maxelem, nelem );

    if( specs->assign ) {
#if defined( __FAR_SUPPORT__ )
        if( specs->far_ptr ) {
            str = va_arg( arg->v, CHAR_TYPE _WCFAR * );
        } else if( specs->near_ptr ) {
            str = va_arg( arg->v, CHAR_TYPE _WCNEAR * );
        } else {
            str = va_arg( arg->v, CHAR_TYPE * );
        }
#else
        str = va_arg( arg->v, CHAR_TYPE * );
#endif
        GET_MAXELEM( maxelem );
    }
    len = 0;
    if( (width = specs->width) == -1 )
        width = 1;
    while( width > 0 ) {
        c = cget( specs );
        if( specs->eoinp )
            break;
        ++len;
        --width;
        if( specs->assign ) {
            CHECK_ELEMS( maxelem, nelem, -1 );
#if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
            if( specs->short_var ) {
                char        mbBuf[MB_CUR_MAX];

                if( wctomb( mbBuf, c ) != -1 ) {
                    *(FAR_ASCII_STRING)str = mbBuf[0];
                    str = (FAR_STRING) ( (FAR_ASCII_STRING)str + 1 );
                    if( _ismbblead( mbBuf[0] ) )  {
                        CHECK_ELEMS( maxelem, nelem, -1 );
                        *(FAR_ASCII_STRING)str = mbBuf[1];
                        str = (FAR_STRING) ( (FAR_ASCII_STRING)str + 1 );
                    }
                } else {
                    return( 0 );
                }
            } else {
                *str++ = c;
            }
#elif defined( USE_MBCS_TRANSLATION )
            if( specs->long_var ) {
                wchar_t     wc;
                char        mbBuf[MB_CUR_MAX];

                mbBuf[0] = c;
                if( _ismbblead( mbBuf[0] ) )
                    mbBuf[1] = cget( specs );
                if( mbtowc( &wc, mbBuf, MB_CUR_MAX ) != -1 ) {
                    *(FAR_UNI_STRING)str = wc;
                    str = (FAR_STRING) ( (FAR_UNI_STRING)str + 1 );
                } else {
                    return( 0 );
                }
            } else {
                *str++ = c;
            }
#else
            *str++ = c;
#endif
        }
    }
    return( len );
}


/*
 * cgetw -- cget which keeps track of field width.
 *          returns STOP_CHR on end of field or end of file.
 */
static long cgetw( PTR_SCNF_SPECS specs )
{
    int     c;

    if( specs->width-- == 0 )
        return( STOP_CHR );
    c = cget( specs );
    return( !( specs->eoinp ) ? c : STOP_CHR );
}


/*
 * scan_string -- handles %s and %S
 */
static int scan_string( PTR_SCNF_SPECS specs, my_va_list *arg )
{
    int                     c;
    int                     len;
    FAR_ASCII_STRING        str;
    char                    chsize;
    DEFINE_VARS( maxelem, nelem );

    if( specs->long_var ) {         /* %ls or %ws */
        chsize = sizeof( wchar_t );
    } else if( specs->short_var ) { /* %hs */
        chsize = 1;
    } else {                        /* %s */
        chsize = CHARSIZE;
    }
    if( specs->assign ) {
#if defined( __FAR_SUPPORT__ )
        if( specs->far_ptr ) {
            str = va_arg( arg->v, char _WCFAR * );
        } else if( specs->near_ptr ) {
            str = va_arg( arg->v, char _WCNEAR * );
        } else {
            str = va_arg( arg->v, char * );
        }
#else
        str = va_arg( arg->v, char * );
#endif
        GET_MAXELEM( maxelem );
    }
    len = 0;
    for( ;; ) {
        c = cget( specs );
        if( !__F_NAME(isspace,iswspace)( c ) )
            break;
        ++len;
    }
    if( specs->eoinp ) {
        len = 0;            /* since this is eof, no input done */
        goto done;
    }
    if( specs->width-- == 0 )
        goto ugdone;
    do {
        ++len;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?