Bash-5.3-rc1 release

This commit is contained in:
Chet Ramey
2025-04-07 12:36:49 -04:00
parent ee9645c4a0
commit c8f067a967
147 changed files with 11100 additions and 51295 deletions
+11 -3
View File
@@ -103,8 +103,8 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
ALLPROG = print truefalse sleep finfo logname basename dirname fdflags \
tty pathchk tee head mkdir rmdir mkfifo mktemp printenv id whoami \
uname sync push ln unlink realpath strftime mypid setpgid seq rm \
accept csv dsv cut stat getconf kv strptime
OTHERPROG = necho hello cat pushd asort
accept csv dsv cut stat getconf kv strptime chmod
OTHERPROG = necho hello cat pushd asort fltexpr
SUBDIRS = perl
@@ -238,6 +238,9 @@ strftime: strftime.o
strptime: strptime.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strptime.o $(SHOBJ_LIBS)
chmod: chmod.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ chmod.o $(SHOBJ_LIBS)
mypid: mypid.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mypid.o $(SHOBJ_LIBS)
@@ -250,6 +253,10 @@ stat: stat.o
asort: asort.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ asort.o $(SHOBJ_LIBS)
fltexpr: fltexpr.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ fltexpr.o $(SHOBJ_LIBS) -lm
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
@@ -315,7 +322,7 @@ OBJS = print.o truefalse.o accept.o sleep.o finfo.o getconf.o logname.o \
basename.o dirname.o tty.o pathchk.o tee.o head.o rmdir.o necho.o \
hello.o cat.o csv.o dsv.o kv.o cut.o printenv.o id.o whoami.o uname.o \
sync.o push.o mkdir.o mktemp.o realpath.o strftime.o setpgid.o stat.o \
fdflags.o seq.o asort.o strptime.o
fdflags.o seq.o asort.o strptime.o chmod.o
${OBJS}: ${BUILD_DIR}/config.h
@@ -336,6 +343,7 @@ rmdir.o: rmdir.c
necho.o: necho.c
hello.o: hello.c
cat.o: cat.c
chmod.o: chmod.c
csv.o: csv.c
dsv.o: dsv.c
kv.o: kv.c
+10 -7
View File
@@ -72,17 +72,18 @@ fcopy(int fd, char *fn)
int
cat_main (int argc, char **argv)
{
int i, fd, r;
int i, fd, r, closefd;
char *s;
if (argc == 1)
return (fcopy(0, "standard input"));
for (i = r = 1; i < argc; i++) {
for (i = 1, r = 0; i < argc; i++) {
QUIT;
if (argv[i][0] == '-' && argv[i][1] == '\0')
if (argv[i][0] == '-' && argv[i][1] == '\0') {
fd = 0;
else {
closefd = 0;
} else {
fd = open(argv[i], O_RDONLY, 0666);
if (fd < 0) {
s = strerror(errno);
@@ -91,11 +92,13 @@ cat_main (int argc, char **argv)
write(2, ": ", 2);
write(2, s, strlen(s));
write(2, "\n", 1);
r++;
continue;
}
closefd = 1;
}
r = fcopy(fd, argv[i]);
if (fd != 0)
r += fcopy(fd, argv[i]);
if (closefd)
close(fd);
}
QUIT;
@@ -113,7 +116,7 @@ cat_builtin(WORD_LIST *list)
r = cat_main(c, v);
free(v);
return r;
return r; /* relies on EXECUTION_SUCCESS being 0 */
}
char *cat_doc[] = {
+156
View File
@@ -0,0 +1,156 @@
/* chmod - change file mode bits */
/* See Makefile for compilation details. */
/*
Copyright (C) 2024-2025 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "bashtypes.h"
#include "posixstat.h"
#include <errno.h>
#include <stdio.h>
#include "bashansi.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
#include "common.h"
#if !defined (errno)
extern int errno;
#endif
#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
extern int parse_symbolic_mode (char *, mode_t);
#define STANDARD_BITS (S_IRWXU | S_IRWXG | S_IRWXO)
#define ALLBITS (STANDARD_BITS | S_ISUID| S_ISGID | S_ISVTX)
int
chmod_builtin (WORD_LIST *list)
{
int opt, nmode, lmode, rval;
char *mode;
struct stat st;
WORD_LIST *l;
reset_internal_getopt ();
mode = (char *)NULL;
while ((opt = internal_getopt(list, "fhvRHLP")) != -1)
switch (opt)
{
CASE_HELPOPT;
default:
return (EX_DISKFALLBACK);
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
mode = list->word->word;
list = list->next;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
nmode = -1;
if (ISOCTAL (*mode)) /* octal number */
{
nmode = read_octal (mode);
if (nmode < 0)
{
builtin_error ("invalid file mode: %s", mode);
return (EXECUTION_FAILURE);
}
}
else /* test for valid symbolic mode */
{
/* initial bits are a=rwx; the mode argument modifies them */
lmode = parse_symbolic_mode (mode, ALLBITS);
if (lmode < 0)
{
builtin_error ("invalid file mode: %s", mode);
return (EXECUTION_FAILURE);
}
}
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
{
lmode = nmode;
if (stat (l->word->word, &st) < 0)
{
builtin_error ("`%s': cannot stat: %s", l->word->word, strerror (errno));
rval = EXECUTION_FAILURE;
continue;
}
if (lmode == -1)
{
lmode = parse_symbolic_mode (mode, st.st_mode & ALLBITS);
if (lmode < 0)
{
builtin_error ("`%s': invalid file mode: %s", l->word->word, mode);
rval = EXECUTION_FAILURE;
continue;
}
}
if (chmod (l->word->word, lmode))
{
builtin_error ("`%s': cannot change mode: %s", l->word->word, strerror (errno));
rval = EXECUTION_FAILURE;
continue;
}
}
return rval;
}
char *chmod_doc[] = {
"Change file mode bits.",
"",
"Change file mode bits. Change the mode bits of files named as",
"arguments, in the order specified, as specified by MODE."
"The MODE argument may be an octal number or a symbolic mode like",
"that described in chmod(1). If a symbolic mode is used, the",
"operations are interpreted relative to an initial mode of \"a=rwx\".",
"",
"The return value is 0 unless an error occurs.",
(char *)NULL
};
struct builtin chmod_struct = {
"chmod",
chmod_builtin,
BUILTIN_ENABLED,
chmod_doc,
"chmod [-R] mode file [file...]",
0
};
File diff suppressed because it is too large Load Diff
+77 -24
View File
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
Copyright (C) 2023 Free Software Foundation, Inc.
Copyright (C) 2023-2025 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -87,16 +87,19 @@ static char * const date_time_formats[] =
"%F %r", /* YYYY-mm-dd HH:MM:SS p.m. */
"%F %R", /* YYYY-mm-dd HH:MM */
"%F %I:%M %p", /* YYYY-mm-dd HH:MM a.m. */
"%F", /* YYYY-mm-dd ISO8601 time */
"%T", /* HH:MM:SS */
"%H.%M.%S", /* HH.MM.SS */
/* From coreutils-9.2 date */
"%Y-%m-%dT%H:%M:%S%z", /* ISO8601 time */
"%Y-%m-%dT%H%z", /* ISO8601 time */
"%Y-%m-%dT%H:%M%z", /* ISO8601 time */
"%Y-%m-%dT%H:%M:%S%Z", /* ISO8601 time but with timezone name */
"%Y-%m-%dT%H%Z", /* ISO8601 time but with timezone name */
"%Y-%m-%dT%H:%M%Z", /* ISO8601 time but with timezone name */
/* RFC 3339 time */
"%Y-%m-%d %H:%M:%S%z", /* RFC 3339 time */
"%Y-%m-%dT%H:%M:%S%z", /* RFC 3339 time */
"%Y-%m-%d %H:%M:%S%Z", /* RFC 3339 time but with timezone name */
#if 0
"%Y-%m-%dT%H:%M:%S%z", /* RFC 3339 time, same as first ISO8601 time */
#endif
/* more oddball formats */
"%m.%d.%Y %T", /* mm.dd.YYYY HH:MM:SS */
"%m.%d.%Y %R", /* mm.dd.YYYY HH:MM */
@@ -151,13 +154,28 @@ static char * const date_time_formats[] =
"%d.%m.%Y %R", /* dd.mm.YYYY HH:MM */
"%d.%m.%Y %r", /* dd.mm.YYYY HH:MM:SS a.m. */
"%d.%m.%Y %I:%M %p", /* dd.mm.YYYY HH:MM p.m. */
/* Some fallbacks */
"%F", /* YYYY-mm-dd ISO8601 time */
"%T", /* HH:MM:SS */
"%H.%M.%S", /* HH.MM.SS */
0
};
static void
inittime (time_t *clock, struct tm *timeptr)
{
timeptr = localtime (clock); /* for now */
struct tm *loctime;
/* Initialize to local time */
loctime = localtime (clock);
if (loctime == 0)
{
timeptr->tm_hour = timeptr->tm_min = timeptr->tm_sec = 0;
return;
}
memcpy (timeptr, loctime, sizeof (struct tm));
/* but default to midnight */
timeptr->tm_hour = timeptr->tm_min = timeptr->tm_sec = 0;
@@ -171,17 +189,31 @@ strptime_builtin (WORD_LIST *list)
char *s;
struct tm t, *tm;
time_t now, secs;
char *datestr;
int i;
char *datestr, *format;
int i, opt;
if (no_options (list)) /* for now */
return (EX_USAGE);
format = NULL;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "f:")) != -1)
{
switch (opt)
{
case 'f':
format = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
return (EX_USAGE);
}
datestr = string_list (list);
@@ -195,26 +227,44 @@ strptime_builtin (WORD_LIST *list)
if (STREQ (datestr, date_time_modifiers[i].shorthand))
{
secs = now + date_time_modifiers[i].incr;
break;
printf ("%ld\n", secs);
return (EXECUTION_SUCCESS);
}
}
if (secs == -1)
/* init struct tm */
inittime (&now, &t);
if (format)
{
s = strptime (datestr, format, &t);
if (s == 0 || s == datestr)
{
builtin_error ("%s: unrecognized format", datestr);
return (EXECUTION_FAILURE);
}
}
else
{
/* init struct tm */
inittime (&now, tm);
t = *tm;
for (i = 0; date_time_formats[i]; i++)
{
{
s = strptime (datestr, date_time_formats[i], &t);
if (s == 0)
if (s == 0 || s == datestr)
continue;
/* skip extra characters at the end for now */
secs = mktime (&t);
break;
}
if (date_time_formats[i] == 0)
{
builtin_error ("%s: unrecognized format", datestr);
return (EXECUTION_FAILURE);
}
}
/* Found something. */
secs = mktime (&t);
if (s && *s)
builtin_warning("%s: not completely converted (%s)", datestr, s);
printf ("%ld\n", secs);
return (EXECUTION_SUCCESS);
}
@@ -222,9 +272,12 @@ strptime_builtin (WORD_LIST *list)
char *strptime_doc[] = {
"Convert a date-time string to seconds since the epoch.",
"",
"Take DATE-TIME, a date-time string, parse it against a set of common",
"date-time formats. If the string matches one of the formats, convert",
"it into seconds since the epoch and display the result.",
"Take DATE-TIME, a date-time string, and parse it using FORMAT, a",
"date and time format accepted by strptime(3). If FORMAT is not supplied,",
"attempt to parse DATE-TIME against a set of common date-time formats,",
"not all of which may be acceptable to strptime(3).",
"If the string matches one of the formats, convert it into seconds",
"since the epoch and display the result.",
(char *)NULL
};
@@ -236,6 +289,6 @@ struct builtin strptime_struct = {
strptime_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
strptime_doc, /* array of long documentation strings. */
"strptime date-time", /* usage synopsis; becomes short_doc */
"strptime [-f format] date-time", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+55 -40
View File
@@ -88,7 +88,7 @@ function _shellmath_handleError()
# Display error msg, making parameter substitutions as needed
msgParameters="$*"
printf "$msgTemplate" "${msgParameters[@]}"
printf '%s ' "$msgTemplate" "${msgParameters[@]}"; printf '\n'
if ((returnDontExit)); then
return "$returnCode"
@@ -442,7 +442,7 @@ function _shellmath_add()
((isNegative2)) && ((integerPart2*=-1))
local sum=$((integerPart1 + integerPart2))
if (( (!isSubcall) && (isScientific1 || isScientific2) )); then
_shellmath_numToScientific $sum ""
_shellmath_numToScientific $sum ""
_shellmath_getReturnValue sum
fi
_shellmath_setReturnValue $sum
@@ -485,17 +485,11 @@ function _shellmath_add()
# Summing the fractional parts is tricky: We need to override the shell's
# default interpretation of leading zeros, but the operator for doing this
# (the "10#" operator) cannot work directly with negative numbers. So we
# break it all down.
if ((isNegative1)); then
((fractionalSum += (-1) * 10#${fractionalPart1:1}))
else
((fractionalSum += 10#$fractionalPart1))
fi
if ((isNegative2)); then
((fractionalSum += (-1) * 10#${fractionalPart2:1}))
else
((fractionalSum += 10#$fractionalPart2))
fi
# use parameter expansions to separate the \+/-\ signs from the numbers.
((fractionalSum =
${fractionalPart1//[^-]}10#${fractionalPart1//[^0-9]} +
${fractionalPart2//[^-]}10#${fractionalPart2//[^0-9]}))
unsignedFracSumLength=${#fractionalSum}
if [[ "$fractionalSum" =~ ^[-] ]]; then
@@ -515,7 +509,9 @@ function _shellmath_add()
fi
# Carry a digit from fraction to integer if required
if ((10#$fractionalSum!=0 && unsignedFracSumLength > unsignedFracLength)); then
if (( ${fractionalSum//[^-]}10#${fractionalSum//[^0-9]} !=0 )) &&
((unsignedFracSumLength > unsignedFracLength))
then
local carryAmount
((carryAmount = isNegative1?-1:1))
((integerSum += carryAmount))
@@ -527,34 +523,43 @@ function _shellmath_add()
# pair (-2,3) is not -2.3 but rather (-2)+(0.3), i.e. -1.7 so we want to
# transform (-2,3) to (-1,7). This transformation is meaningful when
# the two parts have opposite signs, so that's what we look for.
if ((integerSum < 0 && 10#$fractionalSum > 0)); then
if ((integerSum < 0)) &&
(( ${fractionalSum//[^-]}10#${fractionalSum//[^0-9]} > 0))
then
((integerSum += 1))
((fractionalSum = 10#$fractionalSum - 10**unsignedFracSumLength))
elif ((integerSum > 0 && 10#$fractionalSum < 0)); then
((fractionalSum = ${fractionalSum//[^-]}10#${fractionalSum//[^0-9]} -
10**unsignedFracSumLength))
elif ((integerSum > 0)) &&
(( ${fractionalSum//[^-]}10#${fractionalSum//[^0-9]} < 0))
then
((integerSum -= 1))
((fractionalSum = 10**unsignedFracSumLength + 10#$fractionalSum))
((fractionalSum = 10**unsignedFracSumLength +
${fractionalSum//[^-]}10#${fractionalSum//[^0-9]} ))
fi
# This last case needs to function either as an "else" for the above,
# or as a coda to the "if" clause when integerSum is -1 initially.
if ((integerSum == 0 && 10#$fractionalSum < 0)); then
if ((integerSum == 0)) &&
(( ${fractionalSum//[^-]}10#${fractionalSum//[^0-9]} < 0))
then
integerSum="-"$integerSum
((fractionalSum *= -1))
fi
# Touch up the numbers for display
local sum
((10#$fractionalSum < 0)) && fractionalSum=${fractionalSum:1}
(( ${fractionalSum//[^-]}10#${fractionalSum//[^0-9]}< 0)) &&
fractionalSum=${fractionalSum//[-]}
if (( (!isSubcall) && (isScientific1 || isScientific2) )); then
_shellmath_numToScientific "$integerSum" "$fractionalSum"
_shellmath_getReturnValue sum
elif ((10#$fractionalSum)); then
elif (( ${fractionalSum//[^-]}10#${fractionalSum//[^0-9]} )); then
printf -v sum "%s.%s" "$integerSum" "$fractionalSum"
else
sum=$integerSum
fi
# Note the result, print if running "normally", and return
_shellmath_setReturnValue $sum
_shellmath_setReturnValue "$sum"
if (( isVerbose && ! isSubcall )); then
echo "$sum"
fi
@@ -660,9 +665,9 @@ function _shellmath_reduceOuterPairs()
fi
# Discard the least-significant digits or move them past the decimal point
value1=${value1%${tail1}}
value1=${value1%"${tail1}"}
[[ -n "$subvalue1" ]] && subvalue1=${tail1}${subvalue1%0} # remove placeholder zero
value2=${value2%${tail2}}
value2=${value2%"${tail2}"}
[[ -n "$subvalue2" ]] && subvalue2=${tail2}${subvalue2%0}
else
# Signal the caller that no rescaling was actually done
@@ -733,7 +738,7 @@ function _shellmath_round()
number=${number:0:digitCount}
if ((nextDigit >= 5)); then
printf -v number "%0*d" "$digitCount" $((10#$number + 1))
printf -v number "%0*d" "$digitCount" $((${number//[^-]}10#${number//[^0-9]} + 1))
fi
_shellmath_setReturnValue "$number"
@@ -818,11 +823,15 @@ function _shellmath_multiply()
# Overflow / underflow detection and accommodation
local rescalingFactor=0
if ((${#integerPart1} + ${#integerPart2} + ${#fractionalPart1} + ${#fractionalPart2} >= ${__shellmath_precision})); then
if ((${#integerPart1} + ${#integerPart2} + ${#fractionalPart1} + ${#fractionalPart2} >= __shellmath_precision)); then
_shellmath_reduceOuterPairs "$integerPart1" "$integerPart2" "$fractionalPart1" "$fractionalPart2"
_shellmath_getReturnValues integerPart1 integerPart2 fractionalPart1 fractionalPart2 rescalingFactor
if ((10#$fractionalPart1)); then type1=${__shellmath_numericTypes[DECIMAL]}; fi
if ((10#$fractionalPart2)); then type2=${__shellmath_numericTypes[DECIMAL]}; fi
if ((${fractionalPart1//[^-]}10#${fractionalPart1//[^0-9]})); then
type1=${__shellmath_numericTypes[DECIMAL]}
fi
if ((${fractionalPart2//[^-]}10#${fractionalPart2//[^0-9]})); then
type2=${__shellmath_numericTypes[DECIMAL]}
fi
_shellmath_reduceCrossPairs "$integerPart1" "$integerPart2" "$fractionalPart1" "$fractionalPart2"
_shellmath_getReturnValues fractionalPart1 fractionalPart2
@@ -841,7 +850,7 @@ function _shellmath_multiply()
_shellmath_getReturnValue product
fi
if (( (!isSubcall) && (isScientific1 || isScientific2) )); then
_shellmath_numToScientific $product ""
_shellmath_numToScientific $product ""
_shellmath_getReturnValue product
fi
_shellmath_setReturnValue $product
@@ -862,14 +871,16 @@ function _shellmath_multiply()
fractionalWidth1=${#fractionalPart1}
fractionalWidth2=${#fractionalPart2}
((floatWidth = fractionalWidth1 + fractionalWidth2))
((floatProduct = 10#$fractionalPart1 * 10#$fractionalPart2))
((floatProduct =
${fractionalPart1//[^-]}10#${fractionalPart1//[^0-9]} *
${fractionalPart2//[^-]}10#${fractionalPart2//[^0-9]}))
if ((${#floatProduct} < floatWidth)); then
printf -v floatProduct "%0*d" "$floatWidth" "$floatProduct"
fi
# Compute the inner products: First integer-multiply, then rescale
((innerProduct1 = integerPart1 * 10#$fractionalPart2))
((innerProduct2 = integerPart2 * 10#$fractionalPart1))
((innerProduct1 = integerPart1 * ${fractionalPart2//[^-]}10#${fractionalPart2//[^0-9]}))
((innerProduct2 = integerPart2 * ${fractionalPart1//[^-]}10#${fractionalPart1//[^0-9]}))
# Rescale the inner products back to decimals so we can shellmath_add() them
if ((fractionalWidth2 <= ${#innerProduct1})); then
@@ -979,7 +990,9 @@ function _shellmath_divide()
fi
# Throw error on divide by zero
if ((integerPart2 == 0 && 10#$fractionalPart2 == 0)); then
if ((integerPart2 == 0)) &&
(( ${fractionalPart2//[^-]}10#${fractionalPart2//[^0-9]} == 0 ))
then
_shellmath_warn "${__shellmath_returnCodes[DIVIDE_BY_ZERO]}" "$n2"
return $?
fi
@@ -1002,11 +1015,13 @@ function _shellmath_divide()
# Rescale and rewrite the fraction to be computed, and compute it
numerator=${integerPart1}${fractionalPart1}${zeroTail}
denominator=${integerPart2}${fractionalPart2}
((quotient = 10#$numerator / 10#$denominator))
((quotient = ${numerator//[^-]}10#${numerator//[^0-9]} /
${denominator//[^-]}10#${denominator//[^0-9]}))
# For greater precision, re-divide by the remainder to get the next digits of the quotient
local remainder quotient_2
((remainder = 10#$numerator % 10#$denominator)) # cannot exceed numerator or thus, maxValue
((remainder = ${numerator//[^-]}10#${numerator//[^0-9]} %
${denominator//[^-]}10#${denominator//[^0-9]})) # cant exceed numerator or thus, maxValue
((zeroCount = __shellmath_precision - ${#remainder}))
if ((zeroCount > 0)); then
printf -v zeroTail "%0*d" "$zeroCount" 0
@@ -1015,7 +1030,8 @@ function _shellmath_divide()
fi
# Derive the new numerator from the remainder. Do not change the denominator.
numerator=${remainder}${zeroTail}
((quotient_2 = 10#$numerator / 10#$denominator))
((quotient_2 = ${numerator//[^-]}10#${numerator//[^0-9]} /
${denominator//[^-]}10#${denominator//[^0-9]}))
quotient=${quotient}${quotient_2}
((rescaleFactor += ${#quotient_2}))
@@ -1027,12 +1043,12 @@ function _shellmath_divide()
printf -v zeroPrefix "%0*d" "$((rescaleFactor - ${#quotient}))" 0
fi
fractionalPart=${zeroPrefix}${quotient}
_shellmath_round "$fractionalPart" $__shellmath_precision
_shellmath_round "$fractionalPart" "$__shellmath_precision"
_shellmath_getReturnValue fractionalPart
quotient="0."${fractionalPart}
else
fractionalPart=${quotient:(-$rescaleFactor)}
_shellmath_round "$fractionalPart" $__shellmath_precision
_shellmath_round "$fractionalPart" "$__shellmath_precision"
_shellmath_getReturnValue fractionalPart
quotient=${quotient:0:(-$rescaleFactor)}"."${fractionalPart}
fi
@@ -1047,7 +1063,7 @@ function _shellmath_divide()
if [[ "$quotient" =~ [\.].*0$ ]]; then
# If the decimal point IMMEDIATELY precedes the 0s, remove that too
[[ $quotient =~ [\.]?0+$ ]]
quotient=${quotient%${BASH_REMATCH[0]}}
quotient=${quotient%"${BASH_REMATCH[0]}"}
fi
fi
@@ -1065,4 +1081,3 @@ function _shellmath_divide()
return "$__shellmath_SUCCESS"
}