mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
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:
@@ -84,12 +84,12 @@ GncNumeric parse_amount_price (const std::string &str, int currency_format)
|
||||
break;
|
||||
case 1:
|
||||
/* Currency decimal period */
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "\003\003", "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "$+", &val, &endptr)))
|
||||
throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format."));
|
||||
break;
|
||||
case 2:
|
||||
/* Currency decimal comma */
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', ',', '.', "\003\003", "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', ',', '.', "$+", &val, &endptr)))
|
||||
throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format."));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -136,12 +136,12 @@ GncNumeric parse_amount (const std::string &str, int currency_format)
|
||||
break;
|
||||
case 1:
|
||||
/* Currency decimal period */
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "\003\003", "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "$+", &val, &endptr)))
|
||||
throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format."));
|
||||
break;
|
||||
case 2:
|
||||
/* Currency decimal comma */
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', ',', '.', "\003\003", "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', ',', '.', "$+", &val, &endptr)))
|
||||
throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format."));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -252,10 +252,10 @@ gnc_import_parse_numeric(const char* str, GncImportFormat fmt, gnc_numeric *val)
|
||||
switch (fmt)
|
||||
{
|
||||
case GNCIF_NUM_PERIOD:
|
||||
return xaccParseAmountExtended(str, TRUE, '-', '.', ',', NULL, "$+",
|
||||
return xaccParseAmountExtended(str, TRUE, '-', '.', ',', "$+",
|
||||
val, NULL);
|
||||
case GNCIF_NUM_COMMA:
|
||||
return xaccParseAmountExtended(str, TRUE, '-', ',', '.', NULL, "$+",
|
||||
return xaccParseAmountExtended(str, TRUE, '-', ',', '.', "$+",
|
||||
val, NULL);
|
||||
default:
|
||||
PERR("invalid format: %d", fmt);
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -378,7 +378,6 @@ xaccParseAmountPosSign (const char * in_str, gboolean monetary, gnc_numeric *res
|
||||
* xaccParseAmountExtended is just like xaccParseAmount except the
|
||||
* caller must provide all the locale-specific information.
|
||||
*
|
||||
* Note: if group is NULL, no group-size verification will take place.
|
||||
* ignore_list is a list of characters that are completely ignored
|
||||
* while processing the input string. If ignore_list is NULL, nothing
|
||||
* is ignored.
|
||||
@@ -386,7 +385,7 @@ xaccParseAmountPosSign (const char * in_str, gboolean monetary, gnc_numeric *res
|
||||
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);
|
||||
|
||||
/* Initialization ***************************************************/
|
||||
|
||||
Reference in New Issue
Block a user