Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/intl/icu/source/io/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 52 kB image not shown  

Quelle  uprntf_p.cpp   Sprache: C

 
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
*
*   Copyright (C) 1998-2016, International Business Machines
*   Corporation and others.  All Rights Reserved.
*
******************************************************************************
*
* File uprntf_p.c
*
* Modification History:
*
*   Date        Name        Description
*   11/23/98    stephen     Creation.
*   03/12/99    stephen     Modified for new C API.
*   08/07/2003  george      Reunify printf implementations
******************************************************************************
*/


#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION

#include "unicode/ustring.h"
#include "unicode/utf16.h"
#include "uprintf.h"
#include "ufmt_cmn.h"
#include "cmemory.h"
#include "putilimp.h"

/* ANSI style formatting */
/* Use US-ASCII characters only for formatting */

/* % */
#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
/* s */
#define UFMT_STRING         {ufmt_string, u_printf_string_handler}
/* c */
#define UFMT_CHAR           {ufmt_char, u_printf_char_handler}
/* d, i */
#define UFMT_INT            {ufmt_int, u_printf_integer_handler}
/* u */
#define UFMT_UINT           {ufmt_int, u_printf_uinteger_handler}
/* o */
#define UFMT_OCTAL          {ufmt_int, u_printf_octal_handler}
/* x, X */
#define UFMT_HEX            {ufmt_int, u_printf_hex_handler}
/* f */
#define UFMT_DOUBLE         {ufmt_double, u_printf_double_handler}
/* e, E */
#define UFMT_SCIENTIFIC     {ufmt_double, u_printf_scientific_handler}
/* g, G */
#define UFMT_SCIDBL         {ufmt_double, u_printf_scidbl_handler}
/* n */
#define UFMT_COUNT          {ufmt_count, u_printf_count_handler}

/* non-ANSI extensions */
/* Use US-ASCII characters only for formatting */

/* p */
#define UFMT_POINTER        {ufmt_pointer, u_printf_pointer_handler}
/* V */
#define UFMT_SPELLOUT       {ufmt_double, u_printf_spellout_handler}
/* P */
#define UFMT_PERCENT        {ufmt_double, u_printf_percent_handler}
/* C  K is old format */
#define UFMT_UCHAR          {ufmt_uchar, u_printf_uchar_handler}
/* S  U is old format */
#define UFMT_USTRING        {ufmt_ustring, u_printf_ustring_handler}


#define UFMT_EMPTY {ufmt_empty, nullptr}

/**
 * A u_printf handler function.  
 * A u_printf handler is responsible for handling a single u_printf 
 * format specification, for example 'd' or 's'.
 * @param stream The UFILE to which to write output.
 * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
 * information on the format specification.
 * @param args A pointer to the argument data
 * @return The number of Unicode characters written to <TT>stream</TT>.
 */

typedef int32_t U_EXPORT2
u_printf_handler(const u_printf_stream_handler  *handler,

                 void                           *context,
                 ULocaleBundle                  *formatBundle,
                 const u_printf_spec_info       *info,
                 const ufmt_args                *args);

typedef struct u_printf_info {
    ufmt_type_info info;
    u_printf_handler *handler;
} u_printf_info;

/**
 * Struct encapsulating a single uprintf format specification.
 */

typedef struct u_printf_spec {
  u_printf_spec_info    fInfo;        /* Information on this spec */
  int32_t        fWidthPos;     /* Position of width in arg list */
  int32_t        fPrecisionPos;    /* Position of precision in arg list */
  int32_t        fArgPos;    /* Position of data in arg list */
} u_printf_spec;

#define UPRINTF_NUM_FMT_HANDLERS 108

/* We do not use handlers for 0-0x1f */
#define UPRINTF_BASE_FMT_HANDLERS 0x20

/* buffer size for formatting */
#define UPRINTF_BUFFER_SIZE 1024
#define UPRINTF_SYMBOL_BUFFER_SIZE 8

static const char16_t gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
static const char16_t gSpaceStr[] = {0x20, 0}; /* " " */

/* Sets the sign of a format based on u_printf_spec_info */
/* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
static void
u_printf_set_sign(UNumberFormat        *format,
                   const u_printf_spec_info     *info,
                   char16_t *prefixBuffer,
                   int32_t *prefixBufLen,
                   UErrorCode *status)
{
    if(info->fShowSign) {
        *prefixBufLen = unum_getTextAttribute(format,
                                              UNUM_POSITIVE_PREFIX,
                                              prefixBuffer,
                                              *prefixBufLen,
                                              status);
        if (info->fSpace) {
            /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
            /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
            unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
        }
        else {
            char16_t plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
            int32_t symbolLen;

            symbolLen = unum_getSymbol(format,
                UNUM_PLUS_SIGN_SYMBOL,
                plusSymbol,
                UPRV_LENGTHOF(plusSymbol),
                status);
            unum_setTextAttribute(format,
                UNUM_POSITIVE_PREFIX,
                plusSymbol,
                symbolLen,
                status);
        }
    }
    else {
        *prefixBufLen = 0;
    }
}

static void
u_printf_reset_sign(UNumberFormat        *format,
                   const u_printf_spec_info     *info,
                   char16_t *prefixBuffer,
                   int32_t *prefixBufLen,
                   UErrorCode *status)
{
    if(info->fShowSign) {
        unum_setTextAttribute(format,
                              UNUM_POSITIVE_PREFIX,
                              prefixBuffer,
                              *prefixBufLen,
                              status);
    }
}


/* handle a '%' */
static int32_t
u_printf_simple_percent_handler(const u_printf_stream_handler  *handler,
                                void                           *context,
                                ULocaleBundle                  *formatBundle,
                                const u_printf_spec_info       *info,
                                const ufmt_args                *args)
{
    (void)formatBundle;
    (void)info;
    (void)args;
    static const char16_t PERCENT[] = { UP_PERCENT };

    /* put a single '%' onto the output */
    return handler->write(context, PERCENT, 1);
}

