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