home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / extra / ustdio / uscanf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  37.5 KB  |  1,522 lines

  1. /*
  2. *******************************************************************************
  3. *                                                                             *
  4. * COPYRIGHT:                                                                  *
  5. *   (C) Copyright International Business Machines Corporation, 1998           *
  6. *   Licensed Material - Program-Property of IBM - All Rights Reserved.        *
  7. *   US Government Users Restricted Rights - Use, duplication, or disclosure   *
  8. *   restricted by GSA ADP Schedule Contract with IBM Corp.                    *
  9. *                                                                             *
  10. *******************************************************************************
  11. *
  12. * File uscanf.c
  13. *
  14. * Modification History:
  15. *
  16. *   Date        Name        Description
  17. *   12/02/98    stephen        Creation.
  18. *   03/13/99    stephen     Modified for new C API.
  19. *******************************************************************************
  20. */
  21.  
  22. #include "uchar.h"
  23.  
  24. #include "uscanf.h"
  25. #include "uscanf_p.h"
  26. #include "uscanset.h"
  27. #include "ustdio.h"
  28. #include "ufile.h"
  29. #include "ustring.h"
  30. #include "locbund.h"
  31. #include "umutex.h"
  32. #include "unum.h"
  33. #include "udat.h"
  34.  
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include <float.h>
  38. #include <limits.h>
  39. #include <wchar.h>
  40.  
  41.  
  42. u_scanf_handler g_u_scanf_handlers     [256];
  43. u_scanf_info       g_u_scanf_infos     [256];
  44. bool_t        g_u_scanf_inited    = FALSE;
  45.  
  46. int32_t 
  47. u_fscanf(    UFILE        *f,
  48.         const char    *patternSpecification,
  49.         ... )
  50. {
  51.   va_list ap;
  52.   int32_t converted;
  53.   
  54.   va_start(ap, patternSpecification);
  55.   converted = u_vfscanf(f, patternSpecification, ap);
  56.   va_end(ap);
  57.   
  58.   return converted;
  59. }
  60.  
  61. int32_t 
  62. u_fscanf_u(    UFILE        *f,
  63.         const UChar    *patternSpecification,
  64.         ... )
  65. {
  66.   va_list ap;
  67.   int32_t converted;
  68.   
  69.   va_start(ap, patternSpecification);
  70.   converted = u_vfscanf_u(f, patternSpecification, ap);
  71.   va_end(ap);
  72.   
  73.   return converted;
  74. }
  75.  
  76. int32_t 
  77. u_vfscanf(    UFILE        *f,
  78.         const char    *patternSpecification,
  79.         va_list        ap)
  80. {
  81.   int32_t converted;
  82.   UChar *pattern;
  83.   
  84.   /* convert from the default codepage to Unicode */
  85.   pattern = ufmt_defaultCPToUnicode(patternSpecification, 
  86.                     strlen(patternSpecification));
  87.   if(pattern == 0) {
  88.     return 0;
  89.   }
  90.   
  91.   /* do the work */
  92.   converted = u_vfscanf_u(f, pattern, ap);
  93.  
  94.   /* clean up */
  95.   free(pattern);
  96.   
  97.   return converted;
  98. }
  99.  
  100. int32_t
  101. u_scanf_register_handler (UChar            spec, 
  102.               u_scanf_info         info,
  103.               u_scanf_handler     handler)
  104. {
  105.   /* lock the cache */
  106.   umtx_lock(0);
  107.  
  108.   /* add to our list of function pointers */
  109.   g_u_scanf_infos[ (unsigned char) spec ]     = info;
  110.   g_u_scanf_handlers[ (unsigned char) spec ]     = handler;
  111.  
  112.   /* unlock the cache */
  113.   umtx_unlock(0);
  114.   return 0;
  115. }
  116.  
  117. int32_t
  118. u_scanf_skip_leading_ws(UFILE     *stream,
  119.             UChar     pad)
  120. {
  121.   UChar     c;
  122.   int32_t    count = 0;
  123.   
  124.   /* skip all leading ws in the stream */
  125.   while( ((c = u_fgetc(stream)) != 0xFFFF) && (c == pad || ufmt_isws(c)) )
  126.     ++count;
  127.   
  128.   /* put the final character back on the stream */  
  129.   if(c != 0xFFFF)
  130.     u_fungetc(c, stream);
  131.  
  132.   return count;
  133. }
  134.  
  135. int32_t 
  136. u_scanf_simple_percent_info(const u_scanf_spec_info    *info,
  137.                 int32_t             *argtypes,
  138.                 int32_t             n)
  139. {
  140.   /* we don't need any arguments */
  141.   return 0;
  142. }
  143.  
  144. int32_t 
  145. u_scanf_simple_percent_handler(UFILE            *stream,
  146.                    const u_scanf_spec_info     *info,
  147.                    ufmt_args             *args,
  148.                    const UChar        *fmt,
  149.                    int32_t            *consumed)
  150. {
  151.   /* make sure the next character in the stream is a percent */
  152.   if(u_fgetc(stream) != 0x0025)
  153.     return -1;
  154.   else
  155.     return 0;
  156. }
  157.  
  158. int32_t 
  159. u_scanf_string_info(const u_scanf_spec_info     *info,
  160.             int32_t             *argtypes,
  161.             int32_t             n)
  162. {
  163.   /* handle error */
  164.   if(n < 1)
  165.     return 0;
  166.  
  167.   /* we need 1 argument of type string */
  168.   argtypes[0] = ufmt_string;
  169.   return 1;
  170. }
  171.  
  172. int32_t
  173. u_scanf_string_handler(UFILE             *stream,
  174.                const u_scanf_spec_info     *info,
  175.                ufmt_args             *args,
  176.                const UChar        *fmt,
  177.                int32_t            *consumed)
  178. {
  179.   UChar     c;
  180.   int32_t     count;
  181.   const UChar     *source;
  182.   UConverter     *conv;
  183.   UErrorCode     status     = U_ZERO_ERROR;
  184.   char         *arg     = (char*)(args[0].ptrValue);
  185.   char         *alias     = arg;
  186.   char         *limit;
  187.  
  188.   /* skip all ws in the stream */
  189.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  190.   
  191.   /* get the string one character at a time, truncating to the width */
  192.   count = 0;
  193.  
  194.   /* open the default converter */
  195.   conv = ucnv_open(ucnv_getDefaultName(), &status);
  196.  
  197.   if(U_FAILURE(status))
  198.     return -1;
  199.  
  200.   /* since there is no real limit, just use a reasonable value */
  201.   limit = alias + 2048;
  202.  
  203.   while( ((c = u_fgetc(stream)) != 0xFFFF) && 
  204.      (c != info->fPadChar && ! ufmt_isws(c)) &&
  205.      (info->fWidth == -1 || count < info->fWidth) ) {
  206.     
  207.     /* put the character from the stream onto the target */
  208.     source = &c;
  209.  
  210.     /* convert the character to the default codepage */
  211.     ucnv_fromUnicode(conv, &alias, limit, &source, source + 1,
  212.              NULL, TRUE, &status);
  213.     
  214.     if(U_FAILURE(status))
  215.       return -1;
  216.     
  217.     /* increment the count */
  218.     ++count;
  219.   }
  220.  
  221.   /* put the final character we read back on the stream */  
  222.   if(c != 0xFFFF)
  223.     u_fungetc(c, stream);
  224.   
  225.   /* add the terminator */
  226.   *alias = 0x00;
  227.  
  228.   /* clean up */
  229.   ucnv_close(conv);
  230.  
  231.   /* we converted 1 arg */
  232.   return 1;
  233. }
  234.  
  235. int32_t 
  236. u_scanf_ustring_info(const u_scanf_spec_info     *info,
  237.              int32_t             *argtypes,
  238.              int32_t             n)
  239. {
  240.   /* handle error */
  241.   if(n < 1)
  242.     return 0;
  243.  
  244.   /* we need 1 argument of type ustring */
  245.   argtypes[0] = ufmt_ustring;
  246.   return 1;
  247. }
  248.  
  249. int32_t
  250. u_scanf_ustring_handler(UFILE             *stream,
  251.             const u_scanf_spec_info *info,
  252.             ufmt_args        *args,
  253.             const UChar        *fmt,
  254.             int32_t            *consumed)
  255. {
  256.   UChar     c;
  257.   int32_t     count;
  258.   UChar     *arg     = (UChar*)(args[0].ptrValue);
  259.   UChar     *alias     = arg;
  260.   
  261.   /* skip all ws in the stream */
  262.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  263.   
  264.   /* get the string one character at a time, truncating to the width */
  265.   count = 0;
  266.  
  267.   while( ((c = u_fgetc(stream)) != 0xFFFF) && 
  268.      (c != info->fPadChar && ! ufmt_isws(c)) &&
  269.      (info->fWidth == -1 || count < info->fWidth) ) {
  270.     
  271.     /* put the character from the stream onto the target */
  272.     *alias++ = c;
  273.     
  274.     /* increment the count */
  275.     ++count;
  276.   }
  277.  
  278.   /* put the final character we read back on the stream */  
  279.   if(c != 0xFFFF)
  280.     u_fungetc(c, stream);
  281.   
  282.   /* add the terminator */
  283.   *alias = 0x0000;
  284.  
  285.   /* we converted 1 arg */
  286.   return 1;
  287. }
  288.  
  289.  
  290. int32_t 
  291. u_scanf_count_info(const u_scanf_spec_info     *info,
  292.            int32_t             *argtypes,
  293.            int32_t             n)
  294. {
  295.   /* handle error */
  296.   if(n < 1)
  297.     return 0;
  298.  
  299.   /* we need 1 argument of type count */
  300.   argtypes[0] = ufmt_count;
  301.   return 1;
  302. }
  303.  
  304. int32_t
  305. u_scanf_count_handler(UFILE             *stream,
  306.               const u_scanf_spec_info     *info,
  307.               ufmt_args        *args,
  308.               const UChar        *fmt,
  309.               int32_t            *consumed)
  310. {
  311.   int *converted = (int*)(args[0].ptrValue);
  312.   
  313.   /* in the special case of count, the u_scanf_spec_info's width */
  314.   /* will contain the # of items converted thus far */
  315.   *converted = info->fWidth;
  316.  
  317.   /* we converted 0 args */
  318.   return 0;
  319. }
  320.  
  321. int32_t 
  322. u_scanf_integer_info(const u_scanf_spec_info     *info,
  323.              int32_t             *argtypes,
  324.              int32_t             n)
  325. {
  326.   /* handle error */
  327.   if(n < 1)
  328.     return 0;
  329.  
  330.   /* we need 1 argument of type int */
  331.   argtypes[0] = ufmt_int;
  332.   return 1;
  333. }
  334.  
  335. int32_t
  336. u_scanf_integer_handler(UFILE             *stream,
  337.             const u_scanf_spec_info *info,
  338.             ufmt_args        *args,
  339.             const UChar        *fmt,
  340.             int32_t            *consumed)
  341. {
  342.   int32_t        len;
  343.   long            *num         = (long*) (args[0].ptrValue);
  344.   UNumberFormat        *format;
  345.   int32_t        parsePos     = 0;
  346.   UErrorCode         status         = U_ZERO_ERROR;
  347.  
  348.  
  349.   /* skip all ws in the stream */
  350.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  351.  
  352.   /* fill the stream's internal buffer */
  353.   ufile_fill_uchar_buffer(stream);
  354.  
  355.   /* determine the size of the stream's buffer */
  356.   len = stream->fUCLimit - stream->fUCPos;
  357.  
  358.   /* truncate to the width, if specified */
  359.   if(info->fWidth != -1)
  360.     len = ufmt_min(len, info->fWidth);
  361.  
  362.   /* get the formatter */
  363.   format = u_locbund_getNumberFormat(stream->fBundle);
  364.   
  365.   /* handle error */
  366.   if(format == 0)
  367.     return 0;
  368.   
  369.   /* parse the number */
  370.   *num = unum_parse(format, stream->fUCPos, len, &parsePos, &status);
  371.  
  372.   /* mask off any necessary bits */
  373.   if(info->fIsShort)
  374.     *num &= SHRT_MAX;
  375.   else if(! info->fIsLong || ! info->fIsLongLong)
  376.     *num &= INT_MAX;
  377.  
  378.   /* update the stream's position to reflect consumed data */
  379.   stream->fUCPos += parsePos;
  380.   
  381.   /* we converted 1 arg */
  382.   return 1;
  383. }
  384.  
  385. int32_t 
  386. u_scanf_double_info(const u_scanf_spec_info     *info,
  387.             int32_t             *argtypes,
  388.             int32_t             n)
  389. {
  390.   /* handle error */
  391.   if(n < 1)
  392.     return 0;
  393.  
  394.   /* we need 1 argument of type double */
  395.   argtypes[0] = ufmt_double;
  396.   return 1;
  397. }
  398.  
  399. int32_t
  400. u_scanf_double_handler(UFILE             *stream,
  401.                const u_scanf_spec_info     *info,
  402.                ufmt_args        *args,
  403.                const UChar        *fmt,
  404.                int32_t            *consumed)
  405. {
  406.   int32_t        len;
  407.   double        *num         = (double*) (args[0].ptrValue);
  408.   UNumberFormat        *format;
  409.   int32_t        parsePos     = 0;
  410.   UErrorCode         status         = U_ZERO_ERROR;
  411.  
  412.  
  413.   /* skip all ws in the stream */
  414.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  415.  
  416.   /* fill the stream's internal buffer */
  417.   ufile_fill_uchar_buffer(stream);
  418.  
  419.   /* determine the size of the stream's buffer */
  420.   len = stream->fUCLimit - stream->fUCPos;
  421.  
  422.   /* truncate to the width, if specified */
  423.   if(info->fWidth != -1)
  424.     len = ufmt_min(len, info->fWidth);
  425.  
  426.   /* get the formatter */
  427.   format = u_locbund_getNumberFormat(stream->fBundle);
  428.   
  429.   /* handle error */
  430.   if(format == 0)
  431.     return 0;
  432.   
  433.   /* parse the number */
  434.   *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status);
  435.  
  436.   /* mask off any necessary bits */
  437.   /*  if(! info->fIsLong_double)
  438.       num &= DBL_MAX;*/
  439.  
  440.   /* update the stream's position to reflect consumed data */
  441.   stream->fUCPos += parsePos;
  442.   
  443.   /* we converted 1 arg */
  444.   return 1;
  445. }
  446.  
  447. int32_t 
  448. u_scanf_scientific_info(const u_scanf_spec_info     *info,
  449.             int32_t             *argtypes,
  450.             int32_t             n)
  451. {
  452.   /* handle error */
  453.   if(n < 1)
  454.     return 0;
  455.  
  456.   /* we need 1 argument of type double */
  457.   argtypes[0] = ufmt_double;
  458.   return 1;
  459. }
  460.  
  461. int32_t
  462. u_scanf_scientific_handler(UFILE             *stream,
  463.                const u_scanf_spec_info     *info,
  464.                ufmt_args           *args,
  465.                const UChar            *fmt,
  466.                int32_t            *consumed)
  467. {
  468.   int32_t        len;
  469.   double        *num         = (double*) (args[0].ptrValue);
  470.   UNumberFormat        *format;
  471.   int32_t        parsePos     = 0;
  472.   UErrorCode         status         = U_ZERO_ERROR;
  473.  
  474.  
  475.   /* skip all ws in the stream */
  476.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  477.  
  478.   /* fill the stream's internal buffer */
  479.   ufile_fill_uchar_buffer(stream);
  480.  
  481.   /* determine the size of the stream's buffer */
  482.   len = stream->fUCLimit - stream->fUCPos;
  483.  
  484.   /* truncate to the width, if specified */
  485.   if(info->fWidth != -1)
  486.     len = ufmt_min(len, info->fWidth);
  487.  
  488.   /* get the formatter */
  489.   format = u_locbund_getScientificFormat(stream->fBundle);
  490.   
  491.   /* handle error */
  492.   if(format == 0)
  493.     return 0;
  494.   
  495.   /* parse the number */
  496.   *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status);
  497.  
  498.   /* mask off any necessary bits */
  499.   /*  if(! info->fIsLong_double)
  500.       num &= DBL_MAX;*/
  501.  
  502.   /* update the stream's position to reflect consumed data */
  503.   stream->fUCPos += parsePos;
  504.   
  505.   /* we converted 1 arg */
  506.   return 1;
  507. }
  508.  
  509. int32_t 
  510. u_scanf_scidbl_info(const u_scanf_spec_info     *info,
  511.             int32_t             *argtypes,
  512.             int32_t             n)
  513. {
  514.   /* handle error */
  515.   if(n < 1)
  516.     return 0;
  517.  
  518.   /* we need 1 argument of type double */
  519.   argtypes[0] = ufmt_double;
  520.   return 1;
  521. }
  522.  
  523. int32_t
  524. u_scanf_scidbl_handler(UFILE             *stream,
  525.                const u_scanf_spec_info     *info,
  526.                ufmt_args        *args,
  527.                const UChar        *fmt,
  528.                int32_t            *consumed)
  529. {
  530.   int32_t        len;
  531.   double        *num         = (double*) (args[0].ptrValue);
  532.   UNumberFormat        *scientificFormat, *genericFormat;
  533.   int32_t        scientificResult, genericResult;
  534.   int32_t        scientificParsePos = 0, genericParsePos = 0;
  535.   UErrorCode         scientificStatus = U_ZERO_ERROR;
  536.   UErrorCode         genericStatus = U_ZERO_ERROR;
  537.   bool_t        useScientific;
  538.  
  539.  
  540.   /* since we can't determine by scanning the characters whether */
  541.   /* a number was formatted in the 'f' or 'g' styles, parse the */
  542.   /* string with both formatters, and assume whichever one */
  543.   /* parsed the most is the correct formatter to use */
  544.  
  545.  
  546.   /* skip all ws in the stream */
  547.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  548.  
  549.   /* fill the stream's internal buffer */
  550.   ufile_fill_uchar_buffer(stream);
  551.  
  552.   /* determine the size of the stream's buffer */
  553.   len = stream->fUCLimit - stream->fUCPos;
  554.  
  555.   /* truncate to the width, if specified */
  556.   if(info->fWidth != -1)
  557.     len = ufmt_min(len, info->fWidth);
  558.  
  559.   /* get the formatters */
  560.   scientificFormat = u_locbund_getScientificFormat(stream->fBundle);
  561.   genericFormat = u_locbund_getNumberFormat(stream->fBundle);
  562.   
  563.   /* handle error */
  564.   if(scientificFormat == 0 || genericFormat == 0)
  565.     return 0;
  566.   
  567.   /* parse the number using each format*/
  568.  
  569.   scientificResult = unum_parseDouble(scientificFormat, stream->fUCPos, len,
  570.                       &scientificParsePos, &scientificStatus);
  571.  
  572.   genericResult = unum_parseDouble(genericFormat, stream->fUCPos, len,
  573.                    &genericParsePos, &genericStatus);
  574.  
  575.   /* determine which parse made it farther */
  576.   useScientific = scientificParsePos > genericParsePos;
  577.   
  578.   /* stash the result in num */
  579.   *num = useScientific ? scientificResult : genericResult;
  580.   
  581.   /* mask off any necessary bits */
  582.   /*  if(! info->fIsLong_double)
  583.       num &= DBL_MAX;*/
  584.  
  585.   /* update the stream's position to reflect consumed data */
  586.   stream->fUCPos += useScientific ? scientificParsePos : genericParsePos;
  587.   
  588.   /* we converted 1 arg */
  589.   return 1;
  590. }
  591.  
  592. int32_t 
  593. u_scanf_currency_info(const u_scanf_spec_info     *info,
  594.               int32_t             *argtypes,
  595.               int32_t             n)
  596. {
  597.   /* handle error */
  598.   if(n < 1)
  599.     return 0;
  600.  
  601.   /* we need 1 argument of type double */
  602.   argtypes[0] = ufmt_double;
  603.   return 1;
  604. }
  605.  
  606. int32_t
  607. u_scanf_currency_handler(UFILE                 *stream,
  608.              const u_scanf_spec_info     *info,
  609.              ufmt_args            *args,
  610.              const UChar            *fmt,
  611.              int32_t            *consumed)
  612. {
  613.   int32_t        len;
  614.   double        *num         = (double*) (args[0].ptrValue);
  615.   UNumberFormat        *format;
  616.   int32_t        parsePos     = 0;
  617.   UErrorCode         status         = U_ZERO_ERROR;
  618.  
  619.  
  620.   /* skip all ws in the stream */
  621.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  622.  
  623.   /* fill the stream's internal buffer */
  624.   ufile_fill_uchar_buffer(stream);
  625.  
  626.   /* determine the size of the stream's buffer */
  627.   len = stream->fUCLimit - stream->fUCPos;
  628.  
  629.   /* truncate to the width, if specified */
  630.   if(info->fWidth != -1)
  631.     len = ufmt_min(len, info->fWidth);
  632.  
  633.   /* get the formatter */
  634.   format = u_locbund_getCurrencyFormat(stream->fBundle);
  635.   
  636.   /* handle error */
  637.   if(format == 0)
  638.     return 0;
  639.   
  640.   /* parse the number */
  641.   *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status);
  642.   
  643.   /* mask off any necessary bits */
  644.   /*  if(! info->fIsLong_double)
  645.       num &= DBL_MAX;*/
  646.  
  647.   /* update the stream's position to reflect consumed data */
  648.   stream->fUCPos += parsePos;
  649.   
  650.   /* we converted 1 arg */
  651.   return 1;
  652. }
  653.  
  654. int32_t 
  655. u_scanf_percent_info(const u_scanf_spec_info     *info,
  656.              int32_t             *argtypes,
  657.              int32_t             n)
  658. {
  659.   /* handle error */
  660.   if(n < 1)
  661.     return 0;
  662.  
  663.   /* we need 1 argument of type double */
  664.   argtypes[0] = ufmt_double;
  665.   return 1;
  666. }
  667.  
  668. int32_t
  669. u_scanf_percent_handler(UFILE             *stream,
  670.             const u_scanf_spec_info *info,
  671.             ufmt_args        *args,
  672.             const UChar        *fmt,
  673.             int32_t            *consumed)
  674. {
  675.   int32_t        len;
  676.   double        *num         = (double*) (args[0].ptrValue);
  677.   UNumberFormat        *format;
  678.   int32_t        parsePos     = 0;
  679.   UErrorCode         status         = U_ZERO_ERROR;
  680.  
  681.  
  682.   /* skip all ws in the stream */
  683.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  684.  
  685.   /* fill the stream's internal buffer */
  686.   ufile_fill_uchar_buffer(stream);
  687.  
  688.   /* determine the size of the stream's buffer */
  689.   len = stream->fUCLimit - stream->fUCPos;
  690.  
  691.   /* truncate to the width, if specified */
  692.   if(info->fWidth != -1)
  693.     len = ufmt_min(len, info->fWidth);
  694.  
  695.   /* get the formatter */
  696.   format = u_locbund_getPercentFormat(stream->fBundle);
  697.   
  698.   /* handle error */
  699.   if(format == 0)
  700.     return 0;
  701.   
  702.   /* parse the number */
  703.   *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status);
  704.  
  705.   /* mask off any necessary bits */
  706.   /*  if(! info->fIsLong_double)
  707.       num &= DBL_MAX;*/
  708.  
  709.   /* update the stream's position to reflect consumed data */
  710.   stream->fUCPos += parsePos;
  711.   
  712.   /* we converted 1 arg */
  713.   return 1;
  714. }
  715.  
  716. int32_t 
  717. u_scanf_date_info(const u_scanf_spec_info     *info,
  718.           int32_t             *argtypes,
  719.           int32_t             n)
  720. {
  721.   /* handle error */
  722.   if(n < 1)
  723.     return 0;
  724.  
  725.   /* we need 1 argument of type Date */
  726.   argtypes[0] = ufmt_date;
  727.   return 1;
  728. }
  729.  
  730. int32_t
  731. u_scanf_date_handler(UFILE             *stream,
  732.              const u_scanf_spec_info     *info,
  733.              ufmt_args        *args,
  734.              const UChar        *fmt,
  735.              int32_t            *consumed)
  736. {
  737.   int32_t        len;
  738.   UDate            *date         = (UDate*) (args[0].ptrValue);
  739.   UDateFormat        *format;
  740.   int32_t        parsePos     = 0;
  741.   UErrorCode         status         = U_ZERO_ERROR;
  742.  
  743.  
  744.   /* skip all ws in the stream */
  745.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  746.  
  747.   /* fill the stream's internal buffer */
  748.   ufile_fill_uchar_buffer(stream);
  749.  
  750.   /* determine the size of the stream's buffer */
  751.   len = stream->fUCLimit - stream->fUCPos;
  752.  
  753.   /* truncate to the width, if specified */
  754.   if(info->fWidth != -1)
  755.     len = ufmt_min(len, info->fWidth);
  756.  
  757.   /* get the formatter */
  758.   format = u_locbund_getDateFormat(stream->fBundle);
  759.   
  760.   /* handle error */
  761.   if(format == 0)
  762.     return 0;
  763.   
  764.   /* parse the number */
  765.   *date = udat_parse(format, stream->fUCPos, len, &parsePos, &status);
  766.   
  767.   /* update the stream's position to reflect consumed data */
  768.   stream->fUCPos += parsePos;
  769.   
  770.   /* we converted 1 arg */
  771.   return 1;
  772. }
  773.  
  774. int32_t 
  775. u_scanf_time_info(const u_scanf_spec_info     *info,
  776.           int32_t             *argtypes,
  777.           int32_t             n)
  778. {
  779.   /* handle error */
  780.   if(n < 1)
  781.     return 0;
  782.  
  783.   /* we need 1 argument of type Date */
  784.   argtypes[0] = ufmt_date;
  785.   return 1;
  786. }
  787.  
  788. int32_t
  789. u_scanf_time_handler(UFILE             *stream,
  790.              const u_scanf_spec_info     *info,
  791.              ufmt_args        *args,
  792.              const UChar        *fmt,
  793.              int32_t            *consumed)
  794. {
  795.   int32_t        len;
  796.   UDate            *time         = (UDate*) (args[0].ptrValue);
  797.   UDateFormat        *format;
  798.   int32_t        parsePos     = 0;
  799.   UErrorCode         status         = U_ZERO_ERROR;
  800.  
  801.  
  802.   /* skip all ws in the stream */
  803.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  804.  
  805.   /* fill the stream's internal buffer */
  806.   ufile_fill_uchar_buffer(stream);
  807.  
  808.   /* determine the size of the stream's buffer */
  809.   len = stream->fUCLimit - stream->fUCPos;
  810.  
  811.   /* truncate to the width, if specified */
  812.   if(info->fWidth != -1)
  813.     len = ufmt_min(len, info->fWidth);
  814.  
  815.   /* get the formatter */
  816.   format = u_locbund_getTimeFormat(stream->fBundle);
  817.   
  818.   /* handle error */
  819.   if(format == 0)
  820.     return 0;
  821.   
  822.   /* parse the number */
  823.   *time = udat_parse(format, stream->fUCPos, len, &parsePos, &status);
  824.   
  825.   /* update the stream's position to reflect consumed data */
  826.   stream->fUCPos += parsePos;
  827.   
  828.   /* we converted 1 arg */
  829.   return 1;
  830. }
  831.  
  832. int32_t 
  833. u_scanf_char_info(const u_scanf_spec_info     *info,
  834.           int32_t             *argtypes,
  835.           int32_t             n)
  836. {
  837.   /* handle error */
  838.   if(n < 1)
  839.     return 0;
  840.  
  841.   /* we need 1 argument of type char */
  842.   argtypes[0] = ufmt_char;
  843.   return 1;
  844. }
  845.  
  846. int32_t
  847. u_scanf_char_handler(UFILE             *stream,
  848.              const u_scanf_spec_info     *info,
  849.              ufmt_args        *args,
  850.              const UChar        *fmt,
  851.              int32_t            *consumed)
  852. {
  853.   UChar uc;
  854.   char *result;
  855.   char *c = (char*)(args[0].ptrValue);
  856.   
  857.   /* skip all ws in the stream */
  858.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  859.   
  860.   /* get the character from the stream, truncating to the width */
  861.   if(info->fWidth == -1 || info->fWidth > 1)
  862.     uc = u_fgetc(stream);
  863.  
  864.   /* handle EOF */
  865.   if(uc == 0xFFFF)
  866.     return -1;
  867.  
  868.   /* convert the character to the default codepage */
  869.   result = ufmt_unicodeToDefaultCP(&uc, 1);
  870.   *c = result[0];
  871.  
  872.   /* clean up */
  873.   free(result);
  874.   
  875.   /* we converted 1 arg */
  876.   return 1;
  877. }
  878.  
  879. int32_t 
  880. u_scanf_uchar_info(const u_scanf_spec_info     *info,
  881.            int32_t             *argtypes,
  882.            int32_t             n)
  883. {
  884.   /* handle error */
  885.   if(n < 1)
  886.     return 0;
  887.  
  888.   /* we need 1 argument of type uchar */
  889.   argtypes[0] = ufmt_uchar;
  890.   return 1;
  891. }
  892.  
  893. int32_t
  894. u_scanf_uchar_handler(UFILE             *stream,
  895.               const u_scanf_spec_info     *info,
  896.               ufmt_args        *args,
  897.               const UChar        *fmt,
  898.               int32_t            *consumed)
  899. {
  900.   UChar *c = (UChar*)(args[0].ptrValue);
  901.   
  902.   /* skip all ws in the stream */
  903.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  904.   
  905.   /* get the character from the stream, truncating to the width */
  906.   if(info->fWidth == -1 || info->fWidth > 1)
  907.     *c = u_fgetc(stream);
  908.  
  909.   /* handle EOF */
  910.   if(*c == 0xFFFF)
  911.     return -1;
  912.  
  913.   /* we converted 1 arg */
  914.   return 1;
  915. }
  916.  
  917. int32_t 
  918. u_scanf_spellout_info(const u_scanf_spec_info     *info,
  919.               int32_t             *argtypes,
  920.               int32_t             n)
  921. {
  922.   /* handle error */
  923.   if(n < 1)
  924.     return 0;
  925.  
  926.   /* we need 1 argument of type double */
  927.   argtypes[0] = ufmt_double;
  928.   return 1;
  929. }
  930.  
  931. int32_t
  932. u_scanf_spellout_handler(UFILE                 *stream,
  933.              const u_scanf_spec_info     *info,
  934.              ufmt_args             *args,
  935.              const UChar            *fmt,
  936.              int32_t            *consumed)
  937. {
  938.   int32_t        len;
  939.   double        *num         = (double*) (args[0].ptrValue);
  940.   UNumberFormat        *format;
  941.   int32_t        parsePos     = 0;
  942.   UErrorCode         status         = U_ZERO_ERROR;
  943.  
  944.  
  945.   /* skip all ws in the stream */
  946.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  947.  
  948.   /* fill the stream's internal buffer */
  949.   ufile_fill_uchar_buffer(stream);
  950.  
  951.   /* determine the size of the stream's buffer */
  952.   len = stream->fUCLimit - stream->fUCPos;
  953.  
  954.   /* truncate to the width, if specified */
  955.   if(info->fWidth != -1)
  956.     len = ufmt_min(len, info->fWidth);
  957.  
  958.   /* get the formatter */
  959.   format = u_locbund_getSpelloutFormat(stream->fBundle);
  960.   
  961.   /* handle error */
  962.   if(format == 0)
  963.     return 0;
  964.   
  965.   /* parse the number */
  966.   *num = unum_parseDouble(format, stream->fUCPos, len, &parsePos, &status);
  967.  
  968.   /* mask off any necessary bits */
  969.   /*  if(! info->fIsLong_double)
  970.       num &= DBL_MAX;*/
  971.  
  972.   /* update the stream's position to reflect consumed data */
  973.   stream->fUCPos += parsePos;
  974.   
  975.   /* we converted 1 arg */
  976.   return 1;
  977. }
  978.  
  979. int32_t 
  980. u_scanf_hex_info(const u_scanf_spec_info     *info,
  981.          int32_t             *argtypes,
  982.          int32_t             n)
  983. {
  984.   /* handle error */
  985.   if(n < 1)
  986.     return 0;
  987.  
  988.   /* we need 1 argument of type int */
  989.   argtypes[0] = ufmt_int;
  990.   return 1;
  991. }
  992.  
  993. int32_t
  994. u_scanf_hex_handler(UFILE             *stream,
  995.             const u_scanf_spec_info     *info,
  996.             ufmt_args            *args,
  997.             const UChar            *fmt,
  998.             int32_t            *consumed)
  999. {
  1000.   int32_t        len;
  1001.   long            *num         = (long*) (args[0].ptrValue);
  1002.  
  1003.  
  1004.   /* skip all ws in the stream */
  1005.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  1006.  
  1007.   /* fill the stream's internal buffer */
  1008.   ufile_fill_uchar_buffer(stream);
  1009.  
  1010.   /* determine the size of the stream's buffer */
  1011.   len = stream->fUCLimit - stream->fUCPos;
  1012.  
  1013.   /* truncate to the width, if specified */
  1014.   if(info->fWidth != -1)
  1015.     len = ufmt_min(len, info->fWidth);
  1016.  
  1017.   /* check for alternate form */
  1018.   if( *(stream->fUCPos) == 0x0030 && 
  1019.       (*(stream->fUCPos + 1) == 0x0078 || *(stream->fUCPos + 1) == 0x0058) ) {
  1020.  
  1021.     /* skip the '0' and 'x' or 'X' if present */
  1022.     stream->fUCPos += 2;
  1023.     len -= 2;
  1024.   }
  1025.  
  1026.   /* parse the number */
  1027.   *num = ufmt_utol(stream->fUCPos, &len, 16);
  1028.  
  1029.   /* update the stream's position to reflect consumed data */
  1030.   stream->fUCPos += len;
  1031.  
  1032.   /* mask off any necessary bits */
  1033.   if(info->fIsShort)
  1034.     *num &= SHRT_MAX;
  1035.   else if(! info->fIsLong || ! info->fIsLongLong)
  1036.     *num &= INT_MAX;
  1037.  
  1038.   /* we converted 1 arg */
  1039.   return 1;
  1040. }
  1041.  
  1042. int32_t 
  1043. u_scanf_octal_info(const u_scanf_spec_info    *info,
  1044.            int32_t             *argtypes,
  1045.            int32_t             n)
  1046. {
  1047.   /* handle error */
  1048.   if(n < 1)
  1049.     return 0;
  1050.   
  1051.   /* we need 1 argument of type int */
  1052.   argtypes[0] = ufmt_int;
  1053.   return 1;
  1054. }
  1055.  
  1056. int32_t
  1057. u_scanf_octal_handler(UFILE             *stream,
  1058.               const u_scanf_spec_info     *info,
  1059.               ufmt_args         *args,
  1060.               const UChar        *fmt,
  1061.               int32_t            *consumed)
  1062. {
  1063.   int32_t        len;
  1064.   long            *num         = (long*) (args[0].ptrValue);
  1065.  
  1066.  
  1067.   /* skip all ws in the stream */
  1068.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  1069.  
  1070.   /* fill the stream's internal buffer */
  1071.   ufile_fill_uchar_buffer(stream);
  1072.  
  1073.   /* determine the size of the stream's buffer */
  1074.   len = stream->fUCLimit - stream->fUCPos;
  1075.  
  1076.   /* truncate to the width, if specified */
  1077.   if(info->fWidth != -1)
  1078.     len = ufmt_min(len, info->fWidth);
  1079.  
  1080.   /* parse the number */
  1081.   *num = ufmt_utol(stream->fUCPos, &len, 8);
  1082.  
  1083.   /* update the stream's position to reflect consumed data */
  1084.   stream->fUCPos += len;
  1085.  
  1086.   /* mask off any necessary bits */
  1087.   if(info->fIsShort)
  1088.     *num &= SHRT_MAX;
  1089.   else if(! info->fIsLong || ! info->fIsLongLong)
  1090.     *num &= INT_MAX;
  1091.  
  1092.   /* we converted 1 arg */
  1093.   return 1;
  1094. }
  1095.  
  1096. int32_t 
  1097. u_scanf_pointer_info(const u_scanf_spec_info     *info,
  1098.              int32_t             *argtypes,
  1099.              int32_t             n)
  1100. {
  1101.   /* handle error */
  1102.   if(n < 1)
  1103.     return 0;
  1104.  
  1105.   /* we need 1 argument of type void* */
  1106.   argtypes[0] = ufmt_pointer;
  1107.   return 1;
  1108. }
  1109.  
  1110. int32_t
  1111. u_scanf_pointer_handler(UFILE             *stream,
  1112.             const u_scanf_spec_info *info,
  1113.             ufmt_args        *args,
  1114.             const UChar        *fmt,
  1115.             int32_t            *consumed)
  1116. {
  1117.   int32_t    len;
  1118.   void        *p     = (void*)(args[0].ptrValue);
  1119.  
  1120.  
  1121.   /* skip all ws in the stream */
  1122.   u_scanf_skip_leading_ws(stream, info->fPadChar);
  1123.  
  1124.   /* fill the stream's internal buffer */
  1125.   ufile_fill_uchar_buffer(stream);
  1126.  
  1127.   /* determine the size of the stream's buffer */
  1128.   len = stream->fUCLimit - stream->fUCPos;
  1129.  
  1130.   /* truncate to the width, if specified */
  1131.   if(info->fWidth != -1)
  1132.     len = ufmt_min(len, info->fWidth);
  1133.  
  1134.   /* parse the pointer - cast to void** to assign to *p */
  1135.   *(void**)p = (void*) ufmt_utol(stream->fUCPos, &len, 16);
  1136.  
  1137.   /* update the stream's position to reflect consumed data */
  1138.   stream->fUCPos += len;
  1139.  
  1140.   /* we converted 1 arg */
  1141.   return 1;
  1142. }
  1143.  
  1144. int32_t 
  1145. u_scanf_scanset_info(const u_scanf_spec_info     *info,
  1146.              int32_t             *argtypes,
  1147.              int32_t             n)
  1148. {
  1149.   /* handle error */
  1150.   if(n < 1)
  1151.     return 0;
  1152.  
  1153.   /* we need 1 argument of type char* */
  1154.   argtypes[0] = ufmt_string;
  1155.   return 1;
  1156. }
  1157.  
  1158. int32_t
  1159. u_scanf_scanset_handler(UFILE             *stream,
  1160.             const u_scanf_spec_info *info,
  1161.             ufmt_args        *args,
  1162.             const UChar        *fmt,
  1163.             int32_t            *consumed)
  1164. {
  1165.   u_scanf_scanset    scanset;
  1166.   int32_t        len;
  1167.   bool_t        success;
  1168.   UChar            c;
  1169.   const UChar         *source;
  1170.   UConverter         *conv;
  1171.   UErrorCode         status     = U_ZERO_ERROR;
  1172.   char            *s     = (char*) (args[0].ptrValue);
  1173.   char             *alias, *limit;
  1174.  
  1175.  
  1176.   /* fill the stream's internal buffer */
  1177.   ufile_fill_uchar_buffer(stream);
  1178.  
  1179.   /* determine the size of the stream's buffer */
  1180.   len = stream->fUCLimit - stream->fUCPos;
  1181.  
  1182.   /* truncate to the width, if specified */
  1183.   if(info->fWidth != -1)
  1184.     len = ufmt_min(len, info->fWidth);
  1185.  
  1186.   /* alias the target */
  1187.   alias = s;
  1188.   limit = alias + len;
  1189.  
  1190.   /* parse the scanset from the fmt string */
  1191.   *consumed = u_strlen(fmt);
  1192.   success = u_scanf_scanset_init(&scanset, fmt, consumed);
  1193.  
  1194.   /* increment consumed by one to eat the final ']' */
  1195.   ++(*consumed);
  1196.  
  1197.   /* open the default converter */
  1198.   conv = ucnv_open(ucnv_getDefaultName(), &status);
  1199.  
  1200.   /* verify that the parse was successful and the converter opened */
  1201.   if(! success || U_FAILURE(status))
  1202.     return -1;
  1203.  
  1204.   /* grab characters one at a time and make sure they are in the scanset */
  1205.   while( (c = u_fgetc(stream)) != 0xFFFF && alias < limit) {
  1206.     if(u_scanf_scanset_in(&scanset, c)) {
  1207.       source = &c;
  1208.       /* convert the character to the default codepage */
  1209.       ucnv_fromUnicode(conv, &alias, limit, &source, source + 1,
  1210.                NULL, TRUE, &status);
  1211.       
  1212.       if(U_FAILURE(status))
  1213.     return -1;
  1214.     }
  1215.     /* if the character's not in the scanset, break out */
  1216.     else {
  1217.       break;
  1218.     }
  1219.   }
  1220.  
  1221.   /* put the final character we read back on the stream */  
  1222.   if(c != 0xFFFF)
  1223.     u_fungetc(c, stream);
  1224.  
  1225.   /* if we didn't match at least 1 character, fail */
  1226.   if(alias == s)
  1227.     return -1;
  1228.   /* otherwise, add the terminator */
  1229.   else
  1230.     *alias = 0x00;
  1231.  
  1232.   /* clean up */
  1233.   ucnv_close(conv);
  1234.  
  1235.   /* we converted 1 arg */
  1236.   return 1;
  1237. }
  1238.  
  1239. void
  1240. u_scanf_init()
  1241. {
  1242.   int32_t i;
  1243.   /*Mutex *lock;*/
  1244.   
  1245.   /* if we're already inited, do nothing */
  1246.   if(g_u_scanf_inited)
  1247.     return;
  1248.  
  1249.   /* lock the cache */
  1250.   umtx_lock(0);
  1251.  
  1252.   /* if we're already inited, do nothing */
  1253.   if(g_u_scanf_inited) {
  1254.     umtx_unlock(0);
  1255.     return;
  1256.   }
  1257.  
  1258.   /* initialize all handlers and infos to 0 */
  1259.   for(i = 0; i < 256; ++i) {
  1260.     g_u_scanf_infos[i]         = 0;
  1261.     g_u_scanf_handlers[i]     = 0;
  1262.   }
  1263.  
  1264.   /* register the handlers for standard specifiers */
  1265.   /* don't use u_scanf_register_handler to avoid mutex creation */
  1266.  
  1267.   /* handle '%' */
  1268.   g_u_scanf_infos[ 0x0025 ]     = u_scanf_simple_percent_info;
  1269.   g_u_scanf_handlers[ 0x0025 ]     = u_scanf_simple_percent_handler;
  1270.  
  1271.   /* handle 's' */
  1272.   g_u_scanf_infos[ 0x0073 ]     = u_scanf_string_info;
  1273.   g_u_scanf_handlers[ 0x0073 ]     = u_scanf_string_handler;
  1274.  
  1275.   /* handle 'U' */
  1276.   g_u_scanf_infos[ 0x0055 ]     = u_scanf_ustring_info;
  1277.   g_u_scanf_handlers[ 0x0055 ]     = u_scanf_ustring_handler;
  1278.  
  1279.   /* handle 'n' */
  1280.   g_u_scanf_infos[ 0x006E ]     = u_scanf_count_info;
  1281.   g_u_scanf_handlers[ 0x006E ]     = u_scanf_count_handler;
  1282.  
  1283.   /* handle 'd' */
  1284.   g_u_scanf_infos[ 0x0064 ]     = u_scanf_integer_info;
  1285.   g_u_scanf_handlers[ 0x0064 ]     = u_scanf_integer_handler;
  1286.  
  1287.   /* handle 'i' */
  1288.   g_u_scanf_infos[ 0x0069 ]     = u_scanf_integer_info;
  1289.   g_u_scanf_handlers[ 0x0069 ]     = u_scanf_integer_handler;
  1290.  
  1291.   /* handle 'u' */
  1292.   g_u_scanf_infos[ 0x0075 ]     = u_scanf_integer_info;
  1293.   g_u_scanf_handlers[ 0x0075 ]     = u_scanf_integer_handler;
  1294.  
  1295.   /* handle 'f' */
  1296.   g_u_scanf_infos[ 0x0066 ]     = u_scanf_double_info;
  1297.   g_u_scanf_handlers[ 0x0066 ]     = u_scanf_double_handler;
  1298.  
  1299.   /* handle 'e' */
  1300.   g_u_scanf_infos[ 0x0065 ]     = u_scanf_scientific_info;
  1301.   g_u_scanf_handlers[ 0x0065 ]     = u_scanf_scientific_handler;
  1302.  
  1303.   /* handle 'E' */
  1304.   g_u_scanf_infos[ 0x0045 ]     = u_scanf_scientific_info;
  1305.   g_u_scanf_handlers[ 0x0045 ]     = u_scanf_scientific_handler;
  1306.  
  1307.   /* handle 'g' */
  1308.   g_u_scanf_infos[ 0x0067 ]     = u_scanf_scidbl_info;
  1309.   g_u_scanf_handlers[ 0x0067 ]     = u_scanf_scidbl_handler;
  1310.  
  1311.   /* handle 'G' */
  1312.   g_u_scanf_infos[ 0x0047 ]     = u_scanf_scidbl_info;
  1313.   g_u_scanf_handlers[ 0x0047 ]     = u_scanf_scidbl_handler;
  1314.  
  1315.   /* handle 'M' */
  1316.   g_u_scanf_infos[ 0x004D ]     = u_scanf_currency_info;
  1317.   g_u_scanf_handlers[ 0x004D ]     = u_scanf_currency_handler;
  1318.  
  1319.   /* handle 'P' */
  1320.   g_u_scanf_infos[ 0x0050 ]     = u_scanf_percent_info;
  1321.   g_u_scanf_handlers[ 0x0050 ]     = u_scanf_percent_handler;
  1322.  
  1323.   /* handle 'D' */
  1324.   g_u_scanf_infos[ 0x0044 ]     = u_scanf_date_info;
  1325.   g_u_scanf_handlers[ 0x0044 ]     = u_scanf_date_handler;
  1326.  
  1327.   /* handle 'T' */
  1328.   g_u_scanf_infos[ 0x0054 ]     = u_scanf_time_info;
  1329.   g_u_scanf_handlers[ 0x0054 ]     = u_scanf_time_handler;
  1330.  
  1331.   /* handle 'c' */
  1332.   g_u_scanf_infos[ 0x0063 ]     = u_scanf_char_info;
  1333.   g_u_scanf_handlers[ 0x0063 ]     = u_scanf_char_handler;
  1334.  
  1335.   /* handle 'K' */
  1336.   g_u_scanf_infos[ 0x004B ]     = u_scanf_uchar_info;
  1337.   g_u_scanf_handlers[ 0x004B ]     = u_scanf_uchar_handler;
  1338.  
  1339.   /* handle 'V' */
  1340.   g_u_scanf_infos[ 0x0056 ]     = u_scanf_spellout_info;
  1341.   g_u_scanf_handlers[ 0x0056 ]     = u_scanf_spellout_handler;
  1342.  
  1343.   /* handle 'x' */
  1344.   g_u_scanf_infos[ 0x0078 ]     = u_scanf_hex_info;
  1345.   g_u_scanf_handlers[ 0x0078 ]     = u_scanf_hex_handler;
  1346.  
  1347.   /* handle 'X' */
  1348.   g_u_scanf_infos[ 0x0058 ]     = u_scanf_hex_info;
  1349.   g_u_scanf_handlers[ 0x0058 ]     = u_scanf_hex_handler;
  1350.  
  1351.   /* handle 'o' */
  1352.   g_u_scanf_infos[ 0x006F ]     = u_scanf_octal_info;
  1353.   g_u_scanf_handlers[ 0x006F ]     = u_scanf_octal_handler;
  1354.  
  1355.   /* handle 'p' */
  1356.   g_u_scanf_infos[ 0x0070 ]     = u_scanf_pointer_info;
  1357.   g_u_scanf_handlers[ 0x0070 ]     = u_scanf_pointer_handler;
  1358.  
  1359.   /* handle '[' */
  1360.   g_u_scanf_infos[ 0x005B ]     = u_scanf_scanset_info;
  1361.   g_u_scanf_handlers[ 0x005B ]     = u_scanf_scanset_handler;
  1362.  
  1363.   /* we're finished */
  1364.   g_u_scanf_inited = TRUE;
  1365.  
  1366.   /* unlock the cache */
  1367.   umtx_unlock(0);
  1368. }
  1369.  
  1370.  
  1371. #define U_SCANF_MAX_ARGS 32
  1372. #define UP_PERCENT 0x0025
  1373.  
  1374. int32_t 
  1375. u_vfscanf_u(    UFILE        *f,
  1376.         const UChar    *patternSpecification,
  1377.         va_list        ap)
  1378. {
  1379.   u_scanf_spec         spec;
  1380.   const UChar         *alias;
  1381.   int32_t         count, converted, temp;
  1382.  
  1383.   int32_t         num_args_wanted;
  1384.   int32_t         ufmt_types     [U_SCANF_MAX_ARGS];
  1385.   ufmt_args       args         [U_SCANF_MAX_ARGS];
  1386.  
  1387.   u_scanf_info        info;
  1388.   u_scanf_handler    handler;
  1389.  
  1390.   int32_t         cur_arg;
  1391.  
  1392.  
  1393.   /* init our function tables */
  1394.   if(! g_u_scanf_inited)
  1395.     u_scanf_init();
  1396.  
  1397.   /* alias the pattern */
  1398.   alias = patternSpecification;
  1399.   
  1400.   /* haven't converted anything yet */
  1401.   converted = 0;
  1402.  
  1403.   /* iterate through the pattern */
  1404.   for(;;) {
  1405.     
  1406.     /* match any characters up to the next '%' */
  1407.     while(*alias != UP_PERCENT && *alias != 0x0000 && u_fgetc(f) == *alias) {
  1408.       *alias++;
  1409.     }
  1410.  
  1411.     /* if we aren't at a '%', or if we're at end of string, break*/
  1412.     if(*alias != UP_PERCENT || *alias == 0x0000)
  1413.       break;
  1414.     
  1415.     /* parse the specifier */
  1416.     count = u_scanf_parse_spec(alias, &spec);
  1417.     
  1418.     /* update the pointer in pattern */
  1419.     alias += count;
  1420.     
  1421.     /* skip the argument, if necessary */
  1422.     if(spec.fSkipArg)
  1423.       va_arg(ap, int);
  1424.     
  1425.     /* query the info function for argument information */
  1426.     info = g_u_scanf_infos[ (unsigned char) spec.fInfo.fSpec ];
  1427.     if(info != 0) { 
  1428.       num_args_wanted = (*info)(&spec.fInfo, 
  1429.                 ufmt_types,
  1430.                 U_SCANF_MAX_ARGS);
  1431.     }
  1432.     else
  1433.       num_args_wanted = 0;
  1434.  
  1435.     /* fill in the requested arguments */
  1436.     for(cur_arg = 0; 
  1437.     cur_arg < num_args_wanted && cur_arg < U_SCANF_MAX_ARGS; 
  1438.     ++cur_arg) {
  1439.       
  1440.       switch(ufmt_types[cur_arg]) {
  1441.  
  1442.       case ufmt_count:
  1443.     args[cur_arg].intValue = va_arg(ap, int);
  1444.     /* set the spec's width to the # of items converted */
  1445.     spec.fInfo.fWidth = converted;
  1446.     break;
  1447.  
  1448.       case ufmt_int:
  1449.     args[cur_arg].ptrValue = va_arg(ap, int*);
  1450.     break;
  1451.     
  1452.       case ufmt_char:
  1453.     args[cur_arg].ptrValue = va_arg(ap, int*);
  1454.     break;
  1455.     
  1456.       case ufmt_wchar:
  1457.     args[cur_arg].ptrValue = va_arg(ap, wchar_t*);
  1458.     break;
  1459.     
  1460.       case ufmt_string:
  1461.     args[cur_arg].ptrValue = va_arg(ap, char*);
  1462.     break;
  1463.     
  1464.       case ufmt_wstring:
  1465.     args[cur_arg].ptrValue = va_arg(ap, wchar_t*);
  1466.     break;
  1467.     
  1468.       case ufmt_pointer:
  1469.     args[cur_arg].ptrValue = va_arg(ap, void*);
  1470.     break;
  1471.     
  1472.       case ufmt_float:
  1473.     args[cur_arg].ptrValue = va_arg(ap, float*);
  1474.     break;
  1475.     
  1476.       case ufmt_double:
  1477.     args[cur_arg].ptrValue = va_arg(ap, double*);
  1478.     break;
  1479.  
  1480.       case ufmt_date:
  1481.     args[cur_arg].ptrValue = va_arg(ap, UDate*);
  1482.     break;
  1483.  
  1484.       case ufmt_ustring:
  1485.     args[cur_arg].ptrValue = va_arg(ap, UChar*);
  1486.     break;
  1487.  
  1488.       case ufmt_uchar:
  1489.     args[cur_arg].ptrValue = va_arg(ap, int*);
  1490.     break;
  1491.       }
  1492.     }
  1493.     
  1494.     /* call the handler function */
  1495.     handler = g_u_scanf_handlers[ (unsigned char) spec.fInfo.fSpec ];
  1496.     if(handler != 0) {
  1497.  
  1498.       /* reset count */
  1499.       count = 0;
  1500.  
  1501.       temp = (*handler)(f, &spec.fInfo, args, alias, &count);
  1502.  
  1503.       /* if the handler encountered an error condition, break */
  1504.       if(temp == -1)
  1505.     break;
  1506.  
  1507.       /* add to the # of items converted */
  1508.       converted += temp;
  1509.  
  1510.       /* update the pointer in pattern */
  1511.       alias += count;
  1512.     }
  1513.  
  1514.     /* just ignore unknown tags */
  1515.  
  1516.   }
  1517.  
  1518.   /* return # of items converted */
  1519.   return converted;
  1520. }
  1521.  
  1522.