mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Bug 797033 - The CSV Importer should not obey with the "automatic digital point" setting
Expose variations of xaccParseAmount and xaccParseAmountExtended that will ignore the automatic decimal point user preference. This preference is really only useful for manual number entering in the register. The xaccParseAmountImport variant replaces xaccParseAmountPosSign which was used exclusively by the csv importers. Like xaccParseAmountPosSign, this replacement has the flag to ignore or parse the positive number indicator.
This commit is contained in:
parent
fcbda57a6b
commit
26482f397b
@ -78,17 +78,17 @@ GncNumeric parse_amount_price (const std::string &str, int currency_format)
|
||||
{
|
||||
case 0:
|
||||
/* Currency locale */
|
||||
if (!(xaccParseAmountPosSign (str_no_symbols.c_str(), TRUE, &val, &endptr, TRUE)))
|
||||
if (!(xaccParseAmountImport (str_no_symbols.c_str(), TRUE, &val, &endptr, TRUE)))
|
||||
throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format."));
|
||||
break;
|
||||
case 1:
|
||||
/* Currency decimal period */
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtImport (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, '-', ',', '.', "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtImport (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;
|
||||
}
|
||||
|
@ -149,17 +149,17 @@ GncNumeric parse_monetary (const std::string &str, int currency_format)
|
||||
{
|
||||
case 0:
|
||||
/* Currency locale */
|
||||
if (!(xaccParseAmountPosSign (str_no_symbols.c_str(), TRUE, &val, &endptr, TRUE)))
|
||||
if (!(xaccParseAmountImport (str_no_symbols.c_str(), TRUE, &val, &endptr, TRUE)))
|
||||
throw std::invalid_argument (_("Value can't be parsed into a number using the selected currency format."));
|
||||
break;
|
||||
case 1:
|
||||
/* Currency decimal period */
|
||||
if (!(xaccParseAmountExtended (str_no_symbols.c_str(), TRUE, '-', '.', ',', "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtImport (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, '-', ',', '.', "$+", &val, &endptr)))
|
||||
if (!(xaccParseAmountExtImport (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;
|
||||
}
|
||||
|
@ -1759,56 +1759,11 @@ multiplier (int num_decimals)
|
||||
return 1;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccParseAmount (const char * in_str, gboolean monetary, gnc_numeric *result,
|
||||
char **endstr)
|
||||
{
|
||||
return xaccParseAmountPosSign (in_str, monetary, result, endstr, FALSE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccParseAmountPosSign (const char * in_str, gboolean monetary, gnc_numeric *result,
|
||||
char **endstr, gboolean skip)
|
||||
{
|
||||
struct lconv *lc = gnc_localeconv();
|
||||
|
||||
gunichar negative_sign;
|
||||
gunichar decimal_point;
|
||||
gunichar group_separator;
|
||||
gchar *ignore = NULL;
|
||||
char *plus_sign = "+";
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
group_separator = g_utf8_get_char(lc->thousands_sep);
|
||||
decimal_point = g_utf8_get_char(lc->decimal_point);
|
||||
}
|
||||
|
||||
if (skip)
|
||||
{
|
||||
/* We want the locale's positive sign to be ignored.
|
||||
* If the locale doesn't specify one, we assume "+" as
|
||||
* an optional positive sign and ignore that */
|
||||
ignore = lc->positive_sign;
|
||||
if (!ignore || !*ignore)
|
||||
ignore = plus_sign;
|
||||
}
|
||||
|
||||
return xaccParseAmountExtended(in_str, monetary, negative_sign,
|
||||
decimal_point, group_separator,
|
||||
ignore, result, endstr);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccParseAmountExtended (const char * in_str, gboolean monetary,
|
||||
static gboolean
|
||||
xaccParseAmountInternal (const char * in_str, gboolean monetary,
|
||||
gunichar negative_sign, gunichar decimal_point,
|
||||
gunichar group_separator, const char *ignore_list,
|
||||
gboolean use_auto_decimal,
|
||||
gnc_numeric *result, char **endstr)
|
||||
{
|
||||
gboolean is_negative;
|
||||
@ -1874,137 +1829,137 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
|
||||
switch (state)
|
||||
{
|
||||
/* START_ST means we have parsed 0 or more whitespace characters */
|
||||
case START_ST:
|
||||
if (g_unichar_isdigit(uc))
|
||||
{
|
||||
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 = NUMER_ST;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (g_unichar_isspace(uc))
|
||||
{
|
||||
}
|
||||
else if (uc == negative_sign)
|
||||
{
|
||||
is_negative = TRUE;
|
||||
next_state = NEG_ST;
|
||||
}
|
||||
else if (uc == '(')
|
||||
{
|
||||
is_negative = TRUE;
|
||||
need_paren = TRUE;
|
||||
next_state = NEG_ST;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* NEG_ST means we have just parsed a negative sign. For now,
|
||||
* we only recognize formats where the negative sign comes first. */
|
||||
case NEG_ST:
|
||||
if (g_unichar_isdigit(uc))
|
||||
{
|
||||
count = g_unichar_to_utf8(uc, out);
|
||||
out += count;
|
||||
next_state = NUMER_ST;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (g_unichar_isspace(uc))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* 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);
|
||||
out += count;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (uc == group_separator)
|
||||
{
|
||||
; //ignore it
|
||||
}
|
||||
else if (uc == ')' && need_paren)
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
need_paren = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* FRAC_ST means we are now parsing fractional digits. */
|
||||
case FRAC_ST:
|
||||
if (g_unichar_isdigit(uc))
|
||||
{
|
||||
count = g_unichar_to_utf8(uc, out);
|
||||
out += count;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
/* If a subsequent decimal point is also whitespace,
|
||||
* assume it was intended as such and stop parsing.
|
||||
* Otherwise, there is a problem. */
|
||||
if (g_unichar_isspace(decimal_point))
|
||||
next_state = DONE_ST;
|
||||
case START_ST:
|
||||
if (g_unichar_isdigit(uc))
|
||||
{
|
||||
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 = NUMER_ST;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (g_unichar_isspace(uc))
|
||||
{
|
||||
}
|
||||
else if (uc == negative_sign)
|
||||
{
|
||||
is_negative = TRUE;
|
||||
next_state = NEG_ST;
|
||||
}
|
||||
else if (uc == '(')
|
||||
{
|
||||
is_negative = TRUE;
|
||||
need_paren = TRUE;
|
||||
next_state = NEG_ST;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
else if (uc == group_separator)
|
||||
{
|
||||
/* If a subsequent group separator is also whitespace,
|
||||
* assume it was intended as such and stop parsing.
|
||||
* Otherwise ignore it. */
|
||||
if (g_unichar_isspace(group_separator))
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
else if (uc == ')' && need_paren)
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
need_paren = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
PERR("bad state");
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
/* NEG_ST means we have just parsed a negative sign. For now,
|
||||
* we only recognize formats where the negative sign comes first. */
|
||||
case NEG_ST:
|
||||
if (g_unichar_isdigit(uc))
|
||||
{
|
||||
count = g_unichar_to_utf8(uc, out);
|
||||
out += count;
|
||||
next_state = NUMER_ST;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (g_unichar_isspace(uc))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* 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);
|
||||
out += count;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (uc == group_separator)
|
||||
{
|
||||
; //ignore it
|
||||
}
|
||||
else if (uc == ')' && need_paren)
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
need_paren = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* FRAC_ST means we are now parsing fractional digits. */
|
||||
case FRAC_ST:
|
||||
if (g_unichar_isdigit(uc))
|
||||
{
|
||||
count = g_unichar_to_utf8(uc, out);
|
||||
out += count;
|
||||
}
|
||||
else if (uc == decimal_point)
|
||||
{
|
||||
/* If a subsequent decimal point is also whitespace,
|
||||
* assume it was intended as such and stop parsing.
|
||||
* Otherwise, there is a problem. */
|
||||
if (g_unichar_isspace(decimal_point))
|
||||
next_state = DONE_ST;
|
||||
else
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
else if (uc == group_separator)
|
||||
{
|
||||
/* If a subsequent group separator is also whitespace,
|
||||
* assume it was intended as such and stop parsing.
|
||||
* Otherwise ignore it. */
|
||||
if (g_unichar_isspace(group_separator))
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
else if (uc == ')' && need_paren)
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
need_paren = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
PERR("bad state");
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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)) ||
|
||||
((next_state == DONE_ST) && !got_decimal))
|
||||
((next_state == DONE_ST) && !got_decimal))
|
||||
{
|
||||
*out = '\0';
|
||||
|
||||
@ -2063,7 +2018,7 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
|
||||
numer *= denom;
|
||||
numer += fraction;
|
||||
}
|
||||
else if (monetary && auto_decimal_enabled && !got_decimal)
|
||||
else if (monetary && use_auto_decimal && !got_decimal)
|
||||
{
|
||||
if ((auto_decimal_places > 0) && (auto_decimal_places <= 12))
|
||||
{
|
||||
@ -2092,6 +2047,92 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
xaccParseAmountBasicInternal (const char * in_str, gboolean monetary,
|
||||
gboolean use_auto_decimal, gnc_numeric *result,
|
||||
char **endstr, gboolean skip)
|
||||
{
|
||||
struct lconv *lc = gnc_localeconv();
|
||||
|
||||
gunichar negative_sign;
|
||||
gunichar decimal_point;
|
||||
gunichar group_separator;
|
||||
gchar *ignore = NULL;
|
||||
char *plus_sign = "+";
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
group_separator = g_utf8_get_char(lc->thousands_sep);
|
||||
decimal_point = g_utf8_get_char(lc->decimal_point);
|
||||
}
|
||||
|
||||
if (skip)
|
||||
{
|
||||
/* We want the locale's positive sign to be ignored.
|
||||
* If the locale doesn't specify one, we assume "+" as
|
||||
* an optional positive sign and ignore that */
|
||||
ignore = lc->positive_sign;
|
||||
if (!ignore || !*ignore)
|
||||
ignore = plus_sign;
|
||||
}
|
||||
|
||||
return xaccParseAmountInternal(in_str, monetary, negative_sign,
|
||||
decimal_point, group_separator,
|
||||
ignore, use_auto_decimal,
|
||||
result, endstr);
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
xaccParseAmount (const char * in_str, gboolean monetary, gnc_numeric *result,
|
||||
char **endstr)
|
||||
{
|
||||
return xaccParseAmountBasicInternal (in_str, monetary, auto_decimal_enabled,
|
||||
result, endstr, FALSE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccParseAmountImport (const char * in_str, gboolean monetary,
|
||||
gnc_numeric *result,
|
||||
char **endstr, gboolean skip)
|
||||
{
|
||||
return xaccParseAmountBasicInternal (in_str, monetary, FALSE,
|
||||
result, endstr, FALSE);
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
xaccParseAmountExtended (const char * in_str, gboolean monetary,
|
||||
gunichar negative_sign, gunichar decimal_point,
|
||||
gunichar group_separator, const char *ignore_list,
|
||||
gnc_numeric *result, char **endstr)
|
||||
{
|
||||
return xaccParseAmountInternal (in_str, monetary, negative_sign,
|
||||
decimal_point, group_separator,
|
||||
ignore_list, auto_decimal_enabled,
|
||||
result, endstr);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccParseAmountExtImport (const char * in_str, gboolean monetary,
|
||||
gunichar negative_sign, gunichar decimal_point,
|
||||
gunichar group_separator, const char *ignore_list,
|
||||
gnc_numeric *result, char **endstr)
|
||||
{
|
||||
return xaccParseAmountInternal (in_str, monetary, negative_sign,
|
||||
decimal_point, group_separator,
|
||||
ignore_list, FALSE,
|
||||
result, endstr);
|
||||
}
|
||||
|
||||
|
||||
/* enable/disable the auto_decimal_enabled option */
|
||||
static void
|
||||
gnc_set_auto_decimal_enabled (gpointer settings, gchar *key, gpointer user_data)
|
||||
|
@ -331,19 +331,6 @@ gchar *numeric_to_words(gnc_numeric val);
|
||||
gboolean xaccParseAmount (const char * in_str, gboolean monetary,
|
||||
gnc_numeric *result, char **endstr);
|
||||
|
||||
/**
|
||||
* Parses in_str to a gnc_numeric, with a flag to indicate whether the
|
||||
* locale's positive sign (or in absence the '+') character is
|
||||
* ignored. Setting skip to TRUE will cause the function to ignore any
|
||||
* positive sign. Setting it to FALSE, and positive signs will be
|
||||
* treated as unrecognized characters. xaccParseAmount will run as if
|
||||
* skip is FALSE for compatibility reasons (gnc-expression-parser
|
||||
* depends on this behaviour).
|
||||
*/
|
||||
gboolean
|
||||
xaccParseAmountPosSign (const char * in_str, gboolean monetary, gnc_numeric *result,
|
||||
char **endstr, gboolean skip);
|
||||
|
||||
/**
|
||||
* Converts a string to a gnc_numeric. The caller must provide all the
|
||||
* locale-specific information.
|
||||
@ -358,6 +345,37 @@ xaccParseAmountExtended (const char * in_str, gboolean monetary,
|
||||
gunichar group_separator, const char *ignore_list,
|
||||
gnc_numeric *result, char **endstr);
|
||||
|
||||
/**
|
||||
* Similar to xaccParseAmount, but with two differences
|
||||
* - it exposes a flag to indicate whether the
|
||||
* locale's positive sign (or in absence the '+') character is
|
||||
* ignored. Setting skip to TRUE will cause the function to ignore any
|
||||
* positive sign. Setting it to FALSE, and positive signs will be
|
||||
* treated as unrecognized characters. xaccParseAmount will run as if
|
||||
* skip is FALSE for compatibility reasons (gnc-expression-parser
|
||||
* depends on this behaviour).
|
||||
* - The other important difference with xaccParseAmount is that this
|
||||
* function will never apply automatic decimal point logc, whereas
|
||||
* xaccParseAmount will follow the automatic decimal point preference
|
||||
* as set by the user.
|
||||
*/
|
||||
gboolean
|
||||
xaccParseAmountImport (const char * in_str, gboolean monetary,
|
||||
gnc_numeric *result,
|
||||
char **endstr, gboolean skip);
|
||||
|
||||
/**
|
||||
* Similar to xaccParseAmountExtended, but will not automatically
|
||||
* set a decimal point, regardless of what the user has set for this
|
||||
* option. Primarily meant for cases where numbers are coming into
|
||||
* gnucash that are not typed in by the user (like via csv import).
|
||||
*/
|
||||
gboolean
|
||||
xaccParseAmountExtImport (const char * in_str, gboolean monetary,
|
||||
gunichar negative_sign, gunichar decimal_point,
|
||||
gunichar group_separator, const char *ignore_list,
|
||||
gnc_numeric *result, char **endstr);
|
||||
|
||||
/**
|
||||
* Make a string representation of a gnc_numeric. Warning, the
|
||||
* gnc_numeric is not checked for validity and the returned char* may
|
||||
|
Loading…
Reference in New Issue
Block a user