Bug 743999 - Deleting a digit from an existing number greater than...

four digits in length generates an error message.

Because the grouping is off. Checking grouping on input is pointless so
just ignore the grouping separator when parsing number input.
This commit is contained in:
John Ralls
2021-06-18 11:40:06 -07:00
parent 6a7b3791e6
commit 7f62c5395a
5 changed files with 20 additions and 167 deletions

View File

@@ -2048,9 +2048,7 @@ typedef enum
{
START_ST, /* Parsing initial whitespace */
NEG_ST, /* Parsed a negative sign or a left paren */
PRE_GROUP_ST, /* Parsing digits before grouping and decimal characters */
START_GROUP_ST, /* Start of a digit group encountered (possibly) */
IN_GROUP_ST, /* Within a digit group */
NUMER_ST, /* Parsing digits before grouping and decimal characters */
FRAC_ST, /* Parsing the fractional portion of a number */
DONE_ST, /* Finished, number is correct module grouping constraints */
NO_NUM_ST /* Finished, number was malformed */
@@ -2106,20 +2104,17 @@ xaccParseAmountPosSign (const char * in_str, gboolean monetary, gnc_numeric *res
gunichar group_separator;
gchar *ignore = NULL;
char *plus_sign = "+";
char *group;
negative_sign = g_utf8_get_char(lc->negative_sign);
if (monetary)
{
group_separator = g_utf8_get_char(lc->mon_thousands_sep);
decimal_point = g_utf8_get_char(lc->mon_decimal_point);
group = lc->mon_grouping;
}
else
{
group_separator = g_utf8_get_char(lc->thousands_sep);
decimal_point = g_utf8_get_char(lc->decimal_point);
group = lc->grouping;
}
if (skip)
@@ -2132,27 +2127,23 @@ xaccParseAmountPosSign (const char * in_str, gboolean monetary, gnc_numeric *res
ignore = plus_sign;
}
return xaccParseAmountExtended(in_str, monetary, negative_sign, decimal_point,
group_separator, group, ignore, result, endstr);
return xaccParseAmountExtended(in_str, monetary, negative_sign,
decimal_point, group_separator,
ignore, result, endstr);
}
/* Note: xaccParseAmountExtended causes test-print-parse-amount
to fail if QOF_SCANF_LLD is simply replaced by G_GINT64_FORMAT. Why?
A: Because scanf and printf use different symbols for 64-bit numbers.
*/
gboolean
xaccParseAmountExtended (const char * in_str, gboolean monetary,
gunichar negative_sign, gunichar decimal_point,
gunichar group_separator, const char *group, const char *ignore_list,
gunichar group_separator, const char *ignore_list,
gnc_numeric *result, char **endstr)
{
gboolean is_negative;
gboolean got_decimal;
gboolean need_paren;
GList * group_data;
long long int numer;
long long int denom;
int count, group_count;
int count;
ParseState state;
@@ -2185,8 +2176,6 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
is_negative = FALSE;
got_decimal = FALSE;
need_paren = FALSE;
group_data = NULL;
group_count = 0;
numer = 0;
denom = 1;
@@ -2218,7 +2207,7 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
count = g_unichar_to_utf8(uc, out);
out += count; /* we record the digits themselves in out_str
* for later conversion by libc routines */
next_state = PRE_GROUP_ST;
next_state = NUMER_ST;
}
else if (uc == decimal_point)
{
@@ -2252,7 +2241,7 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
{
count = g_unichar_to_utf8(uc, out);
out += count;
next_state = PRE_GROUP_ST;
next_state = NUMER_ST;
}
else if (uc == decimal_point)
{
@@ -2268,9 +2257,9 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
break;
/* PRE_GROUP_ST means we have started parsing the number, but
* have not encountered a decimal point or a grouping character. */
case PRE_GROUP_ST:
/* NUMER_ST means we have started parsing the number, but
* have not encountered a decimal separator. */
case NUMER_ST:
if (g_unichar_isdigit(uc))
{
count = g_unichar_to_utf8(uc, out);
@@ -2282,85 +2271,7 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
}
else if (uc == group_separator)
{
next_state = START_GROUP_ST;
}
else if (uc == ')' && need_paren)
{
next_state = DONE_ST;
need_paren = FALSE;
}
else
{
next_state = DONE_ST;
}
break;
/* START_GROUP_ST means we have just parsed a group character.
* Note that group characters might be whitespace!!! In general,
* if a decimal point or a group character is whitespace, we
* try to interpret it in the fashion that will allow parsing
* of the current number to continue. */
case START_GROUP_ST:
if (g_unichar_isdigit(uc))
{
count = g_unichar_to_utf8(uc, out);
out += count;
group_count++; /* We record the number of digits
* in the group for later checking. */
next_state = IN_GROUP_ST;
}
else if (uc == decimal_point)
{
/* If we now get a decimal point, and both the decimal
* and the group separator are also whitespace, assume
* the last group separator was actually whitespace and
* stop parsing. Otherwise, there's a problem. */
if (g_unichar_isspace(group_separator) &&
g_unichar_isspace(decimal_point))
next_state = DONE_ST;
else
next_state = NO_NUM_ST;
}
else if (uc == ')' && need_paren)
{
if (g_unichar_isspace(group_separator))
{
next_state = DONE_ST;
need_paren = FALSE;
}
else
next_state = NO_NUM_ST;
}
else
{
/* If the last group separator is also whitespace,
* assume it was intended as such and stop parsing.
* Otherwise, there is a problem. */
if (g_unichar_isspace(group_separator))
next_state = DONE_ST;
else
next_state = NO_NUM_ST;
}
break;
/* IN_GROUP_ST means we are in the middle of parsing
* a group of digits. */
case IN_GROUP_ST:
if (g_unichar_isdigit(uc))
{
count = g_unichar_to_utf8(uc, out);
out += count;
group_count++; /* We record the number of digits
* in the group for later checking. */
}
else if (uc == decimal_point)
{
next_state = FRAC_ST;
}
else if (uc == group_separator)
{
next_state = START_GROUP_ST;
; //ignore it
}
else if (uc == ')' && need_paren)
{
@@ -2395,11 +2306,9 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
{
/* If a subsequent group separator is also whitespace,
* assume it was intended as such and stop parsing.
* Otherwise, there is a problem. */
* Otherwise ignore it. */
if (g_unichar_isspace(group_separator))
next_state = DONE_ST;
else
next_state = NO_NUM_ST;
}
else if (uc == ')' && need_paren)
{
@@ -2419,13 +2328,6 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
break;
}
/* If we're moving out of the IN_GROUP_ST, record data for the group */
if ((state == IN_GROUP_ST) && (next_state != IN_GROUP_ST))
{
group_data = g_list_prepend(group_data, GINT_TO_POINTER(group_count));
group_count = 0;
}
/* If we're moving into the FRAC_ST or out of the machine
* without going through FRAC_ST, record the integral value. */
if (((next_state == FRAC_ST) && (state != FRAC_ST)) ||
@@ -2458,57 +2360,9 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
if (need_paren || (state == NO_NUM_ST))
{
g_free(out_str);
g_list_free(group_data);
return FALSE;
}
/* If there were groups, validate them */
if (group_data != NULL)
{
gboolean good_grouping = TRUE;
GList *node;
/* The groups were built in reverse order. This
* is the easiest order to verify them in. */
for (node = group_data; group && node; node = node->next)
{
/* Verify group size */
if (*group != GPOINTER_TO_INT(node->data))
{
good_grouping = FALSE;
break;
}
/* Peek ahead at the next group code */
switch (group[1])
{
/* A null char means repeat the last group indefinitely */
case '\0':
break;
/* CHAR_MAX means no more grouping allowed */
case CHAR_MAX:
if (node->next != NULL)
good_grouping = FALSE;
break;
/* Anything else means another group size */
default:
group++;
break;
}
if (!good_grouping)
break;
}
g_list_free(group_data);
if (!good_grouping)
{
g_free(out_str);
return FALSE;
}
}
/* Cap the end of the fraction string, if any */
*out = '\0';