Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

uprintf.c

00001 /*
00002 *******************************************************************************
00003 *
00004 *   Copyright (C) 1998-1999, International Business Machines
00005 *   Corporation and others.  All Rights Reserved.
00006 *
00007 *******************************************************************************
00008 *
00009 * File uprintf.c
00010 *
00011 * Modification History:
00012 *
00013 *   Date        Name        Description
00014 *   11/19/98    stephen        Creation.
00015 *   03/12/99    stephen     Modified for new C API.
00016 *                           Added conversion from default codepage.
00017 *******************************************************************************
00018 */
00019 
00020 #include "unicode/utypes.h"
00021 #include "uprintf.h"
00022 #include "uprntf_p.h"
00023 #include "unicode/ustdio.h"
00024 #include "ufile.h"
00025 #include "unicode/ustring.h"
00026 #include "locbund.h"
00027 #include "umutex.h"
00028 #include "unicode/unum.h"
00029 #include "unicode/udat.h"
00030 
00031 #include <string.h>
00032 #include <stdlib.h>
00033 #include <math.h>
00034 #include <float.h>
00035 #include <limits.h>
00036 
00037 static u_printf_handler     g_u_printf_handlers     [256];
00038 static u_printf_info       g_u_printf_infos     [256];
00039 static UBool            g_u_printf_inited    = FALSE;
00040 
00041 /* buffer size for formatting */
00042 #define UFPRINTF_BUFFER_SIZE 1024
00043 
00044 int32_t 
00045 u_fprintf(    UFILE        *f,
00046         const char    *patternSpecification,
00047         ... )
00048 {
00049   va_list ap;
00050   int32_t count;
00051   
00052   va_start(ap, patternSpecification);
00053   count = u_vfprintf(f, patternSpecification, ap);
00054   va_end(ap);
00055   
00056   return count;
00057 }
00058 
00059 int32_t 
00060 u_fprintf_u(    UFILE        *f,
00061         const UChar    *patternSpecification,
00062         ... )
00063 {
00064   va_list ap;
00065   int32_t count;
00066   
00067   va_start(ap, patternSpecification);
00068   count = u_vfprintf_u(f, patternSpecification, ap);
00069   va_end(ap);
00070   
00071   return count;
00072 }
00073 
00074 int32_t 
00075 u_vfprintf(    UFILE        *f,
00076         const char    *patternSpecification,
00077         va_list        ap)
00078 {
00079   int32_t count;
00080   UChar *pattern;
00081   
00082   /* convert from the default codepage to Unicode */
00083   pattern = ufmt_defaultCPToUnicode(patternSpecification, 
00084                     strlen(patternSpecification));
00085   if(pattern == 0) {
00086     return 0;
00087   }
00088   
00089   /* do the work */
00090   count = u_vfprintf_u(f, pattern, ap);
00091 
00092   /* clean up */
00093   free(pattern);
00094   
00095   return count;
00096 }
00097 
00098 int32_t
00099 u_printf_register_handler(UChar            spec, 
00100               u_printf_info     info,
00101               u_printf_handler     handler)
00102 {
00103   /* lock the cache */
00104   umtx_lock(0);
00105 
00106   /* add to our list of function pointers */
00107   g_u_printf_infos[ (unsigned char) spec ]     = info;
00108   g_u_printf_handlers[ (unsigned char) spec ]     = handler;
00109 
00110   /* unlock the cache */
00111   umtx_unlock(0);
00112   return 0;
00113 }
00114 
00115 /* handle a '%' */
00116 
00117 int32_t 
00118 u_printf_simple_percent_info(const u_printf_spec_info     *info,
00119                  int32_t             *argtypes,
00120                  int32_t             n)
00121 {
00122   /* we don't need any arguments */
00123   return 0;
00124 }
00125 
00126 int32_t
00127 u_printf_simple_percent_handler(UFILE                 *stream,
00128                 const u_printf_spec_info     *info,
00129                 const ufmt_args            *args)
00130 {
00131   /* put a single '%' on the stream */
00132   u_fputc(0x0025, stream);
00133   /* we wrote one character */
00134   return 1;
00135 }
00136 
00137 /* handle 's' */
00138 
00139 int32_t 
00140 u_printf_string_info(const u_printf_spec_info     *info,
00141              int32_t             *argtypes,
00142              int32_t             n)
00143 {
00144   /* handle error */
00145   if(n < 1)
00146     return 0;
00147 
00148   /* we need 1 argument of type string */
00149   argtypes[0] = ufmt_string;
00150   return 1;
00151 }
00152 
00153 int32_t
00154 u_printf_string_handler(UFILE                 *stream,
00155             const u_printf_spec_info     *info,
00156             const ufmt_args            *args)
00157 {
00158   UChar *s;
00159   int32_t len, written, i;
00160   const char *arg = (const char*)(args[0].ptrValue);
00161 
00162   /* convert from the default codepage to Unicode */
00163   s = ufmt_defaultCPToUnicode(arg, strlen(arg));
00164   if(s == 0) {
00165     return 0;
00166   }
00167   len = u_strlen(s);
00168   
00169   /* width = minimum # of characters to write */
00170   /* precision = maximum # of characters to write */
00171 
00172   /* precision takes precedence over width */
00173   /* determine if the string should be truncated */
00174   if(info->fPrecision != -1 && len > info->fPrecision) {
00175     written = u_file_write(s, info->fPrecision, stream);
00176   }
00177   
00178   /* determine if the string should be padded */
00179   else if(info->fWidth != -1 && len < info->fWidth) {
00180     /* left justify */
00181     if(info->fLeft) {
00182       written = u_file_write(s, len, stream);
00183       for(i = 0; i < info->fWidth - len; ++i)
00184     written += u_file_write(&info->fPadChar, 1, stream);
00185     }
00186     /* right justify */
00187     else {
00188       written = 0;
00189       for(i = 0; i < info->fWidth - len; ++i)
00190     written += u_file_write(&info->fPadChar, 1, stream);
00191       written += u_file_write(s, len, stream);
00192     }
00193   }
00194 
00195   /* just write the string */
00196   else 
00197     written = u_file_write(s, len, stream);
00198 
00199   /* clean up */
00200   free(s);
00201   
00202   return written;
00203 }
00204 
00205 int32_t 
00206 u_printf_integer_info(const u_printf_spec_info     *info,
00207               int32_t             *argtypes,
00208               int32_t             n)
00209 {
00210   /* handle error */
00211   if(n < 1)
00212     return 0;
00213 
00214   /* we need 1 argument of type int */
00215   argtypes[0] = ufmt_int;
00216   return 1;
00217 }
00218 /* HSYS */
00219 int32_t
00220 u_printf_integer_handler(UFILE                 *stream,
00221              const u_printf_spec_info     *info,
00222              const ufmt_args            *args)
00223 {
00224   int32_t         written     = 0;
00225   int32_t         len;
00226   long            num         = (long) (args[0].intValue);
00227   UNumberFormat        *format;
00228   UChar            result        [UFPRINTF_BUFFER_SIZE];
00229   int32_t        i, minDigits     = -1;
00230   UErrorCode        status        = U_ZERO_ERROR;
00231 
00232 
00233   /* mask off any necessary bits */
00234   if(info->fIsShort)
00235     num &= SHRT_MAX;
00236   else if(! info->fIsLong || ! info->fIsLongLong)
00237     num &= INT_MAX;
00238 
00239   /* get the formatter */
00240   format = u_locbund_getNumberFormat(stream->fBundle);
00241 
00242   /* handle error */
00243   if(format == 0)
00244     return 0;
00245 
00246   /* set the appropriate flags on the formatter */
00247 
00248   /* set the minimum integer digits */
00249   if(info->fPrecision != -1) {
00250     /* clone the stream's bundle if it isn't owned */
00251     if(! stream->fOwnBundle) {
00252       stream->fBundle     = u_locbund_clone(stream->fBundle);
00253       stream->fOwnBundle = TRUE;
00254       format           = u_locbund_getNumberFormat(stream->fBundle);
00255     }
00256 
00257     /* set the minimum # of digits */
00258     minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
00259     unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
00260   }
00261 
00262   /* set whether to show the sign */
00263   if(info->fShowSign) {
00264     /* clone the stream's bundle if it isn't owned */
00265     if(! stream->fOwnBundle) {
00266       stream->fBundle     = u_locbund_clone(stream->fBundle);
00267       stream->fOwnBundle = TRUE;
00268       format           = u_locbund_getNumberFormat(stream->fBundle);
00269     }
00270 
00271     /* set whether to show the sign*/
00272     /* {sfb} TBD */
00273   }
00274 
00275   /* format the number */
00276   unum_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
00277   len = u_strlen(result);
00278   
00279   /* pad and justify, if needed */
00280   if(info->fWidth != -1 && len < info->fWidth) {
00281     /* left justify */
00282     if(info->fLeft) {
00283       written = u_file_write(result, len, stream);
00284       for(i = 0; i < info->fWidth - len; ++i)
00285     written += u_file_write(&info->fPadChar, 1, stream);
00286     }
00287     /* right justify */
00288     else {
00289       written = 0;
00290       for(i = 0; i < info->fWidth - len; ++i)
00291     written += u_file_write(&info->fPadChar, 1, stream);
00292       written += u_file_write(result, len, stream);
00293     }
00294   }
00295   /* just write the formatted output */
00296   else
00297     written = u_file_write(result, len, stream);
00298   
00299   /* restore the number format */
00300   if(minDigits != -1)
00301     unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
00302 
00303   return written;
00304 }
00305 
00306 int32_t 
00307 u_printf_hex_info(const u_printf_spec_info     *info,
00308           int32_t             *argtypes,
00309           int32_t             n)
00310 {
00311   /* handle error */
00312   if(n < 1)
00313     return 0;
00314 
00315   /* we need 1 argument of type int */
00316   argtypes[0] = ufmt_int;
00317   return 1;
00318 }
00319 
00320 int32_t
00321 u_printf_hex_handler(UFILE             *stream,
00322              const u_printf_spec_info     *info,
00323              const ufmt_args            *args)
00324 {
00325   int32_t         written     = 0;
00326   long            num         = (long) (args[0].intValue);
00327   int32_t        i;
00328   UChar            result         [UFPRINTF_BUFFER_SIZE];
00329   int32_t         len        = UFPRINTF_BUFFER_SIZE;
00330 
00331 
00332   /* mask off any necessary bits */
00333   if(info->fIsShort)
00334     num &= SHRT_MAX;
00335   else if(! info->fIsLong || ! info->fIsLongLong)
00336     num &= INT_MAX;
00337 
00338   /* format the number, preserving the minimum # of digits */
00339   ufmt_ltou(result, &len, num, 16,
00340         (UBool)(info->fSpec == 0x0078),
00341         (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
00342   
00343   /* convert to alt form, if desired */
00344   if(num != 0 && info->fAlt && len < UFPRINTF_BUFFER_SIZE - 2) {
00345     /* shift the formatted string right by 2 chars */
00346     memmove(result + 2, result, len * sizeof(UChar));
00347     result[0] = 0x0030;
00348     result[1] = info->fSpec;
00349     len += 2;
00350   }
00351 
00352   /* pad and justify, if needed */
00353   if(info->fWidth != -1 && len < info->fWidth) {
00354     /* left justify */
00355     if(info->fLeft) {
00356       written = u_file_write(result, len, stream);
00357       for(i = 0; i < info->fWidth - len; ++i)
00358     written += u_file_write(&info->fPadChar, 1, stream);
00359     }
00360     /* right justify */
00361     else {
00362       written = 0;
00363       for(i = 0; i < info->fWidth - len; ++i)
00364     written += u_file_write(&info->fPadChar, 1, stream);
00365       written += u_file_write(result, len, stream);
00366     }
00367   }
00368   /* just write the formatted output */
00369   else
00370     written = u_file_write(result, len, stream);
00371   
00372   return written;
00373 }
00374 
00375 int32_t 
00376 u_printf_octal_info(const u_printf_spec_info     *info,
00377             int32_t             *argtypes,
00378             int32_t             n)
00379 {
00380   /* handle error */
00381   if(n < 1)
00382     return 0;
00383 
00384   /* we need 1 argument of type int */
00385   argtypes[0] = ufmt_int;
00386   return 1;
00387 }
00388 
00389 int32_t
00390 u_printf_octal_handler(UFILE                 *stream,
00391                const u_printf_spec_info     *info,
00392                const ufmt_args            *args)
00393 {
00394   int32_t         written     = 0;
00395   long            num         = (long) (args[0].intValue);
00396   int32_t        i;
00397   UChar            result         [UFPRINTF_BUFFER_SIZE];
00398   int32_t         len        = UFPRINTF_BUFFER_SIZE;
00399 
00400 
00401   /* mask off any necessary bits */
00402   if(info->fIsShort)
00403     num &= SHRT_MAX;
00404   else if(! info->fIsLong || ! info->fIsLongLong)
00405     num &= INT_MAX;
00406 
00407   /* format the number, preserving the minimum # of digits */
00408   ufmt_ltou(result, &len, num, 8,
00409         FALSE, /* doesn't matter for octal */
00410         info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
00411 
00412   /* convert to alt form, if desired */
00413   if(info->fAlt && result[0] != 0x0030 && len < UFPRINTF_BUFFER_SIZE - 1) {
00414     /* shift the formatted string right by 1 char */
00415     memmove(result + 1, result, len * sizeof(UChar));
00416     result[0] = 0x0030;
00417     len += 1;
00418   }
00419 
00420   /* pad and justify, if needed */
00421   if(info->fWidth != -1 && len < info->fWidth) {
00422     /* left justify */
00423     if(info->fLeft) {
00424       written = u_file_write(result, len, stream);
00425       for(i = 0; i < info->fWidth - len; ++i)
00426     written += u_file_write(&info->fPadChar, 1, stream);
00427     }
00428     /* right justify */
00429     else {
00430       written = 0;
00431       for(i = 0; i < info->fWidth - len; ++i)
00432     written += u_file_write(&info->fPadChar, 1, stream);
00433       written += u_file_write(result, len, stream);
00434     }
00435   }
00436   /* just write the formatted output */
00437   else
00438     written = u_file_write(result, len, stream);
00439   
00440   return written;
00441 }
00442 
00443 
00444 int32_t 
00445 u_printf_double_info(const u_printf_spec_info     *info,
00446              int32_t             *argtypes,
00447              int32_t             n)
00448 {
00449   /* handle error */
00450   if(n < 1)
00451     return 0;
00452 
00453   /* we need 1 argument of type double */
00454   argtypes[0] = ufmt_double;
00455   return 1;
00456 }
00457 
00458 int32_t
00459 u_printf_double_handler(UFILE                 *stream,
00460             const u_printf_spec_info     *info,
00461             const ufmt_args            *args)
00462 {
00463   int32_t         written     = 0;
00464   int32_t         len;
00465   double        num         = (double) (args[0].doubleValue);
00466   UNumberFormat        *format;
00467   UChar            result        [UFPRINTF_BUFFER_SIZE];
00468   int32_t        i, minDecimalDigits;
00469   int32_t        maxDecimalDigits;
00470   UErrorCode        status        = U_ZERO_ERROR;
00471 
00472   /* mask off any necessary bits */
00473   /*  if(! info->fIsLongDouble)
00474       num &= DBL_MAX;*/
00475 
00476   /* get the formatter */
00477   format = u_locbund_getNumberFormat(stream->fBundle);
00478 
00479   /* handle error */
00480   if(format == 0)
00481     return 0;
00482 
00483   /* set the appropriate flags on the formatter */
00484 
00485   /* clone the stream's bundle if it isn't owned */
00486   if(! stream->fOwnBundle) {
00487     stream->fBundle     = u_locbund_clone(stream->fBundle);
00488     stream->fOwnBundle     = TRUE;
00489     format           = u_locbund_getNumberFormat(stream->fBundle);
00490   }
00491 
00492   /* set the number of decimal digits */
00493 
00494   /* save the formatter's state */
00495   minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
00496   maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
00497 
00498   if(info->fPrecision != -1) {
00499     /* set the # of decimal digits */
00500     unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
00501   }
00502   else if(info->fPrecision == 0 && ! info->fAlt) {
00503     /* no decimal point in this case */
00504     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
00505   }
00506   else if(info->fAlt) {
00507     /* '#' means always show decimal point */
00508     /* copy of printf behavior on Solaris - '#' shows 6 digits */
00509     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
00510   }
00511   else {
00512     /* # of decimal digits is 6 if precision not specified */
00513     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
00514   }
00515 
00516   /* set whether to show the sign */
00517   if(info->fShowSign) {
00518     /* set whether to show the sign*/
00519     /* {sfb} TBD */
00520   }
00521 
00522   /* format the number */
00523   unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
00524   len = u_strlen(result);
00525 
00526   /* pad and justify, if needed */
00527   if(info->fWidth != -1 && len < info->fWidth) {
00528     /* left justify */
00529     if(info->fLeft) {
00530       written = u_file_write(result, len, stream);
00531       for(i = 0; i < info->fWidth - len; ++i)
00532     written += u_file_write(&info->fPadChar, 1, stream);
00533     }
00534     /* right justify */
00535     else {
00536       written = 0;
00537       for(i = 0; i < info->fWidth - len; ++i)
00538     written += u_file_write(&info->fPadChar, 1, stream);
00539       written += u_file_write(result, len, stream);
00540     }
00541   }
00542   /* just write the formatted output */
00543   else
00544     written = u_file_write(result, len, stream);
00545   
00546   /* restore the number format */
00547   unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
00548   unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
00549 
00550   return written;
00551 }
00552 
00553 
00554 int32_t 
00555 u_printf_char_info(const u_printf_spec_info     *info,
00556            int32_t             *argtypes,
00557            int32_t             n)
00558 {
00559   /* handle error */
00560   if(n < 1)
00561     return 0;
00562 
00563   /* we need 1 argument of type char */
00564   argtypes[0] = ufmt_char;
00565   return 1;
00566 }
00567 
00568 int32_t
00569 u_printf_char_handler(UFILE                 *stream,
00570               const u_printf_spec_info         *info,
00571               const ufmt_args              *args)
00572 {
00573   UChar *s;
00574   int32_t len, written = 0, i;
00575   unsigned char arg = (unsigned char)(args[0].intValue);
00576 
00577   /* convert from default codepage to Unicode */
00578   s = ufmt_defaultCPToUnicode((const char *)&arg, 1);
00579   if(s == 0) {
00580     return 0;
00581   }
00582   len = u_strlen(s);
00583   
00584   /* width = minimum # of characters to write */
00585   /* precision = maximum # of characters to write */
00586 
00587   /* precision takes precedence over width */
00588   /* determine if the string should be truncated */
00589   if(info->fPrecision != -1 && len > info->fPrecision) {
00590     written = u_file_write(s, info->fPrecision, stream);
00591   }
00592   
00593   /* determine if the string should be padded */
00594   else if(info->fWidth != -1 && len < info->fWidth) {
00595     /* left justify */
00596     if(info->fLeft) {
00597       written = u_file_write(s, len, stream);
00598       for(i = 0; i < info->fWidth - len; ++i)
00599     written += u_file_write(&info->fPadChar, 1, stream);
00600     }
00601     /* right justify */
00602     else {
00603       written = 0;
00604       for(i = 0; i < info->fWidth - len; ++i)
00605     written += u_file_write(&info->fPadChar, 1, stream);
00606       written += u_file_write(s, len, stream);
00607     }
00608   }
00609 
00610   /* just write the string */
00611   else 
00612     written = u_file_write(s, len, stream);
00613 
00614   /* clean up */
00615   free(s);
00616 
00617   return written;
00618 }
00619 
00620 
00621 int32_t 
00622 u_printf_pointer_info(const u_printf_spec_info     *info,
00623               int32_t             *argtypes,
00624               int32_t             n)
00625 {
00626   /* handle error */
00627   if(n < 1)
00628     return 0;
00629 
00630   /* we need 1 argument of type void* */
00631   argtypes[0] = ufmt_pointer;
00632   return 1;
00633 }
00634 
00635 int32_t
00636 u_printf_pointer_handler(UFILE                 *stream,
00637              const u_printf_spec_info     *info,
00638              const ufmt_args            *args)
00639 {
00640   int32_t         written     = 0;
00641   long            num         = (long) (args[0].intValue);
00642   int32_t        i;
00643   UChar            result         [UFPRINTF_BUFFER_SIZE];
00644   int32_t         len        = UFPRINTF_BUFFER_SIZE;
00645 
00646 
00647   /* format the pointer in hex */
00648   ufmt_ltou(result, &len, num, 16, TRUE, info->fPrecision);
00649 
00650   /* pad and justify, if needed */
00651   if(info->fWidth != -1 && len < info->fWidth) {
00652     /* left justify */
00653     if(info->fLeft) {
00654       written = u_file_write(result, len, stream);
00655       for(i = 0; i < info->fWidth - len; ++i)
00656     written += u_file_write(&info->fPadChar, 1, stream);
00657     }
00658     /* right justify */
00659     else {
00660       written = 0;
00661       for(i = 0; i < info->fWidth - len; ++i)
00662     written += u_file_write(&info->fPadChar, 1, stream);
00663       written += u_file_write(result, len, stream);
00664     }
00665   }
00666   /* just write the formatted output */
00667   else
00668     written = u_file_write(result, len, stream);
00669   
00670   return written;
00671 }
00672 
00673 
00674 int32_t 
00675 u_printf_scientific_info(const u_printf_spec_info     *info,
00676              int32_t             *argtypes,
00677              int32_t             n)
00678 {
00679   /* handle error */
00680   if(n < 1)
00681     return 0;
00682   
00683   /* we need 1 argument of type double */
00684   argtypes[0] = ufmt_double;
00685   return 1;
00686 }
00687 
00688 int32_t
00689 u_printf_scientific_handler(UFILE             *stream,
00690                 const u_printf_spec_info     *info,
00691                 const ufmt_args            *args)
00692 {
00693   int32_t         written     = 0;
00694   int32_t         len;
00695   double        num         = (double) (args[0].doubleValue);
00696   UNumberFormat        *format;
00697   UChar            result        [UFPRINTF_BUFFER_SIZE];
00698   int32_t        i, minDecimalDigits;
00699   int32_t        maxDecimalDigits;
00700   UErrorCode        status        = U_ZERO_ERROR;
00701   
00702 
00703   /* mask off any necessary bits */
00704   /*  if(! info->fIsLongDouble)
00705       num &= DBL_MAX;*/
00706 
00707   /* get the formatter */
00708   format = u_locbund_getScientificFormat(stream->fBundle);
00709 
00710   /* handle error */
00711   if(format == 0)
00712     return 0;
00713 
00714   /* set the appropriate flags on the formatter */
00715 
00716   /* clone the stream's bundle if it isn't owned */
00717   if(! stream->fOwnBundle) {
00718     stream->fBundle     = u_locbund_clone(stream->fBundle);
00719     stream->fOwnBundle     = TRUE;
00720     format           = u_locbund_getScientificFormat(stream->fBundle);
00721   }
00722 
00723   /* set the number of decimal digits */
00724 
00725   /* save the formatter's state */
00726   minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
00727   maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
00728 
00729   if(info->fPrecision != -1) {
00730     /* set the # of decimal digits */
00731     unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
00732   }
00733   else if(info->fPrecision == 0 && ! info->fAlt) {
00734     /* no decimal point in this case */
00735     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
00736   }
00737   else if(info->fAlt) {
00738     /* '#' means always show decimal point */
00739     /* copy of printf behavior on Solaris - '#' shows 6 digits */
00740     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
00741   }
00742   else {
00743     /* # of decimal digits is 6 if precision not specified */
00744     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
00745   }
00746 
00747   /* set whether to show the sign */
00748   if(info->fShowSign) {
00749     /* set whether to show the sign*/
00750     /* {sfb} TBD */
00751   }
00752 
00753   /* format the number */
00754   unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
00755   len = u_strlen(result);
00756 
00757   /* pad and justify, if needed */
00758   if(info->fWidth != -1 && len < info->fWidth) {
00759     /* left justify */
00760     if(info->fLeft) {
00761       written = u_file_write(result, len, stream);
00762       for(i = 0; i < info->fWidth - len; ++i)
00763     written += u_file_write(&info->fPadChar, 1, stream);
00764     }
00765     /* right justify */
00766     else {
00767       written = 0;
00768       for(i = 0; i < info->fWidth - len; ++i)
00769     written += u_file_write(&info->fPadChar, 1, stream);
00770       written += u_file_write(result, len, stream);
00771     }
00772   }
00773   /* just write the formatted output */
00774   else
00775     written = u_file_write(result, len, stream);
00776   
00777   /* restore the number format */
00778   unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
00779   unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
00780 
00781   return written;
00782 }
00783 
00784 int32_t 
00785 u_printf_date_info(const u_printf_spec_info     *info,
00786            int32_t             *argtypes,
00787            int32_t             n)
00788 {
00789   /* handle error */
00790   if(n < 1)
00791     return 0;
00792   
00793   /* we need 1 argument of type Date */
00794   argtypes[0] = ufmt_date;
00795   return 1;
00796 }
00797 
00798 int32_t
00799 u_printf_date_handler(UFILE             *stream,
00800               const u_printf_spec_info     *info,
00801               const ufmt_args         *args)
00802 {
00803   int32_t         written     = 0;
00804   int32_t         len;
00805   UDate            num         = (UDate) (args[0].dateValue);
00806   UDateFormat        *format;
00807   UChar            result        [UFPRINTF_BUFFER_SIZE];
00808   int32_t        i;
00809   UErrorCode        status        = U_ZERO_ERROR;
00810 
00811 
00812   /* get the formatter */
00813   format = u_locbund_getDateFormat(stream->fBundle);
00814   
00815   /* handle error */
00816   if(format == 0)
00817     return 0;
00818 
00819   /* format the date */
00820   udat_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
00821   len = u_strlen(result);
00822 
00823   /* pad and justify, if needed */
00824   if(info->fWidth != -1 && len < info->fWidth) {
00825     /* left justify */
00826     if(info->fLeft) {
00827       written = u_file_write(result, len, stream);
00828       for(i = 0; i < info->fWidth - len; ++i)
00829     written += u_file_write(&info->fPadChar, 1, stream);
00830     }
00831     /* right justify */
00832     else {
00833       written = 0;
00834       for(i = 0; i < info->fWidth - len; ++i)
00835     written += u_file_write(&info->fPadChar, 1, stream);
00836       written += u_file_write(result, len, stream);
00837     }
00838   }
00839   /* just write the formatted output */
00840   else
00841     written = u_file_write(result, len, stream);
00842   
00843   return written;
00844 }
00845 
00846 int32_t 
00847 u_printf_time_info(const u_printf_spec_info     *info,
00848            int32_t             *argtypes,
00849            int32_t             n)
00850 {
00851   /* handle error */
00852   if(n < 1)
00853     return 0;
00854   
00855   /* we need 1 argument of type date */
00856   argtypes[0] = ufmt_date;
00857   return 1;
00858 }
00859 
00860 int32_t
00861 u_printf_time_handler(UFILE             *stream,
00862               const u_printf_spec_info     *info,
00863               const ufmt_args         *args)
00864 {
00865   int32_t         written     = 0;
00866   int32_t         len;
00867   UDate            num         = (UDate) (args[0].dateValue);
00868   UDateFormat        *format;
00869   UChar            result        [UFPRINTF_BUFFER_SIZE];
00870   int32_t        i;
00871   UErrorCode        status        = U_ZERO_ERROR;
00872 
00873 
00874   /* get the formatter */
00875   format = u_locbund_getTimeFormat(stream->fBundle);
00876   
00877   /* handle error */
00878   if(format == 0)
00879     return 0;
00880 
00881   /* format the time */
00882   udat_format(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
00883   len = u_strlen(result);
00884 
00885   /* pad and justify, if needed */
00886   if(info->fWidth != -1 && len < info->fWidth) {
00887     /* left justify */
00888     if(info->fLeft) {
00889       written = u_file_write(result, len, stream);
00890       for(i = 0; i < info->fWidth - len; ++i)
00891     written += u_file_write(&info->fPadChar, 1, stream);
00892     }
00893     /* right justify */
00894     else {
00895       written = 0;
00896       for(i = 0; i < info->fWidth - len; ++i)
00897     written += u_file_write(&info->fPadChar, 1, stream);
00898       written += u_file_write(result, len, stream);
00899     }
00900   }
00901   /* just write the formatted output */
00902   else
00903     written = u_file_write(result, len, stream);
00904   
00905   return written;
00906 }
00907 
00908 
00909 int32_t 
00910 u_printf_percent_info(const u_printf_spec_info     *info,
00911               int32_t             *argtypes,
00912               int32_t             n)
00913 {
00914   /* handle error */
00915   if(n < 1)
00916     return 0;
00917 
00918   /* we need 1 argument of type double */
00919   argtypes[0] = ufmt_double;
00920   return 1;
00921 }
00922 
00923 int32_t
00924 u_printf_percent_handler(UFILE                 *stream,
00925              const u_printf_spec_info     *info,
00926              const ufmt_args            *args)
00927 {
00928   int32_t         written     = 0;
00929   int32_t         len;
00930   double        num         = (double) (args[0].doubleValue);
00931   UNumberFormat        *format;
00932   UChar            result        [UFPRINTF_BUFFER_SIZE];
00933   int32_t        i, minDecimalDigits;
00934   int32_t        maxDecimalDigits;
00935   UErrorCode        status        = U_ZERO_ERROR;
00936 
00937 
00938   /* mask off any necessary bits */
00939   /*  if(! info->fIsLongDouble)
00940       num &= DBL_MAX;*/
00941 
00942   /* get the formatter */
00943   format = u_locbund_getPercentFormat(stream->fBundle);
00944 
00945   /* handle error */
00946   if(format == 0)
00947     return 0;
00948 
00949   /* set the appropriate flags on the formatter */
00950 
00951   /* clone the stream's bundle if it isn't owned */
00952   if(! stream->fOwnBundle) {
00953     stream->fBundle     = u_locbund_clone(stream->fBundle);
00954     stream->fOwnBundle     = TRUE;
00955     format           = u_locbund_getPercentFormat(stream->fBundle);
00956   }
00957 
00958   /* set the number of decimal digits */
00959 
00960   /* save the formatter's state */
00961   minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
00962   maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
00963 
00964   if(info->fPrecision != -1) {
00965     /* set the # of decimal digits */
00966     unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
00967   }
00968   else if(info->fPrecision == 0 && ! info->fAlt) {
00969     /* no decimal point in this case */
00970     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
00971   }
00972   else if(info->fAlt) {
00973     /* '#' means always show decimal point */
00974     /* copy of printf behavior on Solaris - '#' shows 6 digits */
00975     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
00976   }
00977   else {
00978     /* # of decimal digits is 6 if precision not specified */
00979     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
00980   }
00981 
00982   /* set whether to show the sign */
00983   if(info->fShowSign) {
00984     /* set whether to show the sign*/
00985     /* {sfb} TBD */
00986   }
00987 
00988   /* format the number */
00989   unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
00990   len = u_strlen(result);
00991 
00992   /* pad and justify, if needed */
00993   if(info->fWidth != -1 && len < info->fWidth) {
00994     /* left justify */
00995     if(info->fLeft) {
00996       written = u_file_write(result, len, stream);
00997       for(i = 0; i < info->fWidth - len; ++i)
00998     written += u_file_write(&info->fPadChar, 1, stream);
00999     }
01000     /* right justify */
01001     else {
01002       written = 0;
01003       for(i = 0; i < info->fWidth - len; ++i)
01004     written += u_file_write(&info->fPadChar, 1, stream);
01005       written += u_file_write(result, len, stream);
01006     }
01007   }
01008   /* just write the formatted output */
01009   else
01010     written = u_file_write(result, len, stream);
01011   
01012   /* restore the number format */
01013   unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
01014   unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
01015 
01016   return written;
01017 }
01018 
01019 
01020 int32_t 
01021 u_printf_currency_info(const u_printf_spec_info     *info,
01022                int32_t                 *argtypes,
01023                int32_t                 n)
01024 {
01025   /* handle error */
01026   if(n < 1)
01027     return 0;
01028 
01029   /* we need 1 argument of type double */
01030   argtypes[0] = ufmt_double;
01031   return 1;
01032 }
01033 
01034 int32_t
01035 u_printf_currency_handler(UFILE             *stream,
01036               const u_printf_spec_info     *info,
01037               const ufmt_args            *args)
01038 {
01039   int32_t         written     = 0;
01040   int32_t         len;
01041   double        num         = (double) (args[0].doubleValue);
01042   UNumberFormat        *format;
01043   UChar            result        [UFPRINTF_BUFFER_SIZE];
01044   int32_t        i, minDecimalDigits;
01045   int32_t        maxDecimalDigits;
01046   UErrorCode        status        = U_ZERO_ERROR;
01047 
01048 
01049   /* mask off any necessary bits */
01050   /*  if(! info->fIsLongDouble)
01051       num &= DBL_MAX;*/
01052 
01053   /* get the formatter */
01054   format = u_locbund_getCurrencyFormat(stream->fBundle);
01055 
01056   /* handle error */
01057   if(format == 0)
01058     return 0;
01059 
01060   /* set the appropriate flags on the formatter */
01061 
01062   /* clone the stream's bundle if it isn't owned */
01063   if(! stream->fOwnBundle) {
01064     stream->fBundle     = u_locbund_clone(stream->fBundle);
01065     stream->fOwnBundle     = TRUE;
01066     format           = u_locbund_getCurrencyFormat(stream->fBundle);
01067   }
01068 
01069   /* set the number of decimal digits */
01070 
01071   /* save the formatter's state */
01072   minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
01073   maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
01074 
01075   if(info->fPrecision != -1) {
01076     /* set the # of decimal digits */
01077     unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
01078   }
01079   else if(info->fPrecision == 0 && ! info->fAlt) {
01080     /* no decimal point in this case */
01081     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
01082   }
01083   else if(info->fAlt) {
01084     /* '#' means always show decimal point */
01085     /* copy of printf behavior on Solaris - '#' shows 6 digits */
01086     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
01087   }
01088   else {
01089     /* # of decimal digits is 6 if precision not specified */
01090     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
01091   }
01092 
01093   /* set whether to show the sign */
01094   if(info->fShowSign) {
01095     /* set whether to show the sign*/
01096     /* {sfb} TBD */
01097   }
01098 
01099   /* format the number */
01100   unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
01101   len = u_strlen(result);
01102 
01103   /* pad and justify, if needed */
01104   if(info->fWidth != -1 && len < info->fWidth) {
01105     /* left justify */
01106     if(info->fLeft) {
01107       written = u_file_write(result, len, stream);
01108       for(i = 0; i < info->fWidth - len; ++i)
01109     written += u_file_write(&info->fPadChar, 1, stream);
01110     }
01111     /* right justify */
01112     else {
01113       written = 0;
01114       for(i = 0; i < info->fWidth - len; ++i)
01115     written += u_file_write(&info->fPadChar, 1, stream);
01116       written += u_file_write(result, len, stream);
01117     }
01118   }
01119   /* just write the formatted output */
01120   else
01121     written = u_file_write(result, len, stream);
01122   
01123   /* restore the number format */
01124   unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
01125   unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
01126 
01127   return written;
01128 }
01129 
01130 int32_t 
01131 u_printf_ustring_info(const u_printf_spec_info     *info,
01132               int32_t             *argtypes,
01133               int32_t             n)
01134 {
01135   /* handle error */
01136   if(n < 1)
01137     return 0;
01138 
01139   /* we need 1 argument of type ustring */
01140   argtypes[0] = ufmt_ustring;
01141   return 1;
01142 }
01143 
01144 int32_t
01145 u_printf_ustring_handler(UFILE                 *stream,
01146              const u_printf_spec_info     *info,
01147              const ufmt_args         *args)
01148 {
01149   int32_t len, written, i;
01150   const UChar *arg = (const UChar*)(args[0].ptrValue);
01151 
01152   /* allocate enough space for the buffer */
01153   len = u_strlen(arg);
01154 
01155   /* width = minimum # of characters to write */
01156   /* precision = maximum # of characters to write */
01157 
01158   /* precision takes precedence over width */
01159   /* determine if the string should be truncated */
01160   if(info->fPrecision != -1 && len > info->fPrecision) {
01161     written = u_file_write(arg, info->fPrecision, stream);
01162   }
01163   
01164   /* determine if the string should be padded */
01165   else if(info->fWidth != -1 && len < info->fWidth) {
01166     /* left justify */
01167     if(info->fLeft) {
01168       written = u_file_write(arg, len, stream);
01169       for(i = 0; i < info->fWidth - len; ++i)
01170     written += u_file_write(&info->fPadChar, 1, stream);
01171     }
01172     /* right justify */
01173     else {
01174       written = 0;
01175       for(i = 0; i < info->fWidth - len; ++i)
01176     written += u_file_write(&info->fPadChar, 1, stream);
01177       written += u_file_write(arg, len, stream);
01178     }
01179   }
01180 
01181   /* just write the string */
01182   else 
01183     written = u_file_write(arg, len, stream);
01184 
01185   return written;
01186 }
01187 
01188 
01189 
01190 int32_t 
01191 u_printf_uchar_info(const u_printf_spec_info     *info,
01192             int32_t             *argtypes,
01193             int32_t             n)
01194 {
01195   /* handle error */
01196   if(n < 1)
01197     return 0;
01198 
01199   /* we need 1 argument of type uchar */
01200   argtypes[0] = ufmt_uchar;
01201   return 1;
01202 }
01203 
01204 int32_t
01205 u_printf_uchar_handler(UFILE                 *stream,
01206                const u_printf_spec_info     *info,
01207                const ufmt_args            *args)
01208 {
01209   int32_t written = 0, i;
01210   UChar arg = (UChar)(args[0].intValue);
01211   
01212 
01213   /* width = minimum # of characters to write */
01214   /* precision = maximum # of characters to write */
01215 
01216   /* precision takes precedence over width */
01217   /* determine if the char should be printed */
01218   if(info->fPrecision != -1 && info->fPrecision < 1) {
01219     /* write nothing */
01220     written = 0;
01221   }
01222   
01223   /* determine if the character should be padded */
01224   else if(info->fWidth != -1 && info->fWidth > 1) {
01225     /* left justify */
01226     if(info->fLeft) {
01227       written = u_file_write(&arg, 1, stream);
01228       for(i = 0; i < info->fWidth - 1; ++i)
01229     written += u_file_write(&info->fPadChar, 1, stream);
01230     }
01231     /* right justify */
01232     else {
01233       written = 0;
01234       for(i = 0; i < info->fWidth - 1; ++i)
01235     written += u_file_write(&info->fPadChar, 1, stream);
01236       written += u_file_write(&arg, 1, stream);
01237     }
01238   }
01239 
01240   /* just write the character */
01241   else 
01242     written = u_file_write(&arg, 1, stream);
01243 
01244   return written;
01245 }
01246 
01247 int32_t 
01248 u_printf_scidbl_info(const u_printf_spec_info     *info,
01249              int32_t             *argtypes,
01250              int32_t             n)
01251 {
01252   /* handle error */
01253   if(n < 1)
01254     return 0;
01255 
01256   /* we need 1 argument of type double */
01257   argtypes[0] = ufmt_double;
01258   return 1;
01259 }
01260 
01261 int32_t
01262 u_printf_scidbl_handler(UFILE                 *stream,
01263             const u_printf_spec_info     *info,
01264             const ufmt_args            *args)
01265 {
01266   double     num = (double)(args[0].doubleValue);
01267   UBool     useE;
01268 
01269   /* a precision of 0 is taken as 1 */
01270   if(info->fPrecision == 0)
01271     ((u_printf_spec_info*)info)->fPrecision = 1;
01272 
01273   /* determine whether to use 'e' or 'f' */
01274   useE = (UBool)(num < 0.0001
01275        || (info->fPrecision != -1 && num > pow(10.0, info->fPrecision)));
01276   
01277   /* use 'e' */
01278   if(useE) {
01279     /* adjust the specifier */
01280     ((u_printf_spec_info*)info)->fSpec = 0x0065;
01281     /* call the scientific handler */
01282     return u_printf_scientific_handler(stream, info, args);
01283   }
01284   /* use 'f' */
01285   else {
01286     /* adjust the specifier */
01287     ((u_printf_spec_info*)info)->fSpec = 0x0066;
01288     /* call the double handler */
01289     return u_printf_double_handler(stream, info, args);
01290   }
01291 }
01292 
01293 
01294 int32_t 
01295 u_printf_count_info(const u_printf_spec_info     *info,
01296             int32_t             *argtypes,
01297             int32_t             n)
01298 {
01299   /* handle error */
01300   if(n < 1)
01301     return 0;
01302 
01303   /* we need 1 argument of type count */
01304   argtypes[0] = ufmt_count;
01305   return 1;
01306 }
01307 
01308 int32_t
01309 u_printf_count_handler(UFILE                 *stream,
01310                const u_printf_spec_info     *info,
01311                const ufmt_args            *args)
01312 {
01313   int *count = (int*)(args[0].ptrValue);
01314 
01315   /* in the special case of count, the u_printf_spec_info's width */
01316   /* will contain the # of chars written thus far */
01317   *count = info->fWidth;
01318 
01319   return 0;
01320 }
01321 
01322 
01323 int32_t 
01324 u_printf_spellout_info(const u_printf_spec_info *info,
01325                int32_t             *argtypes,
01326                int32_t             n)
01327 {
01328   /* handle error */
01329   if(n < 1)
01330     return 0;
01331 
01332   /* we need 1 argument of type double */
01333   argtypes[0] = ufmt_double;
01334   return 1;
01335 }
01336 
01337 int32_t
01338 u_printf_spellout_handler(UFILE             *stream,
01339               const u_printf_spec_info     *info,
01340               const ufmt_args            *args)
01341 {
01342   int32_t         written     = 0;
01343   int32_t         len;
01344   double        num         = (double) (args[0].doubleValue);
01345   UNumberFormat        *format;
01346   UChar            result        [UFPRINTF_BUFFER_SIZE];
01347   int32_t        i, minDecimalDigits;
01348   int32_t        maxDecimalDigits;
01349   UErrorCode        status        = U_ZERO_ERROR;
01350 
01351 
01352   /* mask off any necessary bits */
01353   /*  if(! info->fIsLongDouble)
01354       num &= DBL_MAX;*/
01355 
01356   /* get the formatter */
01357   format = u_locbund_getSpelloutFormat(stream->fBundle);
01358 
01359   /* handle error */
01360   if(format == 0)
01361     return 0;
01362 
01363   /* set the appropriate flags on the formatter */
01364 
01365   /* clone the stream's bundle if it isn't owned */
01366   if(! stream->fOwnBundle) {
01367     stream->fBundle     = u_locbund_clone(stream->fBundle);
01368     stream->fOwnBundle     = TRUE;
01369     format           = u_locbund_getSpelloutFormat(stream->fBundle);
01370   }
01371 
01372   /* set the number of decimal digits */
01373 
01374   /* save the formatter's state */
01375   minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
01376   maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
01377 
01378   if(info->fPrecision != -1) {
01379     /* set the # of decimal digits */
01380     unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
01381   }
01382   else if(info->fPrecision == 0 && ! info->fAlt) {
01383     /* no decimal point in this case */
01384     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 0);
01385   }
01386   else if(info->fAlt) {
01387     /* '#' means always show decimal point */
01388     /* copy of printf behavior on Solaris - '#' shows 6 digits */
01389     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
01390   }
01391   else {
01392     /* # of decimal digits is 6 if precision not specified */
01393     unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
01394   }
01395 
01396   /* set whether to show the sign */
01397   if(info->fShowSign) {
01398     /* set whether to show the sign*/
01399     /* {sfb} TBD */
01400   }
01401 
01402   /* format the number */
01403   unum_formatDouble(format, num, result, UFPRINTF_BUFFER_SIZE, 0, &status);
01404   len = u_strlen(result);
01405 
01406   /* pad and justify, if needed */
01407   if(info->fWidth != -1 && len < info->fWidth) {
01408     /* left justify */
01409     if(info->fLeft) {
01410       written = u_file_write(result, len, stream);
01411       for(i = 0; i < info->fWidth - len; ++i)
01412     written += u_file_write(&info->fPadChar, 1, stream);
01413     }
01414     /* right justify */
01415     else {
01416       written = 0;
01417       for(i = 0; i < info->fWidth - len; ++i)
01418     written += u_file_write(&info->fPadChar, 1, stream);
01419       written += u_file_write(result, len, stream);
01420     }
01421   }
01422   /* just write the formatted output */
01423   else
01424     written = u_file_write(result, len, stream);
01425   
01426   /* restore the number format */
01427   unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
01428   unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
01429 
01430   return written;
01431 }
01432 
01433 void
01434 u_printf_init(void)
01435 {
01436   int32_t i;
01437   /*Mutex *lock;*/
01438 
01439   /* if we're already inited, do nothing */
01440   if(g_u_printf_inited)
01441     return;
01442 
01443   /* lock the cache */
01444   umtx_lock(0);
01445 
01446   /* if we're already inited, do nothing */
01447   if(g_u_printf_inited) {
01448     umtx_unlock(0);
01449     return;
01450   }
01451 
01452   /* initialize all handlers and infos to 0 */
01453   for(i = 0; i < 256; ++i) {
01454     g_u_printf_infos[i]         = 0;
01455     g_u_printf_handlers[i]     = 0;
01456   }
01457 
01458   /* register the handlers for standard specifiers */
01459   /* don't use u_printf_register_handler to avoid mutex creation */
01460 
01461   /* handle '%' */
01462   g_u_printf_infos[ 0x0025 ]     = u_printf_simple_percent_info;
01463   g_u_printf_handlers[ 0x0025 ] = u_printf_simple_percent_handler;
01464 
01465   /* handle 's' */
01466   g_u_printf_infos[ 0x0073 ]     = u_printf_string_info;
01467   g_u_printf_handlers[ 0x0073 ] = u_printf_string_handler;
01468 
01469   /* handle 'd' */
01470   g_u_printf_infos[ 0x0064 ]     = u_printf_integer_info;
01471   g_u_printf_handlers[ 0x0064 ] = u_printf_integer_handler;
01472 
01473   /* handle 'i' */
01474   g_u_printf_infos[ 0x0069 ]     = u_printf_integer_info;
01475   g_u_printf_handlers[ 0x0069 ] = u_printf_integer_handler;
01476 
01477   /* handle 'o' */
01478   g_u_printf_infos[ 0x006F ]     = u_printf_octal_info;
01479   g_u_printf_handlers[ 0x006F ] = u_printf_octal_handler;
01480 
01481   /* handle 'u' */
01482   g_u_printf_infos[ 0x0075 ]     = u_printf_integer_info;
01483   g_u_printf_handlers[ 0x0075 ] = u_printf_integer_handler;
01484 
01485   /* handle 'x' */
01486   g_u_printf_infos[ 0x0078 ]     = u_printf_hex_info;
01487   g_u_printf_handlers[ 0x0078 ] = u_printf_hex_handler;
01488 
01489   /* handle 'X' */
01490   g_u_printf_infos[ 0x0058 ]     = u_printf_hex_info;
01491   g_u_printf_handlers[ 0x0058 ] = u_printf_hex_handler;
01492 
01493   /* handle 'f' */
01494   g_u_printf_infos[ 0x0066 ]     = u_printf_double_info;
01495   g_u_printf_handlers[ 0x0066 ] = u_printf_double_handler;
01496 
01497   /* handle 'c' */
01498   g_u_printf_infos[ 0x0063 ]     = u_printf_char_info;
01499   g_u_printf_handlers[ 0x0063 ] = u_printf_char_handler;
01500 
01501   /* handle 'p' */
01502   g_u_printf_infos[ 0x0070 ]     = u_printf_pointer_info;
01503   g_u_printf_handlers[ 0x0070 ] = u_printf_pointer_handler;
01504 
01505   /* handle 'e' */
01506   g_u_printf_infos[ 0x0065 ]     = u_printf_scientific_info;
01507   g_u_printf_handlers[ 0x0065 ] = u_printf_scientific_handler;
01508 
01509   /* handle 'E' */
01510   g_u_printf_infos[ 0x0045 ]     = u_printf_scientific_info;
01511   g_u_printf_handlers[ 0x0045 ] = u_printf_scientific_handler;
01512 
01513   /* handle 'D' */
01514   g_u_printf_infos[ 0x0044 ]     = u_printf_date_info;
01515   g_u_printf_handlers[ 0x0044 ] = u_printf_date_handler;
01516 
01517   /* handle 'P' */
01518   g_u_printf_infos[ 0x0050 ]     = u_printf_percent_info;
01519   g_u_printf_handlers[ 0x0050 ] = u_printf_percent_handler;
01520 
01521   /* handle 'M' */
01522   g_u_printf_infos[ 0x004D ]     = u_printf_currency_info;
01523   g_u_printf_handlers[ 0x004D ] = u_printf_currency_handler;
01524 
01525   /* handle 'T' */
01526   g_u_printf_infos[ 0x0054 ]     = u_printf_time_info;
01527   g_u_printf_handlers[ 0x0054 ] = u_printf_time_handler;
01528 
01529   /* handle 'K' */
01530   g_u_printf_infos[ 0x004B ]     = u_printf_uchar_info;
01531   g_u_printf_handlers[ 0x004B ] = u_printf_uchar_handler;
01532 
01533   /* handle 'U' */
01534   g_u_printf_infos[ 0x0055 ]     = u_printf_ustring_info;
01535   g_u_printf_handlers[ 0x0055 ] = u_printf_ustring_handler;
01536 
01537   /* handle 'g' */
01538   g_u_printf_infos[ 0x0067 ]     = u_printf_scidbl_info;
01539   g_u_printf_handlers[ 0x0067 ] = u_printf_scidbl_handler;
01540 
01541   /* handle 'G' */
01542   g_u_printf_infos[ 0x0047 ]     = u_printf_scidbl_info;
01543   g_u_printf_handlers[ 0x0047 ] = u_printf_scidbl_handler;
01544 
01545   /* handle 'n' */
01546   g_u_printf_infos[ 0x006E ]     = u_printf_count_info;
01547   g_u_printf_handlers[ 0x006E ] = u_printf_count_handler;
01548 
01549   /* handle 'V' */
01550   g_u_printf_infos[ 0x0056 ]     = u_printf_spellout_info;
01551   g_u_printf_handlers[ 0x0056 ] = u_printf_spellout_handler;
01552 
01553 
01554   /* we're finished */
01555   g_u_printf_inited = TRUE;
01556 
01557   /* unlock the cache */
01558   umtx_unlock(0);
01559 }
01560 
01561 
01562 #define U_PRINTF_MAX_ARGS 32
01563 #define UP_PERCENT 0x0025
01564 
01565 int32_t 
01566 u_vfprintf_u(    UFILE        *f,
01567         const UChar    *patternSpecification,
01568         va_list        ap)
01569 {
01570   u_printf_spec   spec;
01571   const UChar     *alias;
01572   int32_t         count, written;
01573 
01574   int32_t         num_args_wanted;
01575   int32_t         ufmt_types     [U_PRINTF_MAX_ARGS];
01576   ufmt_args       args[U_PRINTF_MAX_ARGS];  
01577         
01578   u_printf_info    info;
01579   u_printf_handler handler;
01580 
01581   int32_t         cur_arg;
01582 
01583 
01584   /* init our function tables */
01585   if(! g_u_printf_inited)
01586     u_printf_init();
01587 
01588   /* alias the pattern */
01589   alias = patternSpecification;
01590   
01591   /* haven't written anything yet */
01592   written = 0;
01593 
01594   /* iterate through the pattern */
01595   for(;;) {
01596 
01597     /* find the next '%' */
01598     count = 0;
01599     while(*alias != UP_PERCENT && *alias != 0x0000) {
01600       alias++;
01601       ++count;
01602     }
01603 
01604     /* write any characters before the '%' */
01605     if(count > 0)
01606       written += u_file_write(alias - count, count, f);
01607 
01608     /* break if at end of string */
01609     if(*alias == 0x0000)
01610       break;
01611     
01612     /* parse the specifier */
01613     count = u_printf_parse_spec(alias, &spec);
01614 
01615     /* fill in the precision and width, if specified out of line */
01616 
01617     /* width specified out of line */
01618     if(spec.fInfo.fWidth == -2) {
01619       if(spec.fWidthPos == -1) {
01620         /* read the width from the argument list */
01621         spec.fInfo.fWidth = va_arg(ap, int);
01622       }
01623       else {
01624         /* handle positional parameter */
01625       }
01626     
01627       /* if it's negative, take the absolute value and set left alignment */
01628       if(spec.fInfo.fWidth < 0) {
01629         spec.fInfo.fWidth     *= -1;
01630         spec.fInfo.fLeft     = TRUE;
01631       }
01632     }
01633 
01634     /* precision specified out of line */
01635     if(spec.fInfo.fPrecision == -2) {
01636       if(spec.fPrecisionPos == -1) {
01637         /* read the precision from the argument list */
01638         spec.fInfo.fPrecision = va_arg(ap, int);
01639       }
01640       else {
01641         /* handle positional parameter */
01642       }
01643       
01644       /* if it's negative, set it to zero */
01645       if(spec.fInfo.fPrecision < 0)
01646         spec.fInfo.fPrecision = 0;
01647     }
01648     
01649     /* query the info function for argument information */
01650     info = g_u_printf_infos[ (unsigned char) spec.fInfo.fSpec ];
01651     if(info != 0) { 
01652       num_args_wanted = (*info)(&spec.fInfo, 
01653                 ufmt_types,
01654                 U_PRINTF_MAX_ARGS);
01655     }
01656     else
01657       num_args_wanted = 0;
01658 
01659     /* fill in the requested arguments */
01660     for(cur_arg = 0; 
01661     cur_arg < num_args_wanted && cur_arg < U_PRINTF_MAX_ARGS; 
01662     ++cur_arg) {
01663       
01664       switch(ufmt_types[cur_arg]) {
01665 
01666       case ufmt_count:
01667         args[cur_arg].intValue = va_arg(ap, int);
01668         /* set the spec's width to the # of chars written */
01669         spec.fInfo.fWidth = written;
01670         break;
01671 
01672       case ufmt_int:
01673         args[cur_arg].intValue = va_arg(ap, int);
01674         break;
01675 
01676       case ufmt_char:
01677         args[cur_arg].intValue = va_arg(ap, int);
01678         break;
01679     
01680       case ufmt_wchar:
01681         args[cur_arg].wcharValue = va_arg(ap, wchar_t);
01682         break;
01683 
01684       case ufmt_string:
01685         args[cur_arg].ptrValue = va_arg(ap, char*);
01686         break;
01687     
01688       case ufmt_wstring:
01689         args[cur_arg].ptrValue = va_arg(ap, wchar_t*);
01690         break;
01691     
01692       case ufmt_pointer:
01693         args[cur_arg].ptrValue = va_arg(ap, void*);
01694         break;
01695     
01696       case ufmt_float:
01697         args[cur_arg].floatValue = (float) va_arg(ap, double);
01698         break;
01699     
01700       case ufmt_double:
01701         args[cur_arg].doubleValue = va_arg(ap, double);
01702         break;
01703 
01704       case ufmt_date:
01705         args[cur_arg].dateValue = va_arg(ap, UDate);
01706         break;
01707 
01708       case ufmt_ustring:
01709         args[cur_arg].ptrValue = va_arg(ap, UChar*);
01710         break;
01711 
01712       case ufmt_uchar:
01713         args[cur_arg].intValue = va_arg(ap, int);
01714         break;
01715       }
01716     }
01717     
01718     /* call the handler function */
01719     handler = g_u_printf_handlers[ (unsigned char) spec.fInfo.fSpec ];
01720     if(handler != 0) {
01721       written += (*handler)(f, &spec.fInfo, args);
01722     }
01723     /* just echo unknown tags */
01724     else
01725       written += u_file_write(alias, count, f);
01726     
01727     /* update the pointer in pattern and continue */
01728     alias += count;
01729   }
01730   
01731   /* return # of UChars written */
01732   return written;
01733 }
01734 

Generated at Tue Dec 5 10:48:10 2000 for ICU by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000