⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sflcvns.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
字号:
/*  ----------------------------------------------------------------<Prolog>-
    Name:       sflcvns.c
    Title:      Converts a number to a string
    Package:    Standard Function Library (SFL)

    Written:    1996/01/05  iMatix SFL project team <sfl@imatix.com>
    Revised:    1999/09/29

    Copyright:  Copyright (c) 1996-2000 iMatix Corporation
    License:    This is free software; you can redistribute it and/or modify
                it under the terms of the SFL License Agreement as provided
                in the file LICENSE.TXT.  This software is distributed in
                the hope that it will be useful, but without any warranty.
 ------------------------------------------------------------------</Prolog>-*/

#include "prelude.h"                    /*  Universal header file            */
#include "sflstr.h"                     /*  String functions                 */
#include "sflconv.h"                    /*  Prototypes for functions         */


/*  ---------------------------------------------------------------------[<]-
    Function: conv_number_str

    Synopsis: Converts a number to a string.  The number format is defined
    largely by the flags argument, which can specify various values defined
    in sflconv.h:
    <TABLE>
        FLAG_N_SIGNED       Show signed number, using sign_format argument.
        FLAG_N_DECIMALS     Show decimals, using dec_format argument.
        FLAG_N_LEFT         Left-justify number; no effect if width is 0.
        FLAG_N_ZERO_FILL    Right-justfified, with leading zeroes.
        FLAG_N_ZERO_BLANK   Show zero as empty string or spaces (width > 0).
        FLAG_N_THOUSANDS    Show number with thousands separators.
    </TABLE>

    Sign formats:
    <TABLE>
        SIGN_NEG_TRAIL          Negative numbers only: 123-
        SIGN_ALL_TRAIL          All non-zero numbers:  123- 123+
        SIGN_NEG_LEAD           Negative numbers only: -123
        SIGN_ALL_LEAD           All non-zero numbers:  -123 +123
        SIGN_FINANCIAL          Negative numbers only: (123)
    </TABLE>

    Decimal formats:
    <TABLE>
        DECS_SHOW_ALL           123.10, 123.00, 0.95
        DECS_DROP_ZEROS         123.1, 123, 0.95
        DECS_HIDE_ALL           123, 123, 0
        DECS_PERCENTAGE         12300, 12300, 95
        DECS_SCIENTIFIC         1.231e2, 1.23e2, 9.5e-1
    </TABLE>

    The input number string may contain leading zeros and a leading sign
    character (space, '+', '-') if signed.  These are examples of valid
    8-digit numbers: "1234" "00001234" "12345678" "+12345678".

    If the flag FLAG_N_DECIMALS is set, the last X digits are taken to be
    decimals, where X is the value of the decimals argument.  If the number
    contains a decimal point (always '.'), this is taken to indicate the
    start of the decimal part.

    The formatted number is placed within a field of specified width.  If
    the number is right-justfied, this means it may have leading spaces.
    If the field width is 0, the number will never have leading spaces.
    Returns a pointer to the formatted string, or NULL if the specified
    width is too small for formatted number or the supplied number does
    not contain enough digits.
    ---------------------------------------------------------------------[>]-*/

