mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Converted all ASCII tabs to ASCII spaces using a 8 character tab stop, for all files, except for all Makefiles (plus rpm.mk). The `git diff -w` reports no changes.
438 lines
13 KiB
Plaintext
438 lines
13 KiB
Plaintext
/*
|
|
* comma - convert numbers into strings with 3-digit group and integer-fraction separators
|
|
*
|
|
* Convert numbers into strings with 3-digit group and integer-fraction separators.
|
|
*
|
|
* If the value is an integer, the integer-fraction separator is not used.
|
|
*
|
|
* str_comma(x, [group, [decimal]])
|
|
*
|
|
* Convert x into a string.
|
|
*
|
|
* If group is given and is a string, group will be used as
|
|
* the 3-digit group separator, otherwise the default 3-digit
|
|
* group separator will be used.
|
|
*
|
|
* If decimal is given and is a string, group will be used as
|
|
* the integer-fraction separator, otherwise the default
|
|
* integer-fraction separator will be used.
|
|
*
|
|
* The decimal and group arguments are optional.
|
|
*
|
|
* set_default_group_separator(group)
|
|
*
|
|
* Change the default 3-digit group separator if group is a string,
|
|
* otherwise the default 3-digit group separator will not be
|
|
* changed. Return the old 3-digit group separator.
|
|
*
|
|
* set_default_decimal_separator(decimal)
|
|
*
|
|
* Change the default 3-digit group separator if decimal is a
|
|
* string, otherwise the default integer-fraction separator
|
|
* will not be changed. Return the old integer-fraction separator.
|
|
*
|
|
* print_comma(x, [group, [decimal]])
|
|
*
|
|
* Print the value produced by str_comma(x, [group, [decimal]])
|
|
* followed by a newline.
|
|
*
|
|
* If the str_comma() does not return a string, nothing is printed.
|
|
*
|
|
* The decimal and group arguments are optional.
|
|
*
|
|
* The value produced by str_comma() is returned.
|
|
*
|
|
* fprint_comma(fd, x, [group, [decimal]])
|
|
*
|
|
* Print the value produced by str_comma(x, [group, [decimal]]),
|
|
* without a trailing newline, on file fd.
|
|
*
|
|
* If the str_comma() does not return a string, nothing is printed.
|
|
*
|
|
* If fd is not an open file, nothing is printed.
|
|
*
|
|
* The decimal and group arguments are optional.
|
|
*
|
|
* The value produced by str_comma() is returned.
|
|
*
|
|
* Copyright (C) 2022 Landon Curt Noll
|
|
*
|
|
* Calc is open software; you can redistribute it and/or modify it under
|
|
* the terms of the version 2.1 of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
* Public License for more details.
|
|
*
|
|
* A copy of version 2.1 of the GNU Lesser General Public License is
|
|
* distributed with calc under the filename COPYING-LGPL. You should have
|
|
* received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Under source code control: 2022/06/20 15:51:49
|
|
* File existed as early as: 2022
|
|
*
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
|
|
static default_group_separator = ","; /* default 3-digit group separator */
|
|
static default_decimal_separator = "."; /* default integer-fraction separator */
|
|
|
|
|
|
/*
|
|
* str_comma - convert number into base 10 string with 3-digit groups and integer-fraction separator
|
|
*
|
|
*
|
|
* This function converts a real number into a base 10 string, where
|
|
* groups of 3 digits are separated by a 3-digit group separator and
|
|
* a integer-fraction separator is printed between integer and decimal fraction.
|
|
*
|
|
* For example:
|
|
*
|
|
* string = str_comma(x);
|
|
* string = str_comma(x), " ", ".");
|
|
* string = str_comma(x), ".", ",");
|
|
*
|
|
* Internally the function calls:
|
|
*
|
|
* strprintf("%f", x);
|
|
*
|
|
* and thus the number of decimal fraction digits is subject to
|
|
* the display() or config("display") value. See:
|
|
*
|
|
* man display
|
|
*
|
|
* for details.
|
|
*
|
|
* given:
|
|
*
|
|
* x number to convert
|
|
*
|
|
* optional args:
|
|
*
|
|
* group use this 3-digit group separator
|
|
* decimal use this integer-fraction separator
|
|
*
|
|
* returns:
|
|
*
|
|
* string containing the base 10 digits with group and decimal separators, OR
|
|
* null() if x is not a number, OR
|
|
* null() if group is neither null() (not given) nor a string, OR
|
|
* null() if group is null() (not given) AND default_group_separator is not a string, OR
|
|
* null() if decimal is neither null() (not given) nor a string, OR
|
|
* null() if decimal is null() (not given) AND default_decimal_separator is not a string.
|
|
*/
|
|
define str_comma(x, group, decimal)
|
|
{
|
|
local group_separator; /* 3-digit group separator */
|
|
local decimal_separator; /* separator between decimal integer and decimal fraction */
|
|
local sign_str; /* leading - if x < 0 or empty if x >= 0 */
|
|
local integer; /* integer part of absolute value of x */
|
|
local int_str; /* integer as a string */
|
|
local int_len; /* number of digits in int_str */
|
|
local first_group_len; /* length of 1st group before the 1st 3-digit group separator */
|
|
local fraction; /* factional part of absolute value of x */
|
|
local frac_str; /* fraction as a string */
|
|
local frac_len; /* number of digits in frac_str including leading 0. */
|
|
local ret; /* string to return */
|
|
local config_leadzero; /* config("leadzero") to restore */
|
|
local config_tilde; /* config("tilde") to restore */
|
|
local i;
|
|
|
|
/*
|
|
* parse args - return null if args are bogus
|
|
*
|
|
* Return null() if args or conditions are bogus.
|
|
*/
|
|
if (!isreal(x)) {
|
|
return null();
|
|
}
|
|
group_separator = isnull(group) ? default_group_separator : group;
|
|
decimal_separator = isnull(decimal) ? default_decimal_separator : decimal;
|
|
if (!isstr(group_separator)) {
|
|
return null();
|
|
}
|
|
if (!isstr(decimal_separator)) {
|
|
return null();
|
|
}
|
|
|
|
/*
|
|
* split number
|
|
*/
|
|
if (x < 0) {
|
|
sign_str = "-";
|
|
integer = int(-x);
|
|
fraction = frac(-x);
|
|
} else {
|
|
sign_str = "";
|
|
integer = int(x);
|
|
fraction = frac(x);
|
|
}
|
|
ret = sign_str;
|
|
|
|
/*
|
|
* convert digits
|
|
*
|
|
* Avoid printing ~ and leading zeros for factional part.
|
|
*/
|
|
int_str = strprintf("%d", integer);
|
|
config_leadzero = config("leadzero", 0);
|
|
config_tilde = config("tilde", 0);
|
|
frac_str = strprintf("%d", fraction);
|
|
config("leadzero", config_leadzero),;
|
|
config("tilde", config_tilde),;
|
|
|
|
/*
|
|
* determine number of digits in the integer part
|
|
*/
|
|
int_len = strlen(int_str);
|
|
frac_len = strlen(frac_str);
|
|
|
|
/*
|
|
* form integer part with group separators as needed
|
|
*/
|
|
|
|
/*
|
|
* case: integer is 3 or fewer digits
|
|
*/
|
|
if (integer < 1000) {
|
|
ret += int_str;
|
|
|
|
/*
|
|
* case: integer is 4 or more digits
|
|
*/
|
|
} else {
|
|
|
|
/*
|
|
* form a decimal string using group separators
|
|
*/
|
|
|
|
/*
|
|
* form the initial leading digits before 1st group separator
|
|
*/
|
|
first_group_len = int_len % 3;
|
|
if (first_group_len == 0) {
|
|
first_group_len = 3;
|
|
}
|
|
ret += substr(int_str, 1, first_group_len);
|
|
|
|
/*
|
|
* until end of digits, print group separator followed by 3 more digits
|
|
*/
|
|
for (i = first_group_len+1; i < int_len; i += 3) {
|
|
ret += group_separator + substr(int_str, i, 3);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* form fractional part using decimal separator as needed
|
|
*/
|
|
|
|
/*
|
|
* case: x is an integer
|
|
*/
|
|
if (fraction == 0) {
|
|
|
|
/* no fraction, nothing more to do */
|
|
|
|
/*
|
|
* case: x is not an integer
|
|
*/
|
|
} else {
|
|
|
|
/*
|
|
* add integer-fraction separator
|
|
*/
|
|
ret += decimal_separator;
|
|
|
|
/*
|
|
* add remaining digits
|
|
*
|
|
* Skip over the leading 0. in frac_str
|
|
*/
|
|
ret += substr(frac_str, 2, frac_len-1);
|
|
}
|
|
|
|
/*
|
|
* All Done!!! -- Jessica Noll, Age 2
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* set_default_group_separator - change the default 3-digit group separator
|
|
*
|
|
* If group is not a string, then the default 3-digit group separator
|
|
* is not changed. Thus, this will only return the default 3-digit group separator:
|
|
*
|
|
* set_default_group_separator(null());
|
|
*
|
|
* given:
|
|
*
|
|
* group 3-digit group separator
|
|
*
|
|
* returns:
|
|
*
|
|
* previous 3-digit group separator value
|
|
*/
|
|
define set_default_group_separator(group)
|
|
{
|
|
local old_default_group_separator; /* previous default 3-digit group separator to return */
|
|
|
|
/*
|
|
* save current 3-digit group separator
|
|
*/
|
|
old_default_group_separator = default_group_separator;
|
|
|
|
/*
|
|
* change 3-digit group separator if group is a string
|
|
*/
|
|
if (isstr(group)) {
|
|
default_group_separator = group;
|
|
}
|
|
return old_default_group_separator;
|
|
}
|
|
|
|
|
|
/*
|
|
* set_default_decimal_separator - change the default integer-fraction separator
|
|
*
|
|
* If decimal is not a string, then the default integer-fraction separator
|
|
* is not changed. Thus, this will only return the integer-fraction separator:
|
|
*
|
|
* set_default_decimal_separator(null());
|
|
*
|
|
* given:
|
|
*
|
|
* decimal separator between decimal integer and decimal fraction (def: ".")
|
|
*
|
|
* returns:
|
|
*
|
|
* previous integer-fraction separator value
|
|
*/
|
|
define set_default_decimal_separator(decimal)
|
|
{
|
|
local old_default_decimal_separator; /* previous default integer-fraction separator */
|
|
|
|
/*
|
|
* save current integer-fraction separator
|
|
*/
|
|
old_default_decimal_separator = default_decimal_separator;
|
|
|
|
/*
|
|
* change 3-digit decimal integer-fraction if decimal is a string
|
|
*/
|
|
if (isstr(decimal)) {
|
|
default_decimal_separator = decimal;
|
|
}
|
|
return old_default_decimal_separator;
|
|
}
|
|
|
|
|
|
/*
|
|
* print_comma - print base 10 string with 3-digit group separators & integer-fraction separator + newline
|
|
*
|
|
* This function prints the result of str_comma(x, group, decimal) followed by a newline.
|
|
* For example:
|
|
*
|
|
* print_comma(x);
|
|
* print_comma(x), " ", ".");
|
|
* print_comma(x), ".", ",");
|
|
*
|
|
* If str_comma() does not return a string, this function prints nothing.
|
|
*
|
|
* NOTE: To print without a newline, use fprint_comma(fd, x, group, decimal).
|
|
*
|
|
* given:
|
|
* x number to convert
|
|
*
|
|
* optional args:
|
|
*
|
|
* group use this 3-digit group separator
|
|
* decimal use this integer-fraction separator
|
|
*
|
|
* returns:
|
|
*
|
|
* string containing the base 10 digits with group and decimal separators, OR
|
|
* null() if x is not a number, OR
|
|
* null() if group is neither null() (not given) nor a string, OR
|
|
* null() if group is null() (not given) AND default_group_separator is not a string, OR
|
|
* null() if decimal is neither null() (not given) nor a string, OR
|
|
* null() if decimal is null() (not given) AND default_decimal_separator is not a string.
|
|
*/
|
|
define print_comma(x, group, decimal)
|
|
{
|
|
local ret; /* base 10 string with 3-digit group and integer-fraction separators */
|
|
|
|
/*
|
|
* convert to string
|
|
*/
|
|
ret = str_comma(x, group, decimal);
|
|
|
|
/*
|
|
* print converted string
|
|
*/
|
|
if (isstr(ret)) {
|
|
printf("%s\n", ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* fprint_comma - print base 10 string with 3-digit group separators & integer-fraction separator w/o newline
|
|
*
|
|
* This function prints the result of str_comma(x, group, decimal) on an open file, without a trailing newline.
|
|
* For example:
|
|
*
|
|
* fprint_comma(files(1), x);
|
|
* fprint_comma(fd, x), " ", ".");
|
|
* fprint_comma(files(2), x), ".", ",");
|
|
*
|
|
* If str_comma() does not return a string, this function prints nothing.
|
|
*
|
|
* This function flushes output to the open file before returning.
|
|
*
|
|
* NOTE: To print with a newline, use print_comma(x, group, decimal).
|
|
*
|
|
* given:
|
|
* fd open file
|
|
* x number to convert
|
|
*
|
|
* optional args:
|
|
*
|
|
* group use this 3-digit group separator
|
|
* decimal use this integer-fraction separator
|
|
*
|
|
* returns:
|
|
*
|
|
* string containing the base 10 digits with group and integer-fraction separators, OR
|
|
* null() if x is not a number, OR
|
|
* null() if group is neither null() (not given) nor a string, OR
|
|
* null() if group is null() (not given) AND default_group_separator is not a string, OR
|
|
* null() if decimal is neither null() (not given) nor a string, OR
|
|
* null() if decimal is null() (not given) AND default_decimal_separator is not a string.
|
|
*/
|
|
define fprint_comma(fd, x, group, decimal)
|
|
{
|
|
local ret; /* base 10 string with 3-digit group and integer-fraction separators */
|
|
|
|
/*
|
|
* convert to string
|
|
*/
|
|
ret = str_comma(x, group, decimal);
|
|
|
|
/*
|
|
* print converted string
|
|
*/
|
|
if (isstr(ret) && isfile(fd)) {
|
|
fprintf(fd, "%s", ret);
|
|
fflush(fd);
|
|
}
|
|
return ret;
|
|
}
|