From b97093e58c574638e888dfbdcd1b3a0384704a3a Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Mon, 20 Jun 2022 18:25:12 -0700 Subject: [PATCH] Fix calc man page \-escape, add cal/comma.cal Fixed a \-escape bug in calc(1) man page. Added cal/comma.cal: 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. --- CHANGES | 59 +++++++ cal/Makefile | 6 +- cal/README | 58 +++++++ cal/comma.cal | 426 ++++++++++++++++++++++++++++++++++++++++++++++++++ calc.man | 2 +- 5 files changed, 547 insertions(+), 4 deletions(-) create mode 100644 cal/comma.cal diff --git a/CHANGES b/CHANGES index 2abad25..c7deec6 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,65 @@ The following are the changes from calc version 2.14.1.0 to date: Adjusted cal/test8900.cal to reflect this bug fix. Added tests to cal/regress.cal to help verify bug fix is fixed. + Fixed a \-escape bug in calc(1) man page. + + Added cal/comma.cal: + + 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. + The following are the changes from calc version 2.14.0.15 to 2.14.0.15: diff --git a/cal/Makefile b/cal/Makefile index 6ffa16c..4bdff7f 100644 --- a/cal/Makefile +++ b/cal/Makefile @@ -267,9 +267,9 @@ TRUE= true # CALC_FILES= README alg_config.cal beer.cal bernoulli.cal \ bernpoly.cal bigprime.cal bindings brentsolve.cal chi.cal chrem.cal \ - constants.cal deg.cal dms.cal dotest.cal ellip.cal factorial.cal \ - factorial2.cal gvec.cal hello.cal hms.cal infinities.cal intfile.cal \ - intnum.cal lambertw.cal linear.cal lnseries.cal lucas.cal \ + comma.cal constants.cal deg.cal dms.cal dotest.cal ellip.cal \ + factorial.cal factorial2.cal gvec.cal hello.cal hms.cal infinities.cal \ + intfile.cal intnum.cal lambertw.cal linear.cal lnseries.cal lucas.cal \ lucas_chk.cal mersenne.cal mfactor.cal mod.cal natnumset.cal \ palindrome.cal pell.cal pi.cal pix.cal pollard.cal poly.cal prompt.cal \ psqrt.cal qtime.cal quat.cal randbitrun.cal randmprime.cal \ diff --git a/cal/README b/cal/README index 65aeb7c..c456890 100644 --- a/cal/README +++ b/cal/README @@ -263,6 +263,64 @@ chrem.cal Chinese remainder theorem/problem solver. +comma.cal + + 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. + + deg.cal deg(deg, min, sec) diff --git a/cal/comma.cal b/cal/comma.cal new file mode 100644 index 0000000..ca4135a --- /dev/null +++ b/cal/comma.cal @@ -0,0 +1,426 @@ +/* + * 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 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 3-digit group separator (def: ",") + * decimal separator between decimal integer and decimal fraction (def: ".") + * + * 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 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 + */ + int_str = strprintf("%d", integer); + frac_str = strprintf("%f", fraction); + + /* + * 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 separator + */ + ret += decimal_separator; + + /* + * add remaining digits + * + * Skip over the leading 0. in frac_str + */ + ret += substr(frac_str, 3, frac_len-2); + } + + /* + * All Done!!! -- Jessica Noll, Age 2 + */ + return ret; +} + + +/* + * set_default_group_separator - change the default integer-fraction 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 is group is a string + */ + if (isstr(group)) { + default_group_separator = group; + } + return old_default_group_separator; +} + + +/* + * set_default_decimal_separator - change the default 3-digit decimal separator + * + * If decimal is not a string, then the default 3-digit decimal separator + * is not changed. Thus, this will only return the default 3-digit decimal separator: + * + * set_default_decimal_separator(null()); + * + * given: + * + * decimal separator between decimal integer and decimal fraction (def: ".") + * + * returns: + * + * previous 3-digit decimal separator value + */ +define set_default_decimal_separator(decimal) +{ + local old_default_decimal_separator; /* previous default 3-digit decimal separator */ + + /* + * save current 3-digit decimal separator + */ + old_default_decimal_separator = default_decimal_separator; + + /* + * change 3-digit decimal separator is 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 3-digit group separator (def: ",") + * decimal separator between decimal integer and decimal fraction (def: ".") + * + * 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 separators + + /* + * convert to string + */ + ret = str_comma(x, group, decimal); + + /* + * print converted string + */ + if (isstr(ret)) { + printf("%s\n", ret); + } + return ret; +} + + +/* + * print_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. + * + * NOTE: To print with a newline, use print_comma(x, group, decimal). + * + * given: + * fd open file + * x number to convert + * + * optional args: + * + * group 3-digit group separator (def: ",") + * decimal separator between decimal integer and decimal fraction (def: ".") + * + * 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 fprint_comma(fd, x, group, decimal) +{ + local ret; /* base 10 string with 3-digit group separators + + /* + * convert to string + */ + ret = str_comma(x, group, decimal); + + /* + * print converted string + */ + if (isstr(ret) && isfile(fd)) { + fprintf(fd, "%s\n", ret); + } + return ret; +} diff --git a/calc.man b/calc.man index 34e2f7f..353752e 100644 --- a/calc.man +++ b/calc.man @@ -596,7 +596,7 @@ may have to be replaced by: .sp 1 .in +5n .nf -print 27! ^2 or print 27\!^2 +print 27! ^2 or print 27\\!^2 .fi .in -5n