/* handle 's' */
static int32_t
u_printf_string_handler(const u_printf_stream_handler  *handler,
                        void                           *context,
                        ULocaleBundle                  *formatBundle,
                        const u_printf_spec_info       *info,
                        const ufmt_args                *args)
{
    (void)formatBundle;
    char16_t *s;
    char16_t buffer[UFMT_DEFAULT_BUFFER_SIZE];
    int32_t len, written;
    int32_t argSize;
    const char* arg = static_cast<const char*>(args[0].ptrValue);

    /* convert from the default codepage to Unicode */
    if (arg) {
        argSize = static_cast<int32_t>(strlen(arg)) + 1;
        if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
            s = ufmt_defaultCPToUnicode(arg, argSize,
                    static_cast<char16_t*>(uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize))),
                    MAX_UCHAR_BUFFER_NEEDED(argSize));
            if(s == nullptr) {
                return 0;
            }
        }
        else {
            s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
                    UPRV_LENGTHOF(buffer));
        }
    }
    else {
        s = (char16_t *)gNullStr;
    }
    len = u_strlen(s);

    /* width = minimum # of characters to write */
    /* precision = maximum # of characters to write */
    if (info->fPrecision != -1 && info->fPrecision < len) {
        len = info->fPrecision;
    }

    written = handler->pad_and_justify(context, info, s, len);

    /* clean up */
    if (gNullStr != s && buffer != s) {
        uprv_free(s);
    }

    return written;
}

static int32_t
u_printf_char_handler(const u_printf_stream_handler  *handler,
                      void                           *context,
                      ULocaleBundle                  *formatBundle,
                      const u_printf_spec_info       *info,
                      const ufmt_args                *args)
{
    (void)formatBundle;
    char16_t s[U16_MAX_LENGTH+1];
    int32_t len = 1, written;
    unsigned char arg = static_cast<unsigned char>(args[0].int64Value);

    /* convert from default codepage to Unicode */
    ufmt_defaultCPToUnicode(reinterpret_cast<const char*>(&arg), 2, s, UPRV_LENGTHOF(s));

    /* Remember that this may be an MBCS character */
    if (arg != 0) {
        len = u_strlen(s);
    }

    /* width = minimum # of characters to write */
    /* precision = maximum # of characters to write */
    /* precision is ignored when handling a char */

    written = handler->pad_and_justify(context, info, s, len);

    return written;
}

static int32_t
u_printf_double_handler(const u_printf_stream_handler  *handler,
                        void                           *context,
                        ULocaleBundle                  *formatBundle,
                        const u_printf_spec_info       *info,
                        const ufmt_args                *args)
{
    double num = args[0].doubleValue;
    UNumberFormat  *format;
    char16_t       result[UPRINTF_BUFFER_SIZE];
    char16_t       prefixBuffer[UPRINTF_BUFFER_SIZE];
    int32_t        prefixBufferLen = sizeof(prefixBuffer);
    int32_t        minDecimalDigits;
    int32_t        maxDecimalDigits;
    int32_t        resultLen;
    UErrorCode     status        = U_ZERO_ERROR;

    prefixBuffer[0] = 0;

    /* mask off any necessary bits */
    /*  if(! info->fIsLongDouble)
    num &= DBL_MAX;*/


    /* get the formatter */
    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);

    /* handle error */
    if (format == nullptr)
        return 0;

    /* save the formatter's state */
    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);

    /* set the appropriate flags and number of decimal digits on the formatter */
    if(info->fPrecision != -1) {
        /* set the # of decimal digits */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    }
    else if(info->fAlt) {
        /* '#' means always show decimal point */
        /* copy of printf behavior on Solaris - '#' shows 6 digits */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }
    else {
        /* # of decimal digits is 6 if precision not specified regardless of locale */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }

    /* set whether to show the sign */
    if (info->fShowSign) {
        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    }

    /* format the number */
    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);

    if (U_FAILURE(status)) {
        resultLen = 0;
    }

    /* restore the number format */
    /* TODO: Is this needed? */
    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);

    if (info->fShowSign) {
        /* Reset back to original value regardless of what the error was */
        UErrorCode localStatus = U_ZERO_ERROR;
        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    }

    return handler->pad_and_justify(context, info, result, resultLen);
}

