📄 sflcvsn.c
字号:
/* ----------------------------------------------------------------<Prolog>-
Name: sflcvsn.c
Title: Converts a string to a number
Package: Standard Function Library (SFL)
Written: 1996/01/05 iMatix SFL project team <sfl@imatix.com>
Revised: 1997/09/08
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 "sflconv.h" /* Prototypes for functions */
/* ---------------------------------------------------------------------[<]-
Function: conv_str_number
Synopsis: Converts a string to a number. The number format is defined
by one or more of these flags (you add them to get a flags argument):
<TABLE>
FLAG_N_SIGNED Number is signed.
FLAG_N_DECIMALS Number has decimals.
FLAG_N_ZERO_FILL Number has leading zeros.
FLAG_N_THOUSANDS Number has thousands-separators.
</TABLE>
The input string may contain digits, decimal point, thousand separators
and a sign character or indicator. Formatting characters are only
accepted if they correspond to the number format. A blank string is
accepted as zero. A space following digits ends the number; anything
further is ignored.
Returns a string of width digits, including leading sign if that is
required. Zeroes are signed with a space. Width must be at least 1.
If the flag FLAG_N_DECIMALS is set, the last X digits are decimals,
where X is the value of the decimals argument. Decimals are then
accepted or rejected depending on the dec_format:
<TABLE>
DECS_SHOW_ALL Accept decimals.
DECS_DROP_ZEROS Accept decimals.
DECS_HIDE_ALL Reject decimals.
DECS_SCIENTIFIC Accept decimals.
</TABLE>
If the flag FLAG_N_SIGNED is set, accepts a leading or trailing sign,
or a financial negative like this: (123).
Returns a pointer to the formatted string, or null if the string was
rejected. These are the possible reasons for rejection:
<LIST>
- input number is too large for specified width;
- input number is signed when no sign is allowed;
- input number decimals when none are allowed;
- input number has more decimals than are allowed;
- more than one sign character in number;
- malformed financial negative '(123)';
- more than one decimal point in number;
- thousand seps when FLAG_N_THOUSANDS is cleared or FLAG_N_ZERO_FILL
is set (this overrides FLAG_N_THOUSANDS);
- junk in input string (unrecognised character).
</LIST>
---------------------------------------------------------------------[>]-*/
char *
conv_str_number (
const char *string, /* String to convert */
int flags, /* Number field 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, > 0 */
)
{
static char
number [FORMAT_MAX + 1]; /* Cleaned-up return string */
int
digits, /* Number of digits read so far */
decs_wanted = decimals; /* Number of decimals wanted */
char
*dest, /* Store formatted number here */
sign_char, /* Number's sign: ' ', '+', '-' */
sep_char, /* Thousands separator '.' or ',' */
decs_seen, /* Number of decimals output */
ch; /* Next character in picture */
Bool
have_point, /* Have we seen a decimal point */
have_zero, /* TRUE if number is all zero */
end_loop; /* Flag to break out of scan loop */
ASSERT (width <= FORMAT_MAX);
ASSERT (width > 0);
ASSERT (dec_point == '.' || dec_point == ',');
conv_reason = 0; /* No conversion errors so far */
/* --------------------------------- Prepare to copy digits ---------*/
if ((flags & FLAG_N_THOUSANDS) && !(flags & FLAG_N_ZERO_FILL))
sep_char = dec_point == '.'? ',': '.';
else
sep_char = ' '; /* Reject any thousands separator */
/* --------------------------------- Copy the digits ----------------*/
digits = 0; /* No digits loaded yet */
decs_seen = 0; /* No decimals output yet */
sign_char = ' '; /* Final sign character '+' or '-' */
end_loop = FALSE; /* Flag to break out of scan loop */
have_point = FALSE; /* No decimal point seen */
have_zero = TRUE; /* So far, it's zero */
dest = number; /* Scan through number */
while (*string)
{
ch = *string++;
switch (ch)
{
case '9':
case '8':
case '7':
case '6':
case '5':
case '4':
case '3':
case '2':
case '1':
have_zero = FALSE;
case '0':
digits++;
*dest++ = ch;
if (have_point)
++decs_seen;
break;
case '-':
case '+':
case '(':
if (sign_char != ' ')
{
conv_reason = CONV_ERR_MULTIPLE_SIGN;
return (NULL); /* More than one sign char */
}
else
if (flags & FLAG_N_SIGNED)
sign_char = ch;
else
{
conv_reason = CONV_ERR_SIGN_REJECTED;
return (NULL); /* Number may not be signed */
}
break;
case ')':
if (sign_char == '(')
sign_char = '-';
else
{
conv_reason = CONV_ERR_SIGN_BAD_FIN;
return (NULL); /* Malformed financial negative */
}
break;
case ' ': /* Space ends number after digits */
end_loop = (digits > 0);
break;
default:
if (ch == dec_point)
{
if (have_point)
{
conv_reason = CONV_ERR_MULTIPLE_POINT;
return (NULL); /* More than one decimal point */
}
else
if (flags & FLAG_N_DECIMALS)
have_point = TRUE;
else
{
conv_reason = CONV_ERR_DECS_REJECTED;
return (NULL); /* No decimals are allowed */
}
}
else
if (ch != sep_char) /* We allow sep chars anywhere */
{
conv_reason = CONV_ERR_INVALID_INPUT;
return (NULL); /* else we have junk */
}
}
if (end_loop)
break;
}
/* --------------------------------- Post-format the result ---------*/
if (flags & FLAG_N_DECIMALS)
{
ASSERT (width > decs_wanted); /* At least decimals + 1 digit */
if (dec_format == DECS_HIDE_ALL)
{
if (have_point)
{
conv_reason = CONV_ERR_DECS_HIDDEN;
return (NULL); /* No decimals are allowed */
}
}
while (decs_seen < decs_wanted) /* Supply missing decimals */
{
digits++;
*dest++ = '0';
decs_seen++;
}
if (decs_seen > decs_wanted)
{
conv_reason = CONV_ERR_DECS_OVERFLOW;
return (NULL); /* More decimals than allowed */
}
}
else
decs_wanted = 0;
*dest = 0; /* Terminate the string nicely */
if (digits > width)
{
conv_reason = CONV_ERR_TOO_MANY_DIGITS;
return (NULL); /* Overflow -- number too large */
}
/* Supply leading zeroes */
if (digits < width)
{
/* Shift number and null to right of field */
memmove (number + (width - digits), number, digits + 1);
memset (number, '0', width - digits);
}
/* Store sign if necessary */
if (flags & FLAG_N_SIGNED)
{
ASSERT (width > 1); /* At least sign + 1 digit */
if (number [0] != '0')
{
conv_reason = CONV_ERR_TOO_MANY_DIGITS;
return (NULL); /* Overflow -- no room for sign */
}
if (sign_char == '(')
{
conv_reason = CONV_ERR_SIGN_BAD_FIN;
return (NULL); /* Malformed financial negative */
}
else
if (sign_char == ' ')
sign_char = '+';
if (have_zero)
number [0] = ' '; /* Store sign */
else
number [0] = sign_char;
}
return (number);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -