Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /****************************************************************************
  2. *
  3. *                            Open Watcom Project
  4. *
  5. *    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
  6. *
  7. *  ========================================================================
  8. *
  9. *    This file contains Original Code and/or Modifications of Original
  10. *    Code as defined in and that are subject to the Sybase Open Watcom
  11. *    Public License version 1.0 (the 'License'). You may not use this file
  12. *    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
  13. *    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
  14. *    provided with the Original Code and Modifications, and is also
  15. *    available at www.sybase.com/developer/opensource.
  16. *
  17. *    The Original Code and all software distributed under the License are
  18. *    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  19. *    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
  20. *    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
  21. *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
  22. *    NON-INFRINGEMENT. Please see the License for the specific language
  23. *    governing rights and limitations under the License.
  24. *
  25. *  ========================================================================
  26. *
  27. * Description:  Platform independent worker routines for scanf().
  28. *
  29. ****************************************************************************/
  30.  
  31.  
  32. #define __LONG_LONG_SUPPORT__
  33.  
  34. #if !defined( __NETWARE__ ) && !defined( __UNIX__ )
  35.     #define USE_MBCS_TRANSLATION
  36. #endif
  37.  
  38. #include "variety.h"
  39. #ifdef SAFE_SCANF
  40.     #include "saferlib.h"
  41. #endif
  42. #include "widechar.h"
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #ifdef __WIDECHAR__
  47.     #include <wctype.h>
  48. #else
  49.     #include <ctype.h>
  50. #endif
  51. #include <stdarg.h>
  52. #include "scanf.h"
  53. #include "prtscncf.h"
  54. #include "fixpoint.h"
  55. #include "ftos.h"
  56. #include "farsupp.h"
  57. #include "myvalist.h"
  58. #if defined( __WIDECHAR__ ) || defined( USE_MBCS_TRANSLATION )
  59.     #include <mbstring.h>
  60. #endif
  61.  
  62. #define TRUE    1
  63. #define FALSE   0
  64.  
  65. #define STOP_CHR 0xFFFFFFFF
  66.  
  67. #define EFG_SCANF (*__EFG_scanf)
  68.  
  69. /* internal file/string get, unget routines */
  70. #ifdef __WINDOWS_386__
  71.     #ifdef __SW_3S
  72.         #pragma aux cget modify [eax edx ecx fs gs]
  73.         #pragma aux uncget modify [eax edx ecx fs gs]
  74.     #else
  75.         #pragma aux cget modify [fs gs]
  76.         #pragma aux uncget modify [fs gs]
  77.     #endif
  78. #endif
  79.  
  80. #if defined(__HUGE__)
  81.     #define SCNF_FAR    _WCFAR
  82. #else
  83.     #define SCNF_FAR
  84. #endif
  85.  
  86.  
  87. /* Macros to reduce the already large number of ifdefs in the code */
  88. #ifdef SAFE_SCANF
  89.  
  90.     #define GET_MAXELEM(x)      x = va_arg( arg->v, size_t )
  91.     #define DEFINE_VARS(x,y)    size_t x, y = 0
  92.     #define CHECK_ELEMS(x,y,z)  if( x < ++y ) return( z )
  93. #else
  94.  
  95.     #define GET_MAXELEM(x)
  96.     #define DEFINE_VARS(x,y)
  97.     #define CHECK_ELEMS(x,y,z)
  98.  
  99. #endif
  100.  
  101. static int cget( PTR_SCNF_SPECS specs )
  102. {
  103.     return( (*((specs)->cget_rtn))( specs ) );
  104. }
  105.  
  106.  
  107. static void uncget( int c, PTR_SCNF_SPECS specs )
  108. {
  109.     ((*((specs)->uncget_rtn))( c, specs ));
  110. }
  111.  
  112.  
  113. /*
  114.  * get_opt -- get option string for current conversion directive
  115.  *            and fills in the SCNF_SPECS structure.
  116.  *            returns advanced format string pointer.
  117.  */
  118. static const CHAR_TYPE *get_opt( const CHAR_TYPE *opt_str, PTR_SCNF_SPECS specs )
  119. {
  120.     int     c, width;
  121.  
  122.     specs->assign           = TRUE;
  123.     specs->far_ptr          = 0;
  124.     specs->near_ptr         = 0;
  125.     specs->char_var         = 0;
  126.     specs->short_var        = 0;
  127.     specs->long_var         = 0;
  128.     specs->long_long_var    = 0;
  129.     specs->long_double_var  = 0;
  130.     specs->p_format         = 0;                    /* 21-nov-89 */
  131.     specs->width            = -1;
  132.     if( *opt_str == '*' ) {
  133.         specs->assign = FALSE;
  134.         ++opt_str;
  135.     }
  136.     c = *opt_str;
  137.     if( __F_NAME(isdigit,iswdigit)( c ) ) {
  138.         width = 0;
  139.         do {
  140.             width *= 10;
  141.             width += ( c - '0' );
  142.             c = *++opt_str;
  143.         } while( __F_NAME(isdigit,iswdigit)( c ) );
  144.         specs->width = width;
  145.     }
  146.     switch( *opt_str ) {
  147.     case 'N':
  148.         specs->near_ptr = 1;
  149.         ++opt_str;
  150.         break;
  151. #if defined( __FAR_SUPPORT__ )
  152.     case 'F':   /* conflicts with ISO-defined 'F' conversion */
  153.         /* fall through */
  154. #endif
  155.     case 'W':
  156.         specs->far_ptr = 1;
  157.         ++opt_str;
  158.         break;
  159.     }
  160.     switch( *opt_str ) {
  161.     case 'h':
  162.         if( opt_str[1] == 'h' ) {
  163.             specs->char_var = 1;
  164.             opt_str += 2;
  165.             break;
  166.         }
  167.         specs->short_var = 1;
  168.         ++opt_str;
  169.         break;
  170.     case 'l':
  171. #if defined( __LONG_LONG_SUPPORT__ )
  172.         if( opt_str[1] == 'l' ) {
  173.             specs->long_long_var = 1;
  174.             opt_str += 2;
  175.             break;
  176.         }
  177. #endif
  178.         /* fall through */
  179.     ZSPEC_CASE_LONG
  180.     TSPEC_CASE_LONG
  181.     case 'w':
  182.         specs->long_var = 1;
  183.         ++opt_str;
  184.         break;
  185. #if defined( __LONG_LONG_SUPPORT__ )
  186.     JSPEC_CASE_LLONG
  187.         /* fall through */
  188. #endif
  189.     case 'L':
  190.         specs->long_double_var = 1;
  191.         specs->long_long_var = 1;
  192.         ++opt_str;
  193.         break;
  194. #if defined( __LONG_LONG_SUPPORT__ )
  195.     case 'I':
  196.         if( opt_str[1] == '6' && opt_str[2] == '4' ) {
  197.             specs->long_long_var = 1;
  198.             opt_str += 3;
  199.         }
  200.         break;
  201. #endif
  202. #if defined( TSPEC_IS_INT ) || defined( ZSPEC_IS_INT )
  203.     TSPEC_CASE_INT      /* If either 't' or 'z' spec corresponds to 'int',  */
  204.     ZSPEC_CASE_INT      /* we need to parse and ignore the spec.            */
  205.         ++opt_str;
  206.         break;
  207. #endif
  208.     }
  209.     return( opt_str );
  210. }
  211.  
  212.  
  213. /*
  214.  * scan_white -- scan white space from input stream
  215.  */
  216. static int scan_white( PTR_SCNF_SPECS specs )
  217. {
  218.     int     c, len;
  219.  
  220.     len = 0;
  221.     for( ;; ) {
  222.         c = cget( specs );
  223.         if( !__F_NAME(isspace,iswspace)( c ) )
  224.             break;
  225.         ++len;
  226.     }
  227.     if( !specs->eoinp )
  228.         uncget( c, specs );
  229.     return( len );
  230. }
  231.  
  232. /*
  233.  * scan_char -- handles %c and %C
  234.  */
  235. static int scan_char( PTR_SCNF_SPECS specs, my_va_list *arg )
  236. {
  237.     int             len;
  238.     int             width;
  239.     FAR_STRING      str;
  240.     int             c;
  241.     DEFINE_VARS( maxelem, nelem );
  242.  
  243.     if( specs->assign ) {
  244. #if defined( __FAR_SUPPORT__ )
  245.         if( specs->far_ptr ) {
  246.             str = va_arg( arg->v, CHAR_TYPE _WCFAR * );
  247.         } else if( specs->near_ptr ) {
  248.             str = va_arg( arg->v, CHAR_TYPE _WCNEAR * );
  249.         } else {
  250.             str = va_arg( arg->v, CHAR_TYPE * );
  251.         }
  252. #else
  253.         str = va_arg( arg->v, CHAR_TYPE * );
  254. #endif
  255.         GET_MAXELEM( maxelem );
  256.     }
  257.     len = 0;
  258.     if( (width = specs->width) == -1 )
  259.         width = 1;
  260.     while( width > 0 ) {
  261.         c = cget( specs );
  262.         if( specs->eoinp )
  263.             break;
  264.         ++len;
  265.         --width;
  266.         if( specs->assign ) {
  267.             CHECK_ELEMS( maxelem, nelem, -1 );
  268. #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  269.             if( specs->short_var ) {
  270.                 char        mbBuf[MB_CUR_MAX];
  271.  
  272.                 if( wctomb( mbBuf, c ) != -1 ) {
  273.                     *(FAR_ASCII_STRING)str = mbBuf[0];
  274.                     str = (FAR_STRING) ( (FAR_ASCII_STRING)str + 1 );
  275.                     if( _ismbblead( mbBuf[0] ) )  {
  276.                         CHECK_ELEMS( maxelem, nelem, -1 );
  277.                         *(FAR_ASCII_STRING)str = mbBuf[1];
  278.                         str = (FAR_STRING) ( (FAR_ASCII_STRING)str + 1 );
  279.                     }
  280.                 } else {
  281.                     return( 0 );
  282.                 }
  283.             } else {
  284.                 *str++ = c;
  285.             }
  286. #elif defined( USE_MBCS_TRANSLATION )
  287.             if( specs->long_var ) {
  288.                 wchar_t     wc;
  289.                 char        mbBuf[MB_CUR_MAX];
  290.  
  291.                 mbBuf[0] = c;
  292.                 if( _ismbblead( mbBuf[0] ) )
  293.                     mbBuf[1] = cget( specs );
  294.                 if( mbtowc( &wc, mbBuf, MB_CUR_MAX ) != -1 ) {
  295.                     *(FAR_UNI_STRING)str = wc;
  296.                     str = (FAR_STRING) ( (FAR_UNI_STRING)str + 1 );
  297.                 } else {
  298.                     return( 0 );
  299.                 }
  300.             } else {
  301.                 *str++ = c;
  302.             }
  303. #else
  304.             *str++ = c;
  305. #endif
  306.         }
  307.     }
  308.     return( len );
  309. }
  310.  
  311.  
  312. /*
  313.  * cgetw -- cget which keeps track of field width.
  314.  *          returns STOP_CHR on end of field or end of file.
  315.  */
  316. static long cgetw( PTR_SCNF_SPECS specs )
  317. {
  318.     int     c;
  319.  
  320.     if( specs->width-- == 0 )
  321.         return( STOP_CHR );
  322.     c = cget( specs );
  323.     return( !( specs->eoinp ) ? c : STOP_CHR );
  324. }
  325.  
  326.  
  327. /*
  328.  * scan_string -- handles %s and %S
  329.  */
  330. static int scan_string( PTR_SCNF_SPECS specs, my_va_list *arg )
  331. {
  332.     int                     c;
  333.     int                     len;
  334.     FAR_ASCII_STRING        str;
  335.     char                    chsize;
  336.     DEFINE_VARS( maxelem, nelem );
  337.  
  338.     if( specs->long_var ) {         /* %ls or %ws */
  339.         chsize = sizeof( wchar_t );
  340.     } else if( specs->short_var ) { /* %hs */
  341.         chsize = 1;
  342.     } else {                        /* %s */
  343.         chsize = CHARSIZE;
  344.     }
  345.     if( specs->assign ) {
  346. #if defined( __FAR_SUPPORT__ )
  347.         if( specs->far_ptr ) {
  348.             str = va_arg( arg->v, char _WCFAR * );
  349.         } else if( specs->near_ptr ) {
  350.             str = va_arg( arg->v, char _WCNEAR * );
  351.         } else {
  352.             str = va_arg( arg->v, char * );
  353.         }
  354. #else
  355.         str = va_arg( arg->v, char * );
  356. #endif
  357.         GET_MAXELEM( maxelem );
  358.     }
  359.     len = 0;
  360.     for( ;; ) {
  361.         c = cget( specs );
  362.         if( !__F_NAME(isspace,iswspace)( c ) )
  363.             break;
  364.         ++len;
  365.     }
  366.     if( specs->eoinp ) {
  367.         len = 0;            /* since this is eof, no input done */
  368.         goto done;
  369.     }
  370.     if( specs->width-- == 0 )
  371.         goto ugdone;
  372.     do {
  373.         ++len;
  374.         if( specs->assign ) {
  375.             CHECK_ELEMS( maxelem, nelem, -1 );
  376.             if( chsize == 1 ) {
  377. #if defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  378.                 char        mbBuf[MB_CUR_MAX];
  379.  
  380.                 if( wctomb( mbBuf, c ) != -1 ) {
  381.                     *(FAR_ASCII_STRING)str = mbBuf[0];
  382.                     if( _ismbblead( mbBuf[0] ) ) {
  383.                         CHECK_ELEMS( maxelem, nelem, -1 );
  384.                         str++;
  385.                         *(FAR_ASCII_STRING)str = mbBuf[1];
  386.                     }
  387.                 } else {
  388.                     return( 0 );
  389.                 }
  390. #else
  391.                 *str = c;
  392. #endif
  393.             } else {
  394. #if !defined( __WIDECHAR__ ) && defined( USE_MBCS_TRANSLATION )
  395.                 wchar_t     wc;
  396.                 char        mbBuf[MB_CUR_MAX];
  397.  
  398.                 mbBuf[0] = c;
  399.                 if( _ismbblead( mbBuf[0] ) )
  400.                     mbBuf[1] = cget( specs );
  401.                 if( mbtowc( &wc, mbBuf, MB_CUR_MAX ) != -1 ) {
  402.                     *(FAR_UNI_STRING)str = wc;
  403.                 } else {
  404.                     return( 0 );
  405.                 }
  406. #else
  407.                 *(FAR_UNI_STRING)str = c;
  408. #endif
  409.             }
  410.             str += chsize;
  411.         }
  412.         if( (c = cgetw( specs )) == STOP_CHR ) {
  413.             goto done;
  414.         }
  415.     } while( !__F_NAME(isspace,iswspace)( c ) );
  416. ugdone:
  417.     uncget( c, specs );
  418. done:
  419.     if( specs->assign && len > 0 ) {
  420.         CHECK_ELEMS( maxelem, nelem, -1 );
  421.         if( chsize == 1 ) {
  422.             *str = '\0';
  423.         } else {
  424.             *(FAR_UNI_STRING)str = 0;
  425.         }
  426.     }
  427.     return( len );
  428. }
  429.  
  430.  
  431. /*
  432.  * report_scan -- handles %n
  433.  */
  434. static void report_scan( PTR_SCNF_SPECS specs, my_va_list *arg, int match )
  435. {
  436.     FAR_INT         iptr;
  437.  
  438.     if( specs->assign ) {
  439. #if defined( __FAR_SUPPORT__ )
  440.         if( specs->far_ptr ) {
  441.             iptr = va_arg( arg->v, int _WCFAR * );
  442.         } else if( specs->near_ptr ) {
  443.             iptr = va_arg( arg->v, int _WCNEAR * );
  444.         } else {
  445.             iptr = va_arg( arg->v, int * );
  446.         }
  447. #else
  448.         iptr = va_arg( arg->v, int * );
  449. #endif
  450.         if( specs->char_var ) {
  451.             *((FAR_CHAR)iptr) = match;
  452.         } else if( specs->short_var ) {
  453.             *((FAR_SHORT)iptr) = match;
  454.         } else if( specs->long_var ) {
  455.             *((FAR_LONG)iptr) = match;
  456. #if defined( __LONG_LONG_SUPPORT__ )
  457.         } else if( specs->long_long_var ) {
  458.             *((FAR_INT64)iptr) = match;
  459. #endif
  460.         } else {
  461.             *iptr = match;
  462.         }
  463.     }
  464. }
  465.  
  466. #if !defined( __WIDECHAR__ )
  467. #define SCANSET_LENGTH  (256 / 8)
  468.  
  469. static const char lst_mask[8] = {
  470.     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
  471. };
  472.  
  473. /*
  474.  * makelist -- create scanset for %[ directive.
  475.  *             scanset is stored as 256 bit flags in a 32 byte array.
  476.  */
  477. static const char *makelist( const char *format, char *scanset )
  478. {
  479.     int     lst_chr;
  480.  
  481.     memset( scanset, 0, SCANSET_LENGTH );
  482.     if( (lst_chr = *format++) == '\0' )
  483.         return( format );
  484.     do {
  485.         scanset[lst_chr >> 3] |= lst_mask[lst_chr & 0x07];
  486.         if( (lst_chr = *format) == '\0' )
  487.             break;
  488.         ++format;
  489.     } while( lst_chr != ']' );
  490.     return( format );
  491. }
  492. #endif
  493.  
  494.  
  495. /*
  496.  * scan_arb -- handles %[
  497.  */
  498. static int scan_arb( PTR_SCNF_SPECS specs, my_va_list *arg, const CHAR_TYPE **format )
  499. {
  500.     unsigned            width;
  501.     FAR_STRING          str;
  502.     int                 len, c, not_flag;
  503. #if defined( __WIDECHAR__ )
  504.     const CHAR_TYPE     *list;
  505.     CHAR_TYPE           ch;
  506.     char                in_list;
  507. #else
  508.     char                scanset[SCANSET_LENGTH];
  509. #endif
  510.     DEFINE_VARS( maxelem, nelem );
  511.  
  512.     if( not_flag = (**format == '^') ) {
  513.         ++(*format);
  514.     }
  515. #if !defined( __WIDECHAR__ )
  516.     *format = makelist( *format, scanset );
  517. #endif
  518.     if( specs->assign ) {
  519. #if defined( __FAR_SUPPORT__ )
  520.         if( specs->far_ptr ) {
  521.             str = va_arg( arg->v, CHAR_TYPE _WCFAR * );
  522.         } else if( specs->near_ptr ) {
  523.             str = va_arg( arg->v, CHAR_TYPE _WCNEAR * );
  524.         } else {
  525.             str = va_arg( arg->v, CHAR_TYPE * );
  526.         }
  527. #else
  528.         str = va_arg( arg->v, CHAR_TYPE * );
  529. #endif
  530.         GET_MAXELEM( maxelem );
  531.     }
  532.     len = 0;
  533.     width = specs->width;
  534.     while( width > 0 ) {
  535.         c = cget( specs );
  536.         if( specs->eoinp )
  537.             break;
  538. #if defined( __WIDECHAR__ )
  539.         list = *format;
  540.         ch = *list;
  541.         in_list = TRUE;
  542.         while( c != ch ) {
  543.             list++;
  544.             ch = *list;
  545.             if( ch == ']' ) {
  546.                 in_list = FALSE;
  547.                 break;
  548.             }
  549.         }
  550.         if( in_list == not_flag ) {
  551.             uncget( c, specs );
  552.             break;
  553.         }
  554. #else
  555.         if( ((scanset[c >> 3] & lst_mask[c & 0x07]) == 0) != not_flag ) {
  556.             uncget( c, specs );
  557.             break;
  558.         }
  559. #endif
  560.         ++len;
  561.         --width;
  562.         if( specs->assign ) {
  563.             CHECK_ELEMS( maxelem, nelem, -1 );
  564.             *str++ = c;
  565.         }
  566.     }
  567.     if( specs->assign && len > 0 ) {
  568.         CHECK_ELEMS( maxelem, nelem, -1 );
  569.         *str = '\0';
  570.     }
  571. #if defined( __WIDECHAR__ )
  572.     while( *(*format)++ != ']' )  /* skip past format specifier */
  573.         ;
  574. #endif
  575.     return( len );
  576. }
  577.  
  578.  
  579. /*
  580.  * scan_float -- handles floating point numerical conversion
  581.  *               *** should implement buffer overflow protection ***
  582.  */
  583. static int scan_float( PTR_SCNF_SPECS specs, my_va_list *arg )
  584. {
  585.     double      value;
  586.     char        *num_str, buf[80];
  587.     int         len;
  588.     int         pref_len;
  589.     long        c;
  590.     int         digit_found;
  591.     FAR_FLOAT   fptr;
  592.     char        *p;
  593.     T32         at;
  594.     T32         ft;
  595.  
  596.     num_str = buf;
  597.     pref_len = len = 0;
  598.     for( ;; ) {
  599.         c = cget( specs );
  600.         if( !__F_NAME(isspace,iswspace)( c ) )
  601.             break;
  602.         ++pref_len;
  603.     }
  604.     if( specs->eoinp )
  605.         goto done;
  606.     if( specs->width-- == 0 )
  607.         goto ugdone;
  608.     if( c == '+' || c == '-' ) {
  609.         *num_str++ = c;
  610.         ++pref_len;
  611.         if( (c = cgetw( specs )) == STOP_CHR ) {
  612.             goto done;
  613.         }
  614.     }
  615.     if( !__F_NAME(isdigit,iswdigit)( c ) && c != '.' )
  616.         goto ugdone;
  617.     at.uWhole = 0;
  618.     digit_found = FALSE;
  619.     if( __F_NAME(isdigit,iswdigit)( c ) ) {
  620.         digit_found = TRUE;
  621.         do {
  622.             *num_str++ = c;
  623.             if( specs->short_var )
  624.                 at.wd.hi = at.wd.hi * 10 + c - '0';
  625.             ++len;
  626.             if( (c = cgetw( specs )) == STOP_CHR ) {
  627.                 goto done;
  628.             }
  629.         } while( __F_NAME(isdigit,iswdigit)( c ) );
  630.     }
  631.     if( c == '.' ) {
  632.         *num_str++ = c;
  633.         ++len;              /* account for the '.' */
  634.         if( (c = cgetw( specs )) == STOP_CHR )
  635.             goto done;
  636.         if( !digit_found && !__F_NAME(isdigit,iswdigit)(c) )
  637.             goto ugdone;
  638.         while( __F_NAME(isdigit,iswdigit)( c ) ) {
  639.             *num_str++ = c;
  640.             ++len;
  641.             if( (c = cgetw( specs )) == STOP_CHR ) {
  642.                 break;
  643.             }
  644.         }
  645.         if( specs->short_var ) {    /* %hf fixed-point format 05-feb-92 */
  646.             ft.uWhole = 0;
  647.             p = num_str;
  648.             for( ;; ) {
  649.                 --p;
  650.                 if( *p == '.' )
  651.                     break;
  652.                 ft.bite.b3 = *p - '0';
  653.                 ft.uWhole = ft.uWhole / 10;
  654.             }
  655.             at.wd.lo = ft.wd.lo;
  656.         }
  657.         if( c == STOP_CHR ) {
  658.             goto done;
  659.         }
  660.     }
  661.     if( specs->short_var == 0  &&  (c == 'e' || c == 'E') ) {
  662.         *num_str++ = c;
  663.         ++len;
  664.         if( (c = cgetw( specs )) == STOP_CHR )
  665.             goto done;
  666.         if( c == '+' || c == '-' ) {
  667.             *num_str++ = c;
  668.             ++len;
  669.             if( (c = cgetw( specs )) == STOP_CHR ) {
  670.                 goto done;
  671.             }
  672.         }
  673.         if( !__F_NAME(isdigit,iswdigit)( c ) ) {
  674.             len = 0;                /* fast way to flag error */
  675.         } else {
  676.             do {
  677.                 *num_str++ = c;
  678.                 ++len;
  679.                 if( (c = cgetw( specs )) == STOP_CHR ) {
  680.                     goto done;
  681.                 }
  682.             } while( __F_NAME(isdigit,iswdigit)( c ) );
  683.         }
  684.     }
  685. ugdone:
  686.     uncget( (int)c, specs );
  687. done:
  688.     if( len > 0 ) {
  689.         len += pref_len;
  690.         if( specs->assign ) {
  691.             *num_str = NULLCHAR;
  692.             if( specs->short_var ) {
  693.                 if( buf[0] == '-' ) {
  694.                     at.sWhole = - at.sWhole;
  695.                 }
  696.             } else {
  697.                 EFG_SCANF( buf, (void *)&value );      /* 27-mar-90 */
  698.             }
  699. #if defined( __FAR_SUPPORT__ )
  700.             if( specs->far_ptr ) {
  701.                 fptr = va_arg( arg->v, float _WCFAR * );
  702.             } else if( specs->near_ptr ) {
  703.                 fptr = va_arg( arg->v, float _WCNEAR * );
  704.             } else {
  705.                 fptr = va_arg( arg->v, float * );
  706.             }
  707. #else
  708.             fptr = va_arg( arg->v, float * );
  709. #endif
  710.             if( specs->short_var ) {                        /* 05-feb-92 */
  711.                 *((FAR_LONG) fptr) = at.uWhole;
  712.             } else if( specs->long_var || specs->long_double_var ) {
  713.                 *((FAR_DOUBLE) fptr) = value;
  714.             } else {
  715.                 *fptr = value;
  716.             }
  717.         }
  718.     }
  719.     return( len );
  720. }
  721.  
  722.  
  723. static int radix_value( int c )
  724. {
  725.     if( c >= '0' && c <= '9' )
  726.         return( c - '0' );
  727.     c = __F_NAME(tolower,towlower)( c );
  728.     if( c >= 'a' && c <= 'f' )
  729.         return( c - 'a' + 10 );
  730.     return( 16 );
  731. }
  732.  
  733.  
  734. /*
  735.  * scan_int -- handles integer numeric conversion
  736.  */
  737. static int scan_int( PTR_SCNF_SPECS specs, my_va_list *arg, int base, int sign_flag )
  738. {
  739.     long                value;
  740.     int                 len;
  741.     int                 pref_len;
  742.     int                 c;
  743.     int                 sign;
  744.     int                 digit;
  745.     FAR_INT             iptr;
  746. #if defined( __LONG_LONG_SUPPORT__ )
  747.     unsigned long long  long_value;
  748.     FAR_INT64           llptr;
  749.  
  750.     long_value = 0;
  751. #endif
  752.  
  753.     value = 0;
  754.     pref_len = len = 0;
  755.     for( ;; ) {
  756.         c = cget( specs );
  757.         if( !__F_NAME(isspace,iswspace)( c ) )
  758.             break;
  759.         ++pref_len;
  760.     }
  761.     if( specs->eoinp )
  762.         goto done;
  763.     if( specs->width-- == 0 )
  764.         goto ugdone;
  765.     sign = '+';
  766.     if( sign_flag && (c == '+' || c == '-') ) {
  767.         sign = c;
  768.         ++pref_len;
  769.         if( (c = cgetw( specs )) == STOP_CHR ) {
  770.             goto done;
  771.         }
  772.     }
  773.     if( base == 0 ) {
  774.         if( c == '0' ) {
  775.             len = 1;
  776.             if( (c = cgetw( specs )) == STOP_CHR )
  777.                 goto done;
  778.             if( c == 'x' || c == 'X' ) {
  779.                 len = 0;
  780.                 ++pref_len;         /* for the '0' */
  781.                 ++pref_len;         /* for the 'x' */
  782.                 if( (c = cgetw( specs )) == STOP_CHR )
  783.                     goto done;
  784.                 base = 16;
  785.             } else {
  786.                 base = 8;
  787.             }
  788.         } else {
  789.             base = 10;
  790.         }
  791.     } else if( base == 16 ) {
  792.         if( c == '0' ) {
  793.             len = 1;
  794.             if( (c = cgetw( specs )) == STOP_CHR )
  795.                 goto done;
  796.             if( c == 'x'  ||  c == 'X' ) {
  797.                 len = 0;
  798.                 ++pref_len;         /* for the '0' */
  799.                 ++pref_len;         /* for the 'x' */
  800.                 if( (c = cgetw( specs )) == STOP_CHR ) {
  801.                     goto done;
  802.                 }
  803.             }
  804.         }
  805.     }
  806. #if defined( __LONG_LONG_SUPPORT__ )
  807.     if( specs->long_long_var ) {
  808.         for( ;; ) {
  809.             digit = radix_value( c );
  810.             if( digit >= base )
  811.                 break;
  812.             long_value = long_value * base + digit;
  813.             ++len;
  814.             if( (c = cgetw( specs )) == STOP_CHR ) {
  815.                 goto done;
  816.             }
  817.         }
  818.         if( c == ':'  &&  specs->p_format ) {
  819.             for( ;; ) {
  820.                 ++len;
  821.                 if( (c = cgetw( specs )) == STOP_CHR )
  822.                     goto done;
  823.                 digit = radix_value( c );
  824.                 if( digit >= base )
  825.                     break;
  826.                 long_value = long_value * base + digit;
  827.             }
  828.         }
  829.     } else
  830. #endif
  831.     {
  832.         for( ;; ) {
  833.             digit = radix_value( c );
  834.             if( digit >= base )
  835.                 break;
  836.             value = value * base + digit;
  837.             ++len;
  838.             if( (c = cgetw( specs )) == STOP_CHR ) {
  839.                 goto done;
  840.             }
  841.         }
  842.         if( c == ':'  &&  specs->p_format ) {
  843.             for( ;; ) {
  844.                 ++len;
  845.                 if( (c = cgetw( specs )) == STOP_CHR )
  846.                     goto done;
  847.                 digit = radix_value( c );
  848.                 if( digit >= base )
  849.                     break;
  850.                 value = value * base + digit;
  851.             }
  852.         }
  853.     }
  854. ugdone:
  855.     uncget( c, specs );
  856. done:
  857. #if defined( __LONG_LONG_SUPPORT__ )
  858.     if( specs->long_long_var ) {
  859.         if( sign == '-' ) {
  860.             long_value =- long_value;
  861.         }
  862.         if( len > 0 ) {
  863.             len += pref_len;
  864.             if( specs->assign ) {
  865. #if defined( __FAR_SUPPORT__ )
  866.                 if( specs->far_ptr ) {
  867.                     llptr = va_arg( arg->v, unsigned long long _WCFAR * );
  868.                 } else if( specs->near_ptr ) {
  869.                     llptr = va_arg( arg->v, unsigned long long _WCNEAR * );
  870.                 } else {
  871.                     llptr = va_arg( arg->v, unsigned long long * );
  872.                 }
  873. #else
  874.                 llptr = va_arg( arg->v, unsigned long long * );
  875. #endif
  876.                 *llptr = long_value;
  877.             }
  878.         }
  879.     } else
  880. #endif
  881.     {
  882.         if( sign == '-' ) {
  883.             value = -value;
  884.         }
  885.         if( len > 0 ) {
  886.             len += pref_len;
  887.             if( specs->assign ) {
  888. #if defined( __FAR_SUPPORT__ )
  889.                 if( specs->far_ptr ) {
  890.                     iptr = va_arg( arg->v, int _WCFAR * );
  891.                 } else if( specs->near_ptr ) {
  892.                     iptr = va_arg( arg->v, int _WCNEAR * );
  893.                 } else {
  894.                     iptr = va_arg( arg->v, int * );
  895.                 }
  896. #else
  897.                 iptr = va_arg( arg->v, int * );
  898. #endif
  899.                 if( specs->char_var ) {
  900.                     *((FAR_CHAR)iptr) = value;
  901.                 } else if( specs->short_var ) {
  902.                     *((FAR_SHORT)iptr) = value;
  903.                 } else if( specs->long_var ) {
  904.                     *((FAR_LONG)iptr) = value;
  905.                 } else {
  906.                     *iptr = value;
  907.                 }
  908.             }
  909.         }
  910.     }
  911.     return( len );
  912. }
  913.  
  914.  
  915. #ifdef SAFE_SCANF
  916.  
  917. /*
  918.  * null_arg -- check for a null pointer passed in arguments
  919.  */
  920. static int null_arg( PTR_SCNF_SPECS specs, my_va_list *arg )
  921. {
  922.     FAR_STRING      str = NULL;
  923.     va_list         args_copy;
  924.  
  925.     va_copy( args_copy, arg->v );
  926. #if defined( __FAR_SUPPORT__ )
  927.     if( specs->far_ptr ) {
  928.         str = va_arg( args_copy, CHAR_TYPE _WCFAR * );
  929.     } else if( specs->near_ptr ) {
  930.         CHAR_TYPE _WCNEAR   *ptr;
  931.  
  932.         ptr = va_arg( args_copy, CHAR_TYPE _WCNEAR * );
  933.         /* The following should work:
  934.          *
  935.          * str = (ptr == NULL) ? (void _WCFAR *)NULL : ptr;
  936.          *
  937.          * but doesn't due to a bug in C compiler introduced in
  938.          * 11.0 and fixe in OW 1.4. Ternary operator may be used
  939.          * when building with OW 1.5. See also similar code in prtf.c.
  940.          */
  941.         if( ptr == NULL ) {
  942.             str = NULL;
  943.         } else {
  944.             str = ptr;
  945.         }
  946.     } else {
  947.         CHAR_TYPE   *ptr;
  948.  
  949.         ptr = va_arg( args_copy, CHAR_TYPE * );
  950.         if( ptr == NULL ) {
  951.             str = NULL;
  952.         } else {
  953.             str = ptr;
  954.         }
  955.     }
  956. #else
  957.     str = va_arg( args_copy, CHAR_TYPE * );
  958. #endif
  959.     va_end( args_copy );
  960.     return( str == NULL ? 1 : 0 );
  961. }
  962.  
  963. #endif
  964.  
  965.  
  966. #ifdef SAFE_SCANF
  967. int __F_NAME(__scnf_s,__wscnf_s)( PTR_SCNF_SPECS specs, const CHAR_TYPE *format, const char **msg, va_list args )
  968. #else
  969. int __F_NAME(__scnf,__wscnf)( PTR_SCNF_SPECS specs, const CHAR_TYPE *format, va_list args )
  970. #endif
  971. {
  972.     int         char_match;
  973.     int         items_converted;
  974.     int         items_assigned;
  975.     int         match_len;
  976.     int         c;
  977.     int         fmt_chr;
  978.     my_va_list  margs;
  979.  
  980.     margs = MY_VA_LIST( args );
  981.  
  982.     char_match = items_assigned = items_converted = 0;
  983.     specs->eoinp = 0;
  984.  
  985.     while( (fmt_chr = *format++) != NULLCHAR ) {
  986.         if( __F_NAME(isspace,iswspace)( fmt_chr ) ) {
  987.             char_match += scan_white( specs );
  988.         } else if( fmt_chr != '%' ) {
  989.             if( (c = cget( specs )) != fmt_chr ) {
  990.                 if( !specs->eoinp )
  991.                     uncget( c, specs );
  992.                 break;
  993.             }
  994.             ++char_match;                           /* 27-oct-88 */
  995.         } else {            /* fmt_chr == '%' */
  996.             format = get_opt( format, specs );
  997.             if( (fmt_chr = *format) != NULLCHAR )
  998.                 ++format;
  999. #ifdef SAFE_SCANF
  1000.             if( fmt_chr != '%' ) {
  1001.                 /* The '%' specifier is the only one not expecting pointer arg */
  1002.                 if( specs->assign && null_arg( specs, &margs ) ) {
  1003.                     *msg = "%ptr -> NULL";
  1004.                     return( __F_NAME(EOF,WEOF) );
  1005.                 }
  1006.             }
  1007. #endif
  1008.             switch( fmt_chr ) {
  1009.             case 'd':
  1010.                 match_len = scan_int( specs, &margs, 10, TRUE );
  1011.                 goto check_match;
  1012.             case 'i':
  1013.                 match_len = scan_int( specs, &margs, 0, TRUE );
  1014.                 goto check_match;
  1015.             case 'o':
  1016.                 match_len = scan_int( specs, &margs, 8, TRUE );
  1017.                 goto check_match;
  1018.             case 'u':
  1019.                 match_len = scan_int( specs, &margs, 10, TRUE );
  1020.                 goto check_match;
  1021.             case 'p':
  1022. #if defined( __BIG_DATA__ )
  1023.                 specs->long_var = 1;    /* indicate far pointer */
  1024.                 specs->p_format = 1;    /* ... */
  1025. #endif
  1026.                 // fall through
  1027.             case 'x':
  1028.             case 'X':
  1029.                 match_len = scan_int( specs, &margs, 16, TRUE );
  1030.                 goto check_match;
  1031.             case 'e':
  1032.             case 'E':
  1033.             case 'f':
  1034.             case 'F':
  1035.             case 'g':
  1036.             case 'G':
  1037.                 match_len = scan_float( specs, &margs );
  1038.                 goto check_match;
  1039. #if !defined(__WIDECHAR__) && !defined(__NETWARE__)
  1040.             case 'S':
  1041.                 specs->long_var = 1;
  1042.                 /* fall through to %s handler */
  1043. #endif
  1044.             case 's':
  1045.                 match_len = scan_string( specs, &margs );
  1046.                 goto check_match;
  1047.             case '[':
  1048.                 match_len = scan_arb( specs, &margs, &format );
  1049.                 goto check_match;
  1050. #if !defined(__WIDECHAR__) && !defined(__NETWARE__)
  1051.             case 'C':
  1052.                 specs->long_var = 1;
  1053.                 /* fall through to %c handler */
  1054. #endif
  1055.             case 'c':
  1056.                 match_len = scan_char( specs, &margs );
  1057. check_match:
  1058.                 if( match_len > 0 ) {
  1059.                     char_match += match_len;
  1060.                     ++items_converted;
  1061.                     if( specs->assign ) {
  1062.                         ++items_assigned;
  1063.                     }
  1064.                 } else {
  1065. #ifdef SAFE_SCANF
  1066.                     if( match_len < 0 ) {
  1067.                         /* Matching failure caused by insufficient space in output
  1068.                          * is not input failure, hence we won't return EOF regardless
  1069.                          * of specs->eoinp state.
  1070.                          */
  1071.                         ++items_converted;
  1072.                     }
  1073. #endif
  1074.                     goto fail;
  1075.                 }
  1076.                 break;
  1077.             case 'n':
  1078.                 report_scan( specs, &margs, char_match );
  1079.                 break;
  1080.             case '%':
  1081.                 if( (c = cget( specs )) != '%' ) {
  1082.                     if( !specs->eoinp )
  1083.                         uncget( c, specs );
  1084.                     goto fail;
  1085.                 } else {
  1086.                     char_match += 1;
  1087.                 }
  1088.                 break;
  1089.             }
  1090.         }
  1091.         if( specs->eoinp ) {
  1092.             while( *format == '%' ) {
  1093.                 ++format;
  1094.                 format = get_opt( format, specs );
  1095.                 if( *format == 'n' ) {
  1096.                     ++format;
  1097. #ifdef SAFE_SCANF
  1098.                     if( specs->assign && null_arg( specs, &margs ) ) {
  1099.                         *msg = "%ptr -> NULL";
  1100.                         return( __F_NAME(EOF,WEOF) );
  1101.                     }
  1102. #endif
  1103.                     report_scan( specs, &margs, char_match );
  1104.                 } else {
  1105.                     break;
  1106.                 }
  1107.             }
  1108.             break;
  1109.         }
  1110.     }
  1111.  
  1112. fail:
  1113.     if( items_converted == 0 && specs->eoinp )
  1114.         return( __F_NAME(EOF,WEOF) );
  1115.     return( items_assigned );
  1116. }
  1117.