/* HSYS */
static int32_t
u_printf_integer_handler(const u_printf_stream_handler  *handler,
                         void                           *context,
                         ULocaleBundle                  *formatBundle,
                         const u_printf_spec_info       *info,
                         const ufmt_args                *args)
{
    int64_t         num        = args[0].int64Value;
    UNumberFormat   *format;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    int32_t         minDigits     = -1;
    int32_t         resultLen;
    UErrorCode      status        = U_ZERO_ERROR;

    prefixBuffer[0] = 0;

    /* mask off any necessary bits */
    if (info->fIsShort)
        num = static_cast<int16_t>(num);
    else if (!info->fIsLongLong)
        num = static_cast<int32_t>(num);

    /* get the formatter */
    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);

    /* handle error */
    if (format == nullptr)
        return 0;

    /* set the appropriate flags on the formatter */

    /* set the minimum integer digits */
    if(info->fPrecision != -1) {
        /* set the minimum # of digits */
        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
    }

    /* set whether to show the sign */
    if(info->fShowSign) {
        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    }

    /* format the number */
    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);

    if (U_FAILURE(status)) {
        resultLen = 0;
    }

    /* restore the number format */
    if (minDigits != -1) {
        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
    }

    if (info->fShowSign) {
        /* Reset back to original value regardless of what the error was */
        UErrorCode localStatus = U_ZERO_ERROR;
        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    }

    return handler->pad_and_justify(context, info, result, resultLen);
}

static int32_t
u_printf_hex_handler(const u_printf_stream_handler  *handler,
                     void                           *context,
                     ULocaleBundle                  *formatBundle,
                     const u_printf_spec_info       *info,
                     const ufmt_args                *args)
{
    (void)formatBundle;
    int64_t         num        = args[0].int64Value;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    int32_t         len        = UPRINTF_BUFFER_SIZE;


    /* mask off any necessary bits */
    if (info->fIsShort)
        num &= UINT16_MAX;
    else if (!info->fIsLongLong)
        num &= UINT32_MAX;

    /* format the number, preserving the minimum # of digits */
    ufmt_64tou(result, &len, num, 16,
        static_cast<UBool>(info->fSpec == 0x0078),
        (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);

    /* convert to alt form, if desired */
    if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
        /* shift the formatted string right by 2 chars */
        memmove(result + 2, result, len * sizeof(char16_t));
        result[0] = 0x0030;
        result[1] = info->fSpec;
        len += 2;
    }

    return handler->pad_and_justify(context, info, result, len);
}

static int32_t
u_printf_octal_handler(const u_printf_stream_handler  *handler,
                       void                           *context,
                       ULocaleBundle                  *formatBundle,
                       const u_printf_spec_info       *info,
                       const ufmt_args                *args)
{
    (void)formatBundle;
    int64_t         num        = args[0].int64Value;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    int32_t         len        = UPRINTF_BUFFER_SIZE;


    /* mask off any necessary bits */
    if (info->fIsShort)
        num &= UINT16_MAX;
    else if (!info->fIsLongLong)
        num &= UINT32_MAX;

    /* format the number, preserving the minimum # of digits */
    ufmt_64tou(result, &len, num, 8,
        false/* doesn't matter for octal */
        info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);

    /* convert to alt form, if desired */
    if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
        /* shift the formatted string right by 1 char */
        memmove(result + 1, result, len * sizeof(char16_t));
        result[0] = 0x0030;
        len += 1;
    }

    return handler->pad_and_justify(context, info, result, len);
}

static int32_t
u_printf_uinteger_handler(const u_printf_stream_handler *handler,
                          void                          *context,
                          ULocaleBundle                 *formatBundle,
                          const u_printf_spec_info      *info,
                          const ufmt_args               *args)
{
    int64_t         num        = args[0].int64Value;
    UNumberFormat   *format;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    int32_t         minDigits     = -1;
    int32_t         resultLen;
    UErrorCode      status        = U_ZERO_ERROR;

    /* TODO: Fix this once uint64_t can be formatted. */
    if (info->fIsShort)
        num &= UINT16_MAX;
    else if (!info->fIsLongLong)
        num &= UINT32_MAX;

    /* get the formatter */
    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);

    /* handle error */
    if (format == nullptr)
        return 0;

    /* set the appropriate flags on the formatter */

    /* set the minimum integer digits */
    if(info->fPrecision != -1) {
        /* set the minimum # of digits */
        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
    }

    /* To mirror other stdio implementations, we ignore the sign argument */

    /* format the number */
    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);

    if (U_FAILURE(status)) {
        resultLen = 0;
    }

    /* restore the number format */
    if (minDigits != -1) {
        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
    }

    return handler->pad_and_justify(context, info, result, resultLen);
}

static int32_t
u_printf_pointer_handler(const u_printf_stream_handler  *handler,
                         void                           *context,
                         ULocaleBundle                  *formatBundle,
                         const u_printf_spec_info       *info,
                         const ufmt_args                *args)

    (void)formatBundle;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    int32_t         len  = UPRINTF_BUFFER_SIZE;

    /* format the pointer in hex */
    ufmt_ptou(result, &len, args[0].ptrValue, true/*, info->fPrecision*/);

    return handler->pad_and_justify(context, info, result, len);
}