char *
conv_number_str (
    const char *number,                 /*  Number to convert                */
    int   flags,                        /*  Number formatting flags          */
    char  dec_point,                    /*  Decimal point: '.' or ','        */
    int   decimals,                     /*  Number of decimals, or 0         */
    int   dec_format,                   /*  How are decimals shown?          */
    int   width,                        /*  Output field width, or 0         */
    int   sign_format                   /*  How are negatives shown?         */
)
{
    static char
        formatted [FORMAT_MAX + 1],     /*  Formatted return string          */
        zero [CONV_MAX_DECS + 2];       /*  Default value if needed          */
    int
        sep_stop,                       /*  Where we put next sep_char       */
        dec_stop,                       /*  Where we put decimal point       */
        decs_wanted = decimals,         /*  Number of decimals wanted        */
        decs_seen,                      /*  Number of decimals output        */
        sign_pos,                       /*  Where we put sign, if any        */
        digits;                         /*  Number of digits read so far     */
    char
       *dest,                           /*  Store formatted number here      */
        sign_char,                      /*  Number's sign: ' ', '+', '-'     */
        sep_char,                       /*  Thousands separator '.' or ','   */
        drop_zero,                      /*  We suppress this char            */
        ch;                             /*  Next character in picture        */
    Bool
        have_zero;                      /*  TRUE if whole number is zero     */

    ASSERT (width <= FORMAT_MAX);
    ASSERT (dec_point == '.' || dec_point == ',');

    conv_reason = 0;                    /*  No conversion errors so far      */

    /*  ---------------------------------   Prepare to copy digits  ---------*/

    if (decs_wanted > CONV_MAX_DECS)
      {
        conv_reason = CONV_ERR_DECS_OVERFLOW;
        return (NULL);                  /*  Error - too many decimals        */
      }
    /*  If value is empty, use "0" with enough decimals as default value     */
    /*  We allow one whole digit and as many decimals as needed.             */
    if (strnull (number))
      {
        strpad (zero, '0', decs_wanted + 1);
        number = zero;
      }

    /*  Pick-up sign character if present                                    */
    if (*number == ' ' || *number == '+' || *number == '-')
        sign_char = *number++;
    else
        sign_char = ' ';

    /*  While leading zero is '0' we blank-out zeros in the number           */
    drop_zero = (char) (flags & FLAG_N_ZERO_FILL? ' ': '0');

    /*  Prepare for decimals                                                 */
    if ((flags & FLAG_N_DECIMALS) == 0)
        decs_wanted = 0;

    if (strchr (number, '.'))
        dec_stop = (int) (strchr (number, '.') - (char *) number);
    else
        dec_stop = strlen (number) - decs_wanted;

    if (dec_stop < 1)
      {
        conv_reason = CONV_ERR_DECS_MISSING;
        return (NULL);                  /*  Error - too few decimals         */
      }

    /*  Prepare for thousands-separators if FLAG_N_THOUSANDS                 */
    if ((flags & FLAG_N_THOUSANDS) && !(flags & FLAG_N_ZERO_FILL))
      {
        /*  Get number of whole digits, allowing for decimals & dec sign     */
        sep_char = (char) (dec_point == '.'? ',': '.');
        sep_stop = (dec_stop - (decs_wanted? decs_wanted + 1: 0)) % 3;
        if (sep_stop == 0)
            sep_stop = 3;               /*  Get into range 1..3              */
      }
    else
      {
        sep_char = ' ';
        sep_stop = 0;                   /*  No thousands separators          */
      }

    /*  ---------------------------------   Copy the digits  ----------------*/

    digits    = 0;                      /*  No digits loaded yet             */
    decs_seen = 0;                      /*  No decimals output yet           */
    have_zero = TRUE;                   /*  Assume number is zero            */
    dest      = formatted;              /*  Format number                    */
    while (*number)                     /*    until we hit the terminator    */
      {
        ch = *number++;
        if (ch == '.')
            continue;                   /*  Ignore '.' in number             */

        digits++;

        if (ch == drop_zero && digits < dec_stop)
            ch = ' ';
        else
        if (isdigit (ch))
          {
            drop_zero = ' ';
            if (ch > '0')
                have_zero = FALSE;
          }
        if (ch != ' ' || (width > 0 && !(flags & FLAG_N_LEFT)))
          {
            *dest++ = ch;               /*  Output this digit                */
            if (digits > dec_stop)
                decs_seen++;            /*  Count the decimal digit          */
            else
            if (digits == dec_stop)     /*  Handle decimal stop              */
              {                         /*    with optional point            */
                if (flags & FLAG_N_DECIMALS)
                    *dest++ = dec_point;
                sep_stop = 0;           /*  And kill further thousand seps   */
              }
          }
        /*  Output thousands separator unless we are in blank area           */
        if (digits == sep_stop)
          {
            if (ch != ' ')
                *dest++ = sep_char;
            sep_stop += 3;
          }
      }
    *dest = 0;                          /*  Terminate the string nicely      */
    /*  ---------------------------------   Post-format the result  ---------*/

    if (decs_wanted > 0)
      {
        /*  Output trailing decimal zeroes if not supplied                   */
        if (decs_seen == 0)
            *dest++ = dec_point;
        while (decs_seen < decs_wanted)
          {
            *dest++ = '0';
            decs_seen++;
          }
        /*  Drop all decimals if format is DEC_HIDE_ALL                      */
        if (dec_format == DECS_HIDE_ALL)
            while (*dest != dec_point)
                dest--;                 /*  Drop-off trailing zero           */
        else
        /*  Drop trailing decimal zeroes if format is DEC_DROP_ZEROS         */
        if (dec_format == DECS_DROP_ZEROS)
            while (*dest != dec_point)
              {
                if (*(dest - 1) > '0')
                    break;
                else
                    dest--;             /*  Drop-off trailing zero           */
              }
        *dest = 0;                      /*  Terminate the string nicely      */
      }

    /*  Justify within width if width > 0                                    */
    sign_pos = 0;                       /*  Sign normally comes at start     */
    digits   = strlen (formatted);
    if (flags & FLAG_N_SIGNED)
      {
        digits++;                       /*  Allow for eventual sign          */
        if (sign_format == SIGN_FINANCIAL)
            digits++;                   /*  Sign shown like (123)            */
      }
    while (digits < width)
      {
        if (flags & FLAG_N_LEFT && !(flags & FLAG_N_ZERO_FILL))
            strcat (formatted, " ");
        else
          {
            stropen (formatted, FALSE); /*  Insert blank at start of string  */
            if (flags & FLAG_N_ZERO_FILL)
                formatted [0] = '0';
            else
                sign_pos++;             /*  Skip leading space               */
          }
        digits++;
      }

    /*  Format sign if FLAG_N_SIGNED                                         */
    if (flags & FLAG_N_SIGNED)
      {
        if (sign_format == SIGN_NEG_LEAD
        ||  sign_format == SIGN_ALL_LEAD
        ||  sign_format == SIGN_FINANCIAL)
            stropen (formatted, FALSE);

        if (sign_format == SIGN_NEG_TRAIL
        ||  sign_format == SIGN_ALL_TRAIL
        ||  sign_format == SIGN_FINANCIAL)
            strcat (formatted, " ");

        if (!have_zero)                 /*  Zero has no sign                 */
            switch (sign_format)
              {
                case SIGN_NEG_LEAD:
                    if (sign_char != '-')
                        break;          /*  Fall through if negative sign    */
                case SIGN_ALL_LEAD:
                    formatted [sign_pos] = sign_char;
                    break;

                case SIGN_NEG_TRAIL:
                    if (sign_char != '-')
                        break;          /*  Fall through if negative sign    */
                case SIGN_ALL_TRAIL:
                    strlast (formatted) = sign_char;
                    break;

                case SIGN_FINANCIAL:
                    if (sign_char == '-')
                      {
                        formatted [0]       = '(';
                        strlast (formatted) = ')';
                      }
                    break;
              }
      }

    /*  If all zeroes, return a blank string if FLAG_N_ZERO_BLANK            */
    if ((flags & FLAG_N_ZERO_BLANK) && have_zero)
      {
        memset (formatted, ' ', width);
        formatted [width] = 0;
      }

    if (width > 0 && (strlen (formatted) > (size_t) width))
      {
        conv_reason = CONV_ERR_NUM_OVERFLOW;
        return (NULL);                  /*  Overflow -- number too large     */
      }
    else
        return (formatted);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -