/**************************************************************************** * * 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 #include #include #ifdef __WIDECHAR__ #include #else #include #endif #include #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 #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; if( specs->assign ) { CHECK_ELEMS( maxelem, nelem, -1 ); if( chsize == 1 ) { #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) char mbBuf[MB_CUR_MAX]; if( wctomb( mbBuf, c ) != -1 ) { *(FAR_ASCII_STRING)str = mbBuf[0]; if( _ismbblead( mbBuf[0] ) ) { CHECK_ELEMS( maxelem, nelem, -1 ); str++; *(FAR_ASCII_STRING)str = mbBuf[1]; } } else { return( 0 ); } #else *str = c; #endif } else { #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION ) 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; } else { return( 0 ); } #else *(FAR_UNI_STRING)str = c; #endif } str += chsize; } if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } while( !__F_NAME(isspace,iswspace)( c ) ); ugdone: uncget( c, specs ); done: if( specs->assign && len > 0 ) { CHECK_ELEMS( maxelem, nelem, -1 ); if( chsize == 1 ) { *str = '\0'; } else { *(FAR_UNI_STRING)str = 0; } } return( len ); } /* * report_scan -- handles %n */ static void report_scan( PTR_SCNF_SPECS specs, my_va_list *arg, int match ) { FAR_INT iptr; if( specs->assign ) { #if defined( __FAR_SUPPORT__ ) if( specs->far_ptr ) { iptr = va_arg( arg->v, int _WCFAR * ); } else if( specs->near_ptr ) { iptr = va_arg( arg->v, int _WCNEAR * ); } else { iptr = va_arg( arg->v, int * ); } #else iptr = va_arg( arg->v, int * ); #endif if( specs->char_var ) { *((FAR_CHAR)iptr) = match; } else if( specs->short_var ) { *((FAR_SHORT)iptr) = match; } else if( specs->long_var ) { *((FAR_LONG)iptr) = match; #if defined( __LONG_LONG_SUPPORT__ ) } else if( specs->long_long_var ) { *((FAR_INT64)iptr) = match; #endif } else { *iptr = match; } } } #if !defined( __WIDECHAR__ ) #define SCANSET_LENGTH (256 / 8) static const char lst_mask[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; /* * makelist -- create scanset for %[ directive. * scanset is stored as 256 bit flags in a 32 byte array. */ static const char *makelist( const char *format, char *scanset ) { int lst_chr; memset( scanset, 0, SCANSET_LENGTH ); if( (lst_chr = *format++) == '\0' ) return( format ); do { scanset[lst_chr >> 3] |= lst_mask[lst_chr & 0x07]; if( (lst_chr = *format) == '\0' ) break; ++format; } while( lst_chr != ']' ); return( format ); } #endif /* * scan_arb -- handles %[ */ static int scan_arb( PTR_SCNF_SPECS specs, my_va_list *arg, const CHAR_TYPE **format ) { unsigned width; FAR_STRING str; int len, c, not_flag; #if defined( __WIDECHAR__ ) const CHAR_TYPE *list; CHAR_TYPE ch; char in_list; #else char scanset[SCANSET_LENGTH]; #endif DEFINE_VARS( maxelem, nelem ); if( not_flag = (**format == '^') ) { ++(*format); } #if !defined( __WIDECHAR__ ) *format = makelist( *format, scanset ); #endif 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; width = specs->width; while( width > 0 ) { c = cget( specs ); if( specs->eoinp ) break; #if defined( __WIDECHAR__ ) list = *format; ch = *list; in_list = TRUE; while( c != ch ) { list++; ch = *list; if( ch == ']' ) { in_list = FALSE; break; } } if( in_list == not_flag ) { uncget( c, specs ); break; } #else if( ((scanset[c >> 3] & lst_mask[c & 0x07]) == 0) != not_flag ) { uncget( c, specs ); break; } #endif ++len; --width; if( specs->assign ) { CHECK_ELEMS( maxelem, nelem, -1 ); *str++ = c; } } if( specs->assign && len > 0 ) { CHECK_ELEMS( maxelem, nelem, -1 ); *str = '\0'; } #if defined( __WIDECHAR__ ) while( *(*format)++ != ']' ) /* skip past format specifier */ ; #endif return( len ); } /* * scan_float -- handles floating point numerical conversion * *** should implement buffer overflow protection *** */ static int scan_float( PTR_SCNF_SPECS specs, my_va_list *arg ) { double value; char *num_str, buf[80]; int len; int pref_len; long c; int digit_found; FAR_FLOAT fptr; char *p; T32 at; T32 ft; num_str = buf; pref_len = len = 0; for( ;; ) { c = cget( specs ); if( !__F_NAME(isspace,iswspace)( c ) ) break; ++pref_len; } if( specs->eoinp ) goto done; if( specs->width-- == 0 ) goto ugdone; if( c == '+' || c == '-' ) { *num_str++ = c; ++pref_len; if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } if( !__F_NAME(isdigit,iswdigit)( c ) && c != '.' ) goto ugdone; at.uWhole = 0; digit_found = FALSE; if( __F_NAME(isdigit,iswdigit)( c ) ) { digit_found = TRUE; do { *num_str++ = c; if( specs->short_var ) at.wd.hi = at.wd.hi * 10 + c - '0'; ++len; if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } while( __F_NAME(isdigit,iswdigit)( c ) ); } if( c == '.' ) { *num_str++ = c; ++len; /* account for the '.' */ if( (c = cgetw( specs )) == STOP_CHR ) goto done; if( !digit_found && !__F_NAME(isdigit,iswdigit)(c) ) goto ugdone; while( __F_NAME(isdigit,iswdigit)( c ) ) { *num_str++ = c; ++len; if( (c = cgetw( specs )) == STOP_CHR ) { break; } } if( specs->short_var ) { /* %hf fixed-point format 05-feb-92 */ ft.uWhole = 0; p = num_str; for( ;; ) { --p; if( *p == '.' ) break; ft.bite.b3 = *p - '0'; ft.uWhole = ft.uWhole / 10; } at.wd.lo = ft.wd.lo; } if( c == STOP_CHR ) { goto done; } } if( specs->short_var == 0 && (c == 'e' || c == 'E') ) { *num_str++ = c; ++len; if( (c = cgetw( specs )) == STOP_CHR ) goto done; if( c == '+' || c == '-' ) { *num_str++ = c; ++len; if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } if( !__F_NAME(isdigit,iswdigit)( c ) ) { len = 0; /* fast way to flag error */ } else { do { *num_str++ = c; ++len; if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } while( __F_NAME(isdigit,iswdigit)( c ) ); } } ugdone: uncget( (int)c, specs ); done: if( len > 0 ) { len += pref_len; if( specs->assign ) { *num_str = NULLCHAR; if( specs->short_var ) { if( buf[0] == '-' ) { at.sWhole = - at.sWhole; } } else { EFG_SCANF( buf, (void *)&value ); /* 27-mar-90 */ } #if defined( __FAR_SUPPORT__ ) if( specs->far_ptr ) { fptr = va_arg( arg->v, float _WCFAR * ); } else if( specs->near_ptr ) { fptr = va_arg( arg->v, float _WCNEAR * ); } else { fptr = va_arg( arg->v, float * ); } #else fptr = va_arg( arg->v, float * ); #endif if( specs->short_var ) { /* 05-feb-92 */ *((FAR_LONG) fptr) = at.uWhole; } else if( specs->long_var || specs->long_double_var ) { *((FAR_DOUBLE) fptr) = value; } else { *fptr = value; } } } return( len ); } static int radix_value( int c ) { if( c >= '0' && c <= '9' ) return( c - '0' ); c = __F_NAME(tolower,towlower)( c ); if( c >= 'a' && c <= 'f' ) return( c - 'a' + 10 ); return( 16 ); } /* * scan_int -- handles integer numeric conversion */ static int scan_int( PTR_SCNF_SPECS specs, my_va_list *arg, int base, int sign_flag ) { long value; int len; int pref_len; int c; int sign; int digit; FAR_INT iptr; #if defined( __LONG_LONG_SUPPORT__ ) unsigned long long long_value; FAR_INT64 llptr; long_value = 0; #endif value = 0; pref_len = len = 0; for( ;; ) { c = cget( specs ); if( !__F_NAME(isspace,iswspace)( c ) ) break; ++pref_len; } if( specs->eoinp ) goto done; if( specs->width-- == 0 ) goto ugdone; sign = '+'; if( sign_flag && (c == '+' || c == '-') ) { sign = c; ++pref_len; if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } if( base == 0 ) { if( c == '0' ) { len = 1; if( (c = cgetw( specs )) == STOP_CHR ) goto done; if( c == 'x' || c == 'X' ) { len = 0; ++pref_len; /* for the '0' */ ++pref_len; /* for the 'x' */ if( (c = cgetw( specs )) == STOP_CHR ) goto done; base = 16; } else { base = 8; } } else { base = 10; } } else if( base == 16 ) { if( c == '0' ) { len = 1; if( (c = cgetw( specs )) == STOP_CHR ) goto done; if( c == 'x' || c == 'X' ) { len = 0; ++pref_len; /* for the '0' */ ++pref_len; /* for the 'x' */ if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } } } #if defined( __LONG_LONG_SUPPORT__ ) if( specs->long_long_var ) { for( ;; ) { digit = radix_value( c ); if( digit >= base ) break; long_value = long_value * base + digit; ++len; if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } if( c == ':' && specs->p_format ) { for( ;; ) { ++len; if( (c = cgetw( specs )) == STOP_CHR ) goto done; digit = radix_value( c ); if( digit >= base ) break; long_value = long_value * base + digit; } } } else #endif { for( ;; ) { digit = radix_value( c ); if( digit >= base ) break; value = value * base + digit; ++len; if( (c = cgetw( specs )) == STOP_CHR ) { goto done; } } if( c == ':' && specs->p_format ) { for( ;; ) { ++len; if( (c = cgetw( specs )) == STOP_CHR ) goto done; digit = radix_value( c ); if( digit >= base ) break; value = value * base + digit; } } } ugdone: uncget( c, specs ); done: #if defined( __LONG_LONG_SUPPORT__ ) if( specs->long_long_var ) { if( sign == '-' ) { long_value =- long_value; } if( len > 0 ) { len += pref_len; if( specs->assign ) { #if defined( __FAR_SUPPORT__ ) if( specs->far_ptr ) { llptr = va_arg( arg->v, unsigned long long _WCFAR * ); } else if( specs->near_ptr ) { llptr = va_arg( arg->v, unsigned long long _WCNEAR * ); } else { llptr = va_arg( arg->v, unsigned long long * ); } #else llptr = va_arg( arg->v, unsigned long long * ); #endif *llptr = long_value; } } } else #endif { if( sign == '-' ) { value = -value; } if( len > 0 ) { len += pref_len; if( specs->assign ) { #if defined( __FAR_SUPPORT__ ) if( specs->far_ptr ) { iptr = va_arg( arg->v, int _WCFAR * ); } else if( specs->near_ptr ) { iptr = va_arg( arg->v, int _WCNEAR * ); } else { iptr = va_arg( arg->v, int * ); } #else iptr = va_arg( arg->v, int * ); #endif if( specs->char_var ) { *((FAR_CHAR)iptr) = value; } else if( specs->short_var ) { *((FAR_SHORT)iptr) = value; } else if( specs->long_var ) { *((FAR_LONG)iptr) = value; } else { *iptr = value; } } } } return( len ); } #ifdef SAFE_SCANF /* * null_arg -- check for a null pointer passed in arguments */ static int null_arg( PTR_SCNF_SPECS specs, my_va_list *arg ) { FAR_STRING str = NULL; va_list args_copy; va_copy( args_copy, arg->v ); #if defined( __FAR_SUPPORT__ ) if( specs->far_ptr ) { str = va_arg( args_copy, CHAR_TYPE _WCFAR * ); } else if( specs->near_ptr ) { CHAR_TYPE _WCNEAR *ptr; ptr = va_arg( args_copy, CHAR_TYPE _WCNEAR * ); /* The following should work: * * str = (ptr == NULL) ? (void _WCFAR *)NULL : ptr; * * but doesn't due to a bug in C compiler introduced in * 11.0 and fixe in OW 1.4. Ternary operator may be used * when building with OW 1.5. See also similar code in prtf.c. */ 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 ); return( str == NULL ? 1 : 0 ); } #endif #ifdef SAFE_SCANF int __F_NAME(__scnf_s,__wscnf_s)( PTR_SCNF_SPECS specs, const CHAR_TYPE *format, const char **msg, va_list args ) #else int __F_NAME(__scnf,__wscnf)( PTR_SCNF_SPECS specs, const CHAR_TYPE *format, va_list args ) #endif { int char_match; int items_converted; int items_assigned; int match_len; int c; int fmt_chr; my_va_list margs; margs = MY_VA_LIST( args ); char_match = items_assigned = items_converted = 0; specs->eoinp = 0; while( (fmt_chr = *format++) != NULLCHAR ) { if( __F_NAME(isspace,iswspace)( fmt_chr ) ) { char_match += scan_white( specs ); } else if( fmt_chr != '%' ) { if( (c = cget( specs )) != fmt_chr ) { if( !specs->eoinp ) uncget( c, specs ); break; } ++char_match; /* 27-oct-88 */ } else { /* fmt_chr == '%' */ format = get_opt( format, specs ); if( (fmt_chr = *format) != NULLCHAR ) ++format; #ifdef SAFE_SCANF if( fmt_chr != '%' ) { /* The '%' specifier is the only one not expecting pointer arg */ if( specs->assign && null_arg( specs, &margs ) ) { *msg = "%ptr -> NULL"; return( __F_NAME(EOF,WEOF) ); } } #endif switch( fmt_chr ) { case 'd': match_len = scan_int( specs, &margs, 10, TRUE ); goto check_match; case 'i': match_len = scan_int( specs, &margs, 0, TRUE ); goto check_match; case 'o': match_len = scan_int( specs, &margs, 8, TRUE ); goto check_match; case 'u': match_len = scan_int( specs, &margs, 10, TRUE ); goto check_match; case 'p': #if defined( __BIG_DATA__ ) specs->long_var = 1; /* indicate far pointer */ specs->p_format = 1; /* ... */ #endif // fall through case 'x': case 'X': match_len = scan_int( specs, &margs, 16, TRUE ); goto check_match; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': match_len = scan_float( specs, &margs ); goto check_match; #if !defined(__WIDECHAR__) && !defined(__NETWARE__) case 'S': specs->long_var = 1; /* fall through to %s handler */ #endif case 's': match_len = scan_string( specs, &margs ); goto check_match; case '[': match_len = scan_arb( specs, &margs, &format ); goto check_match; #if !defined(__WIDECHAR__) && !defined(__NETWARE__) case 'C': specs->long_var = 1; /* fall through to %c handler */ #endif case 'c': match_len = scan_char( specs, &margs ); check_match: if( match_len > 0 ) { char_match += match_len; ++items_converted; if( specs->assign ) { ++items_assigned; } } else { #ifdef SAFE_SCANF if( match_len < 0 ) { /* Matching failure caused by insufficient space in output * is not input failure, hence we won't return EOF regardless * of specs->eoinp state. */ ++items_converted; } #endif goto fail; } break; case 'n': report_scan( specs, &margs, char_match ); break; case '%': if( (c = cget( specs )) != '%' ) { if( !specs->eoinp ) uncget( c, specs ); goto fail; } else { char_match += 1; } break; } } if( specs->eoinp ) { while( *format == '%' ) { ++format; format = get_opt( format, specs ); if( *format == 'n' ) { ++format; #ifdef SAFE_SCANF if( specs->assign && null_arg( specs, &margs ) ) { *msg = "%ptr -> NULL"; return( __F_NAME(EOF,WEOF) ); } #endif report_scan( specs, &margs, char_match ); } else { break; } } break; } } fail: if( items_converted == 0 && specs->eoinp ) return( __F_NAME(EOF,WEOF) ); return( items_assigned ); }