static int32_t
u_printf_scientific_handler(const u_printf_stream_handler  *handler,
                            void                           *context,
                            ULocaleBundle                  *formatBundle,
                            const u_printf_spec_info       *info,
                            const ufmt_args                *args)
{
    double num = args[0].doubleValue;
    UNumberFormat   *format;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    int32_t         minDecimalDigits;
    int32_t         maxDecimalDigits;
    UErrorCode      status        = U_ZERO_ERROR;
    char16_t srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
    int32_t srcLen, expLen;
    int32_t resultLen;
    char16_t expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];

    prefixBuffer[0] = 0;

    /* mask off any necessary bits */
    /*  if(! info->fIsLongDouble)
    num &= DBL_MAX;*/


    /* get the formatter */
    format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);

    /* handle error */
    if (format == nullptr)
        return 0;

    /* set the appropriate flags on the formatter */

    srcLen = unum_getSymbol(format,
        UNUM_EXPONENTIAL_SYMBOL,
        srcExpBuf,
        sizeof(srcExpBuf),
        &status);

    /* Upper/lower case the e */
    if (info->fSpec == static_cast<char16_t>(0x65) /* e */) {
        expLen = u_strToLower(expBuf, static_cast<int32_t>(sizeof(expBuf)),
            srcExpBuf, srcLen,
            formatBundle->fLocale,
            &status);
    }
    else {
        expLen = u_strToUpper(expBuf, static_cast<int32_t>(sizeof(expBuf)),
            srcExpBuf, srcLen,
            formatBundle->fLocale,
            &status);
    }

    unum_setSymbol(format,
        UNUM_EXPONENTIAL_SYMBOL,
        expBuf,
        expLen,
        &status);

    /* save the formatter's state */
    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);

    /* set the appropriate flags and number of decimal digits on the formatter */
    if(info->fPrecision != -1) {
        /* set the # of decimal digits */
        if (info->fOrigSpec == static_cast<char16_t>(0x65) /* e */ ||
            info->fOrigSpec == static_cast<char16_t>(0x45) /* E */) {
            unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
        }
        else {
            unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
            unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
        }
    }
    else if(info->fAlt) {
        /* '#' means always show decimal point */
        /* copy of printf behavior on Solaris - '#' shows 6 digits */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }
    else {
        /* # of decimal digits is 6 if precision not specified */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }

    /* set whether to show the sign */
    if (info->fShowSign) {
        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    }

    /* format the number */
    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);

    if (U_FAILURE(status)) {
        resultLen = 0;
    }

    /* restore the number format */
    /* TODO: Is this needed? */
    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);

    /* Since we're the only one using the scientific
       format, we don't need to save the old exponent value. */

    /*unum_setSymbol(format,
        UNUM_EXPONENTIAL_SYMBOL,
        srcExpBuf,
        srcLen,
        &status);*/


    if (info->fShowSign) {
        /* Reset back to original value regardless of what the error was */
        UErrorCode localStatus = U_ZERO_ERROR;
        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    }

    return handler->pad_and_justify(context, info, result, resultLen);
}

static int32_t
u_printf_percent_handler(const u_printf_stream_handler  *handler,
                         void                           *context,
                         ULocaleBundle                  *formatBundle,
                         const u_printf_spec_info       *info,
                         const ufmt_args                *args)
{
    double num = args[0].doubleValue;
    UNumberFormat   *format;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    int32_t         minDecimalDigits;
    int32_t         maxDecimalDigits;
    int32_t         resultLen;
    UErrorCode      status        = U_ZERO_ERROR;

    prefixBuffer[0] = 0;

    /* mask off any necessary bits */
    /*  if(! info->fIsLongDouble)
    num &= DBL_MAX;*/


    /* get the formatter */
    format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);

    /* handle error */
    if (format == nullptr)
        return 0;

    /* save the formatter's state */
    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);

    /* set the appropriate flags and number of decimal digits on the formatter */
    if(info->fPrecision != -1) {
        /* set the # of decimal digits */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    }
    else if(info->fAlt) {
        /* '#' means always show decimal point */
        /* copy of printf behavior on Solaris - '#' shows 6 digits */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }
    else {
        /* # of decimal digits is 6 if precision not specified */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }

    /* set whether to show the sign */
    if (info->fShowSign) {
        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    }

    /* format the number */
    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);

    if (U_FAILURE(status)) {
        resultLen = 0;
    }

    /* restore the number format */
    /* TODO: Is this needed? */
    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);

    if (info->fShowSign) {
        /* Reset back to original value regardless of what the error was */
        UErrorCode localStatus = U_ZERO_ERROR;
        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    }

    return handler->pad_and_justify(context, info, result, resultLen);
}

static int32_t
u_printf_ustring_handler(const u_printf_stream_handler  *handler,
                         void                           *context,
                         ULocaleBundle                  *formatBundle,
                         const u_printf_spec_info       *info,
                         const ufmt_args                *args)
{
    (void)formatBundle;
    int32_t len, written;
    const char16_t* arg = static_cast<const char16_t*>(args[0].ptrValue);

    /* allocate enough space for the buffer */
    if (arg == nullptr) {
        arg = gNullStr;
    }
    len = u_strlen(arg);

    /* width = minimum # of characters to write */
    /* precision = maximum # of characters to write */
    if (info->fPrecision != -1 && info->fPrecision < len) {
        len = info->fPrecision;
    }

    /* determine if the string should be padded */
    written = handler->pad_and_justify(context, info, arg, len);

    return written;
}

static int32_t
u_printf_uchar_handler(const u_printf_stream_handler  *handler,
                       void                           *context,
                       ULocaleBundle                  *formatBundle,
                       const u_printf_spec_info       *info,
                       const ufmt_args                *args)
{
    (void)formatBundle;
    int32_t written = 0;
    char16_t arg = static_cast<char16_t>(args[0].int64Value);

    /* width = minimum # of characters to write */
    /* precision = maximum # of characters to write */
    /* precision is ignored when handling a uchar */

    /* determine if the string should be padded */
    written = handler->pad_and_justify(context, info, &arg, 1);

    return written;
}

static int32_t
u_printf_scidbl_handler(const u_printf_stream_handler  *handler,
                        void                           *context,
                        ULocaleBundle                  *formatBundle,
                        const u_printf_spec_info       *info,
                        const ufmt_args                *args)
{
    u_printf_spec_info scidbl_info;
    double      num = args[0].doubleValue;
    int32_t     retVal;
    UNumberFormat *format;
    int32_t maxSigDecimalDigits, significantDigits;

    memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));

    /* determine whether to use 'd', 'e' or 'f' notation */
    if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
    {
        /* use 'f' notation */
        scidbl_info.fSpec = 0x0066;
        scidbl_info.fPrecision = 0;
        /* call the double handler */
        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
    }
    else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
        || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
    {
        /* use 'e' or 'E' notation */
        scidbl_info.fSpec = scidbl_info.fSpec - 2;
        if (scidbl_info.fPrecision == -1) {
            scidbl_info.fPrecision = 5;
        }
        /* call the scientific handler */
        retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
    }
    else {
        format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
        /* Check for null pointer */
        if (format == nullptr) {
            return 0;
        }
        maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
        significantDigits = scidbl_info.fPrecision;

        /* use 'f' notation */
        scidbl_info.fSpec = 0x0066;
        if (significantDigits == -1) {
            significantDigits = 6;
        }
        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, true);
        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
        /* call the double handler */
        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, false);
    }
    return retVal;
}

static int32_t
u_printf_count_handler(const u_printf_stream_handler  *handler,
                       void                           *context,
                       ULocaleBundle                  *formatBundle,
                       const u_printf_spec_info       *info,
                       const ufmt_args                *args)
{
    (void)handler;
    (void)context;
    (void)formatBundle;
    int32_t* count = static_cast<int32_t*>(args[0].ptrValue);

    /* in the special case of count, the u_printf_spec_info's width */
    /* will contain the # of chars written thus far */
    *count = info->fWidth;

    return 0;
}

static int32_t
u_printf_spellout_handler(const u_printf_stream_handler *handler,
                          void                          *context,
                          ULocaleBundle                 *formatBundle,
                          const u_printf_spec_info      *info,
                          const ufmt_args               *args)
{
    double num = args[0].doubleValue;
    UNumberFormat   *format;
    char16_t        result[UPRINTF_BUFFER_SIZE];
    char16_t        prefixBuffer[UPRINTF_BUFFER_SIZE];
    int32_t         prefixBufferLen = sizeof(prefixBuffer);
    int32_t         minDecimalDigits;
    int32_t         maxDecimalDigits;
    int32_t         resultLen;
    UErrorCode      status        = U_ZERO_ERROR;

    prefixBuffer[0] = 0;

    /* mask off any necessary bits */
    /*  if(! info->fIsLongDouble)
    num &= DBL_MAX;*/


    /* get the formatter */
    format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);

    /* handle error */
    if (format == nullptr)
        return 0;

    /* save the formatter's state */
    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);

    /* set the appropriate flags and number of decimal digits on the formatter */
    if(info->fPrecision != -1) {
        /* set the # of decimal digits */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    }
    else if(info->fAlt) {
        /* '#' means always show decimal point */
        /* copy of printf behavior on Solaris - '#' shows 6 digits */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }
    else {
        /* # of decimal digits is 6 if precision not specified */
        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    }

    /* set whether to show the sign */
    if (info->fShowSign) {
        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    }

    /* format the number */
    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status);

    if (U_FAILURE(status)) {
        resultLen = 0;
    }

    /* restore the number format */
    /* TODO: Is this needed? */
    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);

    if (info->fShowSign) {
        /* Reset back to original value regardless of what the error was */
        UErrorCode localStatus = U_ZERO_ERROR;
        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    }

    return handler->pad_and_justify(context, info, result, resultLen);
}

/* Use US-ASCII characters only for formatting. Most codepages have
 characters 20-7F from Unicode. Using any other codepage specific
 characters will make it very difficult to format the string on
 non-Unicode machines */

static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
/* 0x20 */
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,

/* 0x30 */
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,

/* 0x40 */
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
    UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
#ifdef U_USE_OBSOLETE_IO_FORMATTING
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
#else
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
#endif
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,

/* 0x50 */
    UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
#ifdef U_USE_OBSOLETE_IO_FORMATTING
    UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
#else
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
#endif
    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,

/* 0x60 */
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
    UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
    UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,

/* 0x70 */
    UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
    UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
};

/* flag characters for uprintf */
#define FLAG_MINUS 0x002D
#define FLAG_PLUS 0x002B
#define FLAG_SPACE 0x0020
#define FLAG_POUND 0x0023
#define FLAG_ZERO  0x0030
#define FLAG_PAREN 0x0028

#define ISFLAG(s)    (s) == FLAG_MINUS || \
            (s) == FLAG_PLUS || \
            (s) == FLAG_SPACE || \
            (s) == FLAG_POUND || \
            (s) == FLAG_ZERO || \
            (s) == FLAG_PAREN

/* special characters for uprintf */
#define SPEC_ASTERISK 0x002A
#define SPEC_DOLLARSIGN 0x0024
#define SPEC_PERIOD 0x002E
#define SPEC_PERCENT 0x0025

/* unicode digits */
#define DIGIT_ZERO 0x0030
#define DIGIT_ONE 0x0031
#define DIGIT_TWO 0x0032
#define DIGIT_THREE 0x0033
#define DIGIT_FOUR 0x0034
#define DIGIT_FIVE 0x0035
#define DIGIT_SIX 0x0036
#define DIGIT_SEVEN 0x0037
#define DIGIT_EIGHT 0x0038
#define DIGIT_NINE 0x0039

#define ISDIGIT(s)    (s) == DIGIT_ZERO || \
            (s) == DIGIT_ONE || \
            (s) == DIGIT_TWO || \
            (s) == DIGIT_THREE || \
            (s) == DIGIT_FOUR || \
            (s) == DIGIT_FIVE || \
            (s) == DIGIT_SIX || \
            (s) == DIGIT_SEVEN || \
            (s) == DIGIT_EIGHT || \
            (s) == DIGIT_NINE

/* u_printf modifiers */
#define MOD_H 0x0068
#define MOD_LOWERL 0x006C
#define MOD_L 0x004C

#define ISMOD(s)    (s) == MOD_H || \
            (s) == MOD_LOWERL || \
            (s) == MOD_L
/* Returns an array of the parsed argument type given in the format string. */
static ufmt_args* parseArguments(const char16_t *alias, va_list ap, UErrorCode *status) {
    ufmt_args *arglist = nullptr;
    ufmt_type_info *typelist = nullptr;
    UBool *islonglong = nullptr;
    int32_t size = 0;
    int32_t pos = 0;
    char16_t type;
    uint16_t handlerNum;
    const char16_t *aliasStart = alias;

    /* get maximum number of arguments */
    for(;;) {
        /* find % */
        while(*alias != UP_PERCENT && *alias != 0x0000) {
            alias++;
        }

        if(*alias == 0x0000) {
            break;
        }

        alias++;

        /* handle the pos number */
        if(ISDIGIT(*alias)) {

            /* handle positional parameters */
            if(ISDIGIT(*alias)) {
                pos = *alias++ - DIGIT_ZERO;

                while(ISDIGIT(*alias)) {
                    pos *= 10;
                    pos += *alias++ - DIGIT_ZERO;
                }
            }

            /* if there is no '$', don't read anything */
            if(*alias != SPEC_DOLLARSIGN) {
                return nullptr;
            }
        } else {
            return nullptr;
        }

        if (pos > size) {
            size = pos;
        }
    }

    /* create the parsed argument list */
    typelist = static_cast<ufmt_type_info*>(uprv_malloc(sizeof(ufmt_type_info) * size));
    islonglong = static_cast<UBool*>(uprv_malloc(sizeof(UBool) * size));
    arglist = static_cast<ufmt_args*>(uprv_malloc(sizeof(ufmt_args) * size));

    /* If malloc failed, return nullptr */
    if (!typelist || !islonglong || !arglist) {
        if (typelist) {
            uprv_free(typelist);
        }

        if (islonglong) {
            uprv_free(islonglong);
        }

        if (arglist) {
            uprv_free(arglist);
        }

        *status = U_MEMORY_ALLOCATION_ERROR;
        return nullptr;
    }

    /* reset alias back to the beginning */
    alias = aliasStart;

    for(;;) {
        /* find % */
        while(*alias != UP_PERCENT && *alias != 0x0000) {
            alias++;
        }

        if(*alias == 0x0000) {
            break;
        }

        alias++;

        /* handle positional parameters */
        if(ISDIGIT(*alias)) {
            pos = *alias++ - DIGIT_ZERO;

            while(ISDIGIT(*alias)) {
                pos *= 10;
                pos += *alias++ - DIGIT_ZERO;
            }
        }
        /* offset position by 1 */
        pos--;

        /* skip over everything except for the type */
        while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || 
            *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
                islonglong[pos] = false;
                if (ISMOD(*alias)) {
                    alias++;
                    if (*alias == MOD_LOWERL) {
                        islonglong[pos] = true;
                    } 
                } 
                alias++;
        }
        type = *alias;

        /* store the argument type in the correct position of the parsed argument list */
        handlerNum = static_cast<uint16_t>(type - UPRINTF_BASE_FMT_HANDLERS);
        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
            typelist[pos] = g_u_printf_infos[ handlerNum ].info;
        } else {
            typelist[pos] = ufmt_empty;
        }
    }

    /* store argument in arglist */
    for (pos = 0; pos < size; pos++) {
        switch (typelist[pos]) {
        case ufmt_string:
        case ufmt_ustring:
        case ufmt_pointer:
            arglist[pos].ptrValue = va_arg(ap, void*);
            break;
        case ufmt_char:
        case ufmt_uchar:
        case ufmt_int:
            if (islonglong[pos]) {
                arglist[pos].int64Value = va_arg(ap, int64_t);
            }
            else {
                arglist[pos].int64Value = va_arg(ap, int32_t);
            }
            break;
        case ufmt_float:
            arglist[pos].floatValue = static_cast<float>(va_arg(ap, double));
            break;
        case ufmt_double:
            arglist[pos].doubleValue = va_arg(ap, double);
            break;
        default:
            /* else args is ignored */
            arglist[pos].ptrValue = nullptr;
            break;
        }
    }

    uprv_free(typelist);
    uprv_free(islonglong);

    return arglist;
}

/* We parse the argument list in Unicode */
U_CFUNC int32_t
u_printf_parse(const u_printf_stream_handler *streamHandler,
               const char16_t  *fmt,
               void            *context,
               u_localized_print_string *locStringContext,
               ULocaleBundle   *formatBundle,
               int32_t         *written,
               va_list         ap)
{
    uint16_t         handlerNum;
    ufmt_args        args;
    ufmt_type_info   argType;
    u_printf_handler *handler;
    u_printf_spec    spec;
    u_printf_spec_info *info = &(spec.fInfo);

    const char16_t *alias = fmt;
    const char16_t *backup;
    const char16_t *lastAlias;
    const char16_t *orgAlias = fmt;
    /* parsed argument list */
    ufmt_args *arglist = nullptr; /* initialized it to avoid compiler warnings */
    UErrorCode status = U_ZERO_ERROR;
    if (!locStringContext || locStringContext->available >= 0) {
        /* get the parsed list of argument types */
        arglist = parseArguments(orgAlias, ap, &status);

        /* Return error if parsing failed. */
        if (U_FAILURE(status)) {
            return -1;
        }
    }
    
    /* iterate through the pattern */
    while(!locStringContext || locStringContext->available >= 0) {

        /* find the next '%' */
        lastAlias = alias;
        while(*alias != UP_PERCENT && *alias != 0x0000) {
            alias++;
        }

        /* write any characters before the '%' */
        if(alias > lastAlias) {
            *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
        }

        /* break if at end of string */
        if(*alias == 0x0000) {
            break;
        }

        /* initialize spec to default values */
        spec.fWidthPos     = -1;
        spec.fPrecisionPos = -1;
        spec.fArgPos       = -1;

        uprv_memset(info, 0, sizeof(*info));
        info->fPrecision    = -1;
        info->fWidth        = -1;
        info->fPadChar      = 0x0020;

        /* skip over the initial '%' */
        alias++;

        /* Check for positional argument */
        if(ISDIGIT(*alias)) {

            /* Save the current position */
            backup = alias;

            /* handle positional parameters */
            if(ISDIGIT(*alias)) {
                spec.fArgPos = *alias++ - DIGIT_ZERO;

                while(ISDIGIT(*alias)) {
                    spec.fArgPos *= 10;
                    spec.fArgPos += *alias++ - DIGIT_ZERO;
                }
            }

            /* if there is no '$', don't read anything */
            if(*alias != SPEC_DOLLARSIGN) {
                spec.fArgPos = -1;
                alias = backup;
            }
            /* munge the '$' */
            else
                alias++;
        }

        /* Get any format flags */
        while(ISFLAG(*alias)) {
            switch(*alias++) {

                /* left justify */
            case FLAG_MINUS:
                info->fLeft = true;
                break;

                /* always show sign */
            case FLAG_PLUS:
                info->fShowSign = true;
                break;

                /* use space if no sign present */
            case FLAG_SPACE:
                info->fShowSign = true;
                info->fSpace = true;
                break;

                /* use alternate form */
            case FLAG_POUND:
                info->fAlt = true;
                break;

                /* pad with leading zeroes */
            case FLAG_ZERO:
                info->fZero = true;
                info->fPadChar = 0x0030;
                break;

                /* pad character specified */
            case FLAG_PAREN:

                /* TODO test that all four are numbers */
                /* first four characters are hex values for pad char */
                info->fPadChar = (char16_t)ufmt_digitvalue(*alias++);
                info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
                info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
                info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));

                /* final character is ignored */
                alias++;

                break;
            }
        }

        /* Get the width */

        /* width is specified out of line */
        if(*alias == SPEC_ASTERISK) {

            info->fWidth = -2;

            /* Skip the '*' */
            alias++;

            /* Save the current position */
            backup = alias;

            /* handle positional parameters */
            if(ISDIGIT(*alias)) {
                spec.fWidthPos = *alias++ - DIGIT_ZERO;

                while(ISDIGIT(*alias)) {
                    spec.fWidthPos *= 10;
                    spec.fWidthPos += *alias++ - DIGIT_ZERO;
                }
            }

            /* if there is no '$', don't read anything */
            if(*alias != SPEC_DOLLARSIGN) {
                spec.fWidthPos = -1;
                alias = backup;
            }
            /* munge the '$' */
            else
                alias++;
        }
        /* read the width, if present */
        else if(ISDIGIT(*alias)){
            info->fWidth = *alias++ - DIGIT_ZERO;

            while(ISDIGIT(*alias)) {
                info->fWidth *= 10;
                info->fWidth += *alias++ - DIGIT_ZERO;
            }
        }

        /* Get the precision */

        if(*alias == SPEC_PERIOD) {

            /* eat up the '.' */
            alias++;

            /* precision is specified out of line */
            if(*alias == SPEC_ASTERISK) {

                info->fPrecision = -2;

                /* Skip the '*' */
                alias++;

                /* save the current position */
                backup = alias;

                /* handle positional parameters */
                if(ISDIGIT(*alias)) {
                    spec.fPrecisionPos = *alias++ - DIGIT_ZERO;

                    while(ISDIGIT(*alias)) {
                        spec.fPrecisionPos *= 10;
                        spec.fPrecisionPos += *alias++ - DIGIT_ZERO;
                    }

                    /* if there is no '$', don't read anything */
                    if(*alias != SPEC_DOLLARSIGN) {
                        spec.fPrecisionPos = -1;
                        alias = backup;
                    }
                    else {
                        /* munge the '$' */
                        alias++;
                    }
                }
            }
            /* read the precision */
            else if(ISDIGIT(*alias)){
                info->fPrecision = *alias++ - DIGIT_ZERO;

                while(ISDIGIT(*alias)) {
                    info->fPrecision *= 10;
                    info->fPrecision += *alias++ - DIGIT_ZERO;
                }
            }
        }

        /* Get any modifiers */
        if(ISMOD(*alias)) {
            switch(*alias++) {

                /* short */
            case MOD_H:
                info->fIsShort = true;
                break;

                /* long or long long */
            case MOD_LOWERL:
                if(*alias == MOD_LOWERL) {
                    info->fIsLongLong = true;
                    /* skip over the next 'l' */
                    alias++;
                }
                else
                    info->fIsLong = true;
                break;

                /* long double */
            case MOD_L:
                info->fIsLongDouble = true;
                break;
            }
        }

        /* finally, get the specifier letter */
        info->fSpec = *alias++;
        info->fOrigSpec = info->fSpec;

        /* fill in the precision and width, if specified out of line */

        /* width specified out of line */
        if(spec.fInfo.fWidth == -2) {
            if(spec.fWidthPos == -1) {
                /* read the width from the argument list */
                info->fWidth = va_arg(ap, int32_t);
            }
            /* else handle positional parameter */

            /* if it's negative, take the absolute value and set left alignment */
            if(info->fWidth < 0) {
                info->fWidth *= -1; /* Make positive */
                info->fLeft = true;
            }
        }

        /* precision specified out of line */
        if(info->fPrecision == -2) {
            if(spec.fPrecisionPos == -1) {
                /* read the precision from the argument list */
                info->fPrecision = va_arg(ap, int32_t);
            }
            /* else handle positional parameter */

            /* if it's negative, set it to zero */
            if(info->fPrecision < 0)
                info->fPrecision = 0;
        }

        handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
            /* query the info function for argument information */
            argType = g_u_printf_infos[ handlerNum ].info;

            /* goto the correct argument on arg_list if position is specified */
            if (spec.fArgPos > 0) {
                /* offset position by 1 */
                spec.fArgPos--;
                switch(argType) {
                case ufmt_count:
                    /* set the spec's width to the # of chars written */
                    info->fWidth = *written;
                    /* fall through to set the pointer */
                    U_FALLTHROUGH;
                case ufmt_string:
                case ufmt_ustring:
                case ufmt_pointer:
                    args.ptrValue = arglist[spec.fArgPos].ptrValue;
                    break;
                case ufmt_char:
                case ufmt_uchar:
                case ufmt_int:
                    args.int64Value = arglist[spec.fArgPos].int64Value;
                    break;
                case ufmt_float:
                    args.floatValue = arglist[spec.fArgPos].floatValue;
                    break;
                case ufmt_double:
                    args.doubleValue = arglist[spec.fArgPos].doubleValue;
                    break;
                default:
                    /* else args is ignored */
                    args.ptrValue = nullptr;
                    break;
                }
            } else { /* no positional argument specified */
                switch(argType) {
                case ufmt_count:
                    /* set the spec's width to the # of chars written */
                    info->fWidth = *written;
                    /* fall through to set the pointer */
                    U_FALLTHROUGH;
                case ufmt_string:
                case ufmt_ustring:
                case ufmt_pointer:
                    args.ptrValue = va_arg(ap, void*);
                    break;
                case ufmt_char:
                case ufmt_uchar:
                case ufmt_int:
                    if (info->fIsLongLong) {
                        args.int64Value = va_arg(ap, int64_t);
                    }
                    else {
                        args.int64Value = va_arg(ap, int32_t);
                    }
                    break;
                case ufmt_float:
                    args.floatValue = (float) va_arg(ap, double);
                    break;
                case ufmt_double:
                    args.doubleValue = va_arg(ap, double);
                    break;
                default:
                    /* else args is ignored */
                    args.ptrValue = nullptr;
                    break;
                }
            }

            /* call the handler function */
            handler = g_u_printf_infos[ handlerNum ].handler;
            if (handler != nullptr) {
                *written += (*handler)(streamHandler, context, formatBundle, info, &args);
            }
            else {
                /* just echo unknown tags */
                *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
            }
        }
        else {
            /* just echo unknown tags */
            *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
        }
    }
    /* delete parsed argument list */
    if (arglist != nullptr) {
        uprv_free(arglist);
    }
    /* return # of characters in this format that have been parsed. */
    return (int32_t)(alias - fmt);
}

#endif /* #if !UCONFIG_NO_FORMATTING */

Messung V0.5
C=84 H=94 G=88

¤ Dauer der Verarbeitung: 0.64 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.