mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-26 02:40:43 -06:00
Generalize xaccParseAmount.
Add a GnuCash-specific interface to the src/calculation expression parser. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2736 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
70361420c9
commit
a0e4b34fbf
@ -8,7 +8,7 @@
|
||||
# This script requires the programs 'makepatch', 'gzip',
|
||||
# 'diff', and 'uuencode'.
|
||||
#
|
||||
# Author: Dave Peticolas <peticola@cs.ucdavis.edu>
|
||||
# Author: Dave Peticolas <dave@krondo.com>
|
||||
|
||||
use strict;
|
||||
|
||||
|
@ -39,7 +39,8 @@ gnucash_SOURCES = \
|
||||
Destroy.c \
|
||||
EuroUtils.c \
|
||||
FileDialog.c \
|
||||
Refresh.c
|
||||
Refresh.c \
|
||||
gnc-exp-parser.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
AccWindow.h \
|
||||
@ -55,6 +56,7 @@ noinst_HEADERS = \
|
||||
RegWindow.h \
|
||||
SplitLedger.h \
|
||||
file-history.h \
|
||||
gnc-exp-parser.h \
|
||||
gnc-ui-common.h \
|
||||
messages.h \
|
||||
messages_i18n.h \
|
||||
@ -67,6 +69,7 @@ EXTRA_DIST = \
|
||||
CFLAGS = @CFLAGS@ ${GLIB_CFLAGS} ${GNOME_CFLAGS} ${GUILE_COMPILE_ARGS}
|
||||
|
||||
INCLUDES = \
|
||||
-I./calculation \
|
||||
-I./engine \
|
||||
-I./guile \
|
||||
-I./register
|
||||
|
@ -129,10 +129,10 @@ bin_PROGRAMS = gnucash
|
||||
LDADD = gnome/libgncgnome.a register/libgncregister.a register/gnome/libgncregistergnome.a guile/libgncguile.a gnome/libgncgnome.a calculation/libgnccalc.a engine/libgncengine.la @GNOME_LIBS@ @G_WRAP_LINK_ARGS@ @GUILE_LINK_ARGS@ @INTLLIBS@
|
||||
|
||||
|
||||
gnucash_SOURCES = MultiLedger.c SplitLedger.c Destroy.c EuroUtils.c FileDialog.c Refresh.c
|
||||
gnucash_SOURCES = MultiLedger.c SplitLedger.c Destroy.c EuroUtils.c FileDialog.c Refresh.c gnc-exp-parser.c
|
||||
|
||||
|
||||
noinst_HEADERS = AccWindow.h AdjBWindow.h Destroy.h EuroUtils.h FileBox.h FileDialog.h MainWindow.h MultiLedger.h RecnWindow.h Refresh.h RegWindow.h SplitLedger.h file-history.h gnc-ui-common.h messages.h messages_i18n.h top-level.h ui-callbacks.h
|
||||
noinst_HEADERS = AccWindow.h AdjBWindow.h Destroy.h EuroUtils.h FileBox.h FileDialog.h MainWindow.h MultiLedger.h RecnWindow.h Refresh.h RegWindow.h SplitLedger.h file-history.h gnc-exp-parser.h gnc-ui-common.h messages.h messages_i18n.h top-level.h ui-callbacks.h
|
||||
|
||||
|
||||
EXTRA_DIST = .cvsignore
|
||||
@ -140,7 +140,7 @@ EXTRA_DIST = .cvsignore
|
||||
|
||||
CFLAGS = @CFLAGS@ ${GLIB_CFLAGS} ${GNOME_CFLAGS} ${GUILE_COMPILE_ARGS}
|
||||
|
||||
INCLUDES = -I./engine -I./guile -I./register
|
||||
INCLUDES = -I./calculation -I./engine -I./guile -I./register
|
||||
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_HEADER = ../config.h
|
||||
@ -157,7 +157,7 @@ X_LIBS = @X_LIBS@
|
||||
X_EXTRA_LIBS = @X_EXTRA_LIBS@
|
||||
X_PRE_LIBS = @X_PRE_LIBS@
|
||||
gnucash_OBJECTS = MultiLedger.o SplitLedger.o Destroy.o EuroUtils.o \
|
||||
FileDialog.o Refresh.o
|
||||
FileDialog.o Refresh.o gnc-exp-parser.o
|
||||
gnucash_LDADD = $(LDADD)
|
||||
gnucash_DEPENDENCIES = gnome/libgncgnome.a register/libgncregister.a \
|
||||
register/gnome/libgncregistergnome.a guile/libgncguile.a \
|
||||
@ -177,7 +177,8 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
|
||||
TAR = gtar
|
||||
GZIP_ENV = --best
|
||||
DEP_FILES = .deps/Destroy.P .deps/EuroUtils.P .deps/FileDialog.P \
|
||||
.deps/MultiLedger.P .deps/Refresh.P .deps/SplitLedger.P
|
||||
.deps/MultiLedger.P .deps/Refresh.P .deps/SplitLedger.P \
|
||||
.deps/gnc-exp-parser.P
|
||||
SOURCES = $(gnucash_SOURCES)
|
||||
OBJECTS = $(gnucash_OBJECTS)
|
||||
|
||||
|
@ -25,16 +25,17 @@
|
||||
* Author: Linas Vepstas (linas@linas.org) *
|
||||
\********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* #include <glib.h> */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "messages.h"
|
||||
#include "gnc-common.h"
|
||||
#include "util.h"
|
||||
@ -59,6 +60,10 @@ gncLogLevel loglevel[MOD_LAST + 1] =
|
||||
GNC_LOG_WARNING, /* QUERY */
|
||||
};
|
||||
|
||||
/* This static indicates the debugging module that this .o belongs to. */
|
||||
static short module = MOD_ENGINE;
|
||||
|
||||
|
||||
/* Set the logging level of the given module. */
|
||||
void
|
||||
gnc_set_log_level(gncModuleType module, gncLogLevel level)
|
||||
@ -434,10 +439,12 @@ gnc_localeconv()
|
||||
|
||||
gnc_lconv_set(&lc.decimal_point, ".");
|
||||
gnc_lconv_set(&lc.thousands_sep, ",");
|
||||
gnc_lconv_set(&lc.grouping, "\003");
|
||||
gnc_lconv_set(&lc.int_curr_symbol, "USD ");
|
||||
gnc_lconv_set(&lc.currency_symbol, CURRENCY_SYMBOL);
|
||||
gnc_lconv_set(&lc.mon_decimal_point, ".");
|
||||
gnc_lconv_set(&lc.mon_thousands_sep, ",");
|
||||
gnc_lconv_set(&lc.mon_grouping, "\003");
|
||||
gnc_lconv_set(&lc.negative_sign, "-");
|
||||
|
||||
gnc_lconv_set_char(&lc.frac_digits, 2);
|
||||
@ -821,176 +828,427 @@ xaccPrintAmountArgs (double val, gboolean print_currency_symbol,
|
||||
* xaccParseAmount *
|
||||
* parses amount strings using locale data *
|
||||
* *
|
||||
* Args: str -- pointer to string rep of num *
|
||||
monetary -- boolean indicating whether value is monetary *
|
||||
* Return: double -- the parsed amount *
|
||||
* Args: in_str -- pointer to string rep of num *
|
||||
* monetary -- boolean indicating whether value is monetary *
|
||||
* result -- pointer to result location, may be NULL *
|
||||
* endstr -- used to store first digit not used in parsing *
|
||||
* Return: gboolean -- TRUE if a number found and parsed *
|
||||
* If FALSE, result is not changed *
|
||||
\********************************************************************/
|
||||
|
||||
double xaccParseAmount (const char * instr, gboolean monetary)
|
||||
/* Parsing state machine states */
|
||||
typedef enum
|
||||
{
|
||||
struct lconv *lc = gnc_localeconv();
|
||||
gboolean isneg = FALSE;
|
||||
char *mstr, *str, *tok;
|
||||
double amount = 0.0;
|
||||
char negative_sign;
|
||||
char thousands_sep;
|
||||
char decimal_point;
|
||||
int len, i;
|
||||
START_ST, /* Parsing initial whitespace */
|
||||
NEG_ST, /* Parsed a negative sign */
|
||||
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 */
|
||||
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 */
|
||||
} ParseState;
|
||||
|
||||
if (!instr) return 0.0;
|
||||
if (*instr == '\0') return 0.0;
|
||||
#define done_state(state) (((state) == DONE_ST) || ((state) == NO_NUM_ST))
|
||||
|
||||
mstr = strdup (instr);
|
||||
str = mstr;
|
||||
G_INLINE_FUNC double
|
||||
fractional_multiplier (int num_decimals)
|
||||
{
|
||||
switch (num_decimals)
|
||||
{
|
||||
case 8:
|
||||
return 0.00000001;
|
||||
case 7:
|
||||
return 0.0000001;
|
||||
case 6:
|
||||
return 0.000001;
|
||||
break;
|
||||
case 5:
|
||||
return 0.00001;
|
||||
case 4:
|
||||
return 0.0001;
|
||||
case 3:
|
||||
return 0.001;
|
||||
case 2:
|
||||
return 0.01;
|
||||
case 1:
|
||||
return 0.1;
|
||||
default:
|
||||
PERR("bad fraction length");
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
|
||||
negative_sign = lc->negative_sign[0];
|
||||
if (monetary)
|
||||
{
|
||||
thousands_sep = lc->mon_thousands_sep[0];
|
||||
decimal_point = lc->mon_decimal_point[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
thousands_sep = lc->thousands_sep[0];
|
||||
decimal_point = lc->decimal_point[0];
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* strip off garbage at the beginning of the line */
|
||||
while (*str != '\0')
|
||||
{
|
||||
switch (*str)
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
case ' ':
|
||||
case '\t':
|
||||
str++;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
gboolean
|
||||
xaccParseAmount (const char * in_str, gboolean monetary, double *result,
|
||||
char **endstr)
|
||||
{
|
||||
struct lconv *lc = gnc_localeconv();
|
||||
gboolean is_negative;
|
||||
gboolean got_decimal;
|
||||
GList *group_data;
|
||||
int group_count;
|
||||
double value;
|
||||
|
||||
break;
|
||||
}
|
||||
ParseState state;
|
||||
|
||||
/* look for a negative sign */
|
||||
if (*str == negative_sign) {
|
||||
isneg = TRUE;
|
||||
str++;
|
||||
}
|
||||
char negative_sign;
|
||||
char decimal_point;
|
||||
char group_separator;
|
||||
const char *in;
|
||||
char *out_str;
|
||||
char *out;
|
||||
|
||||
if (*str == '\0') return 0.0;
|
||||
/* Initialize *endstr to in_str */
|
||||
if (endstr != NULL)
|
||||
*endstr = (char *) in_str;
|
||||
|
||||
/* go to end of string */
|
||||
for (tok = str; *tok != '\0'; tok++)
|
||||
;
|
||||
if (in_str == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* strip off garbage at end of the line */
|
||||
while (--tok != str)
|
||||
{
|
||||
switch (*tok)
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
case ' ':
|
||||
case '\t':
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
negative_sign = lc->negative_sign[0];
|
||||
if (monetary)
|
||||
{
|
||||
group_separator = lc->mon_thousands_sep[0];
|
||||
decimal_point = lc->mon_decimal_point[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
group_separator = lc->thousands_sep[0];
|
||||
decimal_point = lc->decimal_point[0];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/* 'out_str' will be used to store digits for numeric conversion.
|
||||
* 'out' will be used to traverse out_str. */
|
||||
out = out_str = g_new(char, strlen(in_str) + 1);
|
||||
|
||||
/* look for a negative sign at the end, some locales allow it,
|
||||
* we'll just allow it everywhere. */
|
||||
if (*tok == negative_sign) {
|
||||
isneg = TRUE;
|
||||
*tok = '\0';
|
||||
}
|
||||
/* 'in' is used to traverse 'in_str'. */
|
||||
in = in_str;
|
||||
|
||||
if (*str == '\0') return 0.0;
|
||||
is_negative = FALSE;
|
||||
got_decimal = FALSE;
|
||||
group_data = NULL;
|
||||
group_count = 0;
|
||||
value = 0.0;
|
||||
|
||||
/* remove thousands separator */
|
||||
tok = strchr (str, thousands_sep);
|
||||
while (tok) {
|
||||
*tok = '\0';
|
||||
amount *= 1000.0;
|
||||
amount += ((double) (1000 * atoi (str)));
|
||||
str = tok + sizeof(char);
|
||||
tok = strchr (str, thousands_sep);
|
||||
}
|
||||
/* Initialize the state machine */
|
||||
state = START_ST;
|
||||
|
||||
/* search for a decimal point */
|
||||
tok = strchr (str, decimal_point);
|
||||
if (tok) {
|
||||
*tok = '\0';
|
||||
amount += ((double) (atoi (str)));
|
||||
str = tok + sizeof(char);
|
||||
/* This while loop implements a state machine for parsing numbers. */
|
||||
while (TRUE)
|
||||
{
|
||||
ParseState next_state = state;
|
||||
|
||||
/* if there is anything trailing the decimal
|
||||
* point, convert it */
|
||||
if (str[0]) {
|
||||
/* Note we never need to check for then end of 'in_str' explicitly.
|
||||
* The 'else' clauses on all the state transitions will handle that. */
|
||||
switch (state)
|
||||
{
|
||||
/* START_ST means we have parsed 0 or more whitespace characters */
|
||||
case START_ST:
|
||||
if (isdigit(*in))
|
||||
{
|
||||
*out++ = *in; /* we record the digits themselves in out_str
|
||||
* for later conversion by libc routines */
|
||||
next_state = PRE_GROUP_ST;
|
||||
}
|
||||
else if (isspace(*in))
|
||||
{
|
||||
}
|
||||
else if (*in == negative_sign)
|
||||
{
|
||||
is_negative = TRUE;
|
||||
next_state = NEG_ST;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
|
||||
/* strip off garbage at end of the line */
|
||||
tok = strchr (str, ' ');
|
||||
if (tok) *tok = '\0';
|
||||
break;
|
||||
|
||||
/* adjust for number of decimal places */
|
||||
len = strlen(str);
|
||||
/* 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 (isdigit(*in))
|
||||
{
|
||||
*out++ = *in;
|
||||
next_state = PRE_GROUP_ST;
|
||||
}
|
||||
else if (isspace(*in))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
|
||||
if (len > 8)
|
||||
{
|
||||
str[8] = '\0';
|
||||
len = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
if (8 == len) {
|
||||
amount += 0.00000001 * ((double) atoi (str));
|
||||
} else
|
||||
if (7 == len) {
|
||||
amount += 0.0000001 * ((double) atoi (str));
|
||||
} else
|
||||
if (6 == len) {
|
||||
amount += 0.000001 * ((double) atoi (str));
|
||||
} else
|
||||
if (5 == len) {
|
||||
amount += 0.00001 * ((double) atoi (str));
|
||||
} else
|
||||
if (4 == len) {
|
||||
amount += 0.0001 * ((double) atoi (str));
|
||||
} else
|
||||
if (3 == len) {
|
||||
amount += 0.001 * ((double) atoi (str));
|
||||
} else
|
||||
if (2 == len) {
|
||||
amount += 0.01 * ((double) atoi (str));
|
||||
} else
|
||||
if (1 == len) {
|
||||
amount += 0.1 * ((double) atoi (str));
|
||||
}
|
||||
/* 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:
|
||||
if (isdigit(*in))
|
||||
{
|
||||
*out++ = *in;
|
||||
}
|
||||
else if (*in == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (*in == group_separator)
|
||||
{
|
||||
next_state = START_GROUP_ST;
|
||||
}
|
||||
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 (isdigit(*in))
|
||||
{
|
||||
*out++ = *in;
|
||||
group_count++; /* We record the number of digits
|
||||
* in the group for later checking. */
|
||||
next_state = IN_GROUP_ST;
|
||||
}
|
||||
else if (*in == 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 (isspace(group_separator) && isspace(decimal_point))
|
||||
next_state = DONE_ST;
|
||||
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 (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 (isdigit(*in))
|
||||
{
|
||||
*out++ = *in;
|
||||
group_count++; /* We record the number of digits
|
||||
* in the group for later checking. */
|
||||
}
|
||||
else if (*in == decimal_point)
|
||||
{
|
||||
next_state = FRAC_ST;
|
||||
}
|
||||
else if (*in == group_separator)
|
||||
{
|
||||
next_state = START_GROUP_ST;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* FRAC_ST means we are now parsing fractional digits. */
|
||||
case FRAC_ST:
|
||||
if (isdigit(*in))
|
||||
{
|
||||
*out++ = *in;
|
||||
}
|
||||
else if (*in == 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 (isspace(decimal_point))
|
||||
next_state = DONE_ST;
|
||||
else
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
else if (*in == group_separator)
|
||||
{
|
||||
/* If a subsequent group separator is also whitespace,
|
||||
* assume it was intended as such and stop parsing.
|
||||
* Otherwise, there is a problem. */
|
||||
if (isspace(group_separator))
|
||||
next_state = DONE_ST;
|
||||
else
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_state = DONE_ST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
PERR("bad state");
|
||||
g_assert_not_reached();
|
||||
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)) ||
|
||||
((next_state == DONE_ST) && !got_decimal))
|
||||
{
|
||||
*out = '\0';
|
||||
value = strtod(out_str, NULL);
|
||||
|
||||
if (value == HUGE_VAL)
|
||||
{
|
||||
next_state = NO_NUM_ST;
|
||||
}
|
||||
else if (next_state == FRAC_ST)
|
||||
{
|
||||
/* reset the out pointer to record the fraction */
|
||||
out = out_str;
|
||||
*out = '\0';
|
||||
|
||||
got_decimal = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
state = next_state;
|
||||
if (done_state (state))
|
||||
break;
|
||||
|
||||
in++;
|
||||
}
|
||||
|
||||
/* If there was an error, just quit */
|
||||
if (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;
|
||||
char *group;
|
||||
|
||||
group = monetary ? lc->mon_grouping : lc->grouping;
|
||||
|
||||
/* The groups were built in reverse order. This
|
||||
* is the easiest order to verify them in. */
|
||||
for (node = group_data; node; node = node->next)
|
||||
{
|
||||
/* Verify group size */
|
||||
if (*group != GPOINTER_TO_INT(node->data))
|
||||
{
|
||||
good_grouping = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if( auto_decimal_enabled ) {
|
||||
/* No decimal point and auto decimal point enabled, so assume that
|
||||
* the value is an integer number of cents or a cent-type unit.
|
||||
* For each auto decimal place requested, move the final decimal
|
||||
* point one place to the left.
|
||||
*/
|
||||
amount += ((double) (atoi (str)));
|
||||
for( i = 0; i < auto_decimal_places; i++ )
|
||||
amount *= 0.1;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* NOTE: further additions to amount after this point will
|
||||
* generate incorrect results.
|
||||
*/
|
||||
if (!good_grouping)
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
amount += ((double) (atoi (str)));
|
||||
}
|
||||
g_list_free(group_data);
|
||||
|
||||
if (isneg) amount = -amount;
|
||||
if (!good_grouping)
|
||||
{
|
||||
g_free(out_str);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
free (mstr);
|
||||
return amount;
|
||||
/* Cap the end of the fraction string, if any */
|
||||
*out = '\0';
|
||||
|
||||
/* Add in fractional value */
|
||||
if (got_decimal && (*out_str != '\0'))
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(out_str);
|
||||
|
||||
if (len > 8)
|
||||
{
|
||||
out_str[8] = '\0';
|
||||
len = 8;
|
||||
}
|
||||
|
||||
value += fractional_multiplier(len) * strtod(out_str, NULL);
|
||||
|
||||
if (value == HUGE_VAL)
|
||||
{
|
||||
g_free(out_str);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (auto_decimal_enabled && !got_decimal)
|
||||
{
|
||||
/* No decimal point and auto decimal point enabled, so assume
|
||||
* that the value is an integer number of cents or a cent-type
|
||||
* unit. For each auto decimal place requested, move the final
|
||||
* decimal point one place to the left. */
|
||||
if ((auto_decimal_places > 0) && (auto_decimal_places < 9))
|
||||
value *= fractional_multiplier(auto_decimal_places);
|
||||
}
|
||||
|
||||
if (is_negative)
|
||||
value = -value;
|
||||
|
||||
if (result != NULL)
|
||||
*result = value;
|
||||
|
||||
if (endstr != NULL)
|
||||
*endstr = (char *) in;
|
||||
|
||||
g_free (out_str);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -180,7 +180,6 @@ extern char *strcasestr(const char *str1, const char *str2);
|
||||
* An alernate (better??) implementation might be
|
||||
* #define strpskip(s,r) (s+strspn(s,r))
|
||||
*/
|
||||
|
||||
extern char * strpskip (const char * s, const char *reject);
|
||||
|
||||
/********************************************************/
|
||||
@ -188,7 +187,6 @@ extern char * strpskip (const char * s, const char *reject);
|
||||
* It accepts a number and prints it in the indicated base.
|
||||
* The returned string should be freed when done.
|
||||
*/
|
||||
|
||||
char * ultostr (unsigned long val, int base);
|
||||
|
||||
/* Returns true if string s is a number, possibly
|
||||
@ -268,8 +266,21 @@ const char * xaccPrintAmountArgs (double val,
|
||||
gboolean is_shares_value,
|
||||
const char *curr_code);
|
||||
|
||||
/* Parse i18n amount strings */
|
||||
double xaccParseAmount (const char * instr, gboolean monetary);
|
||||
|
||||
/* xaccParseAmount parses in_str to obtain a numeric result. The
|
||||
* routine will parse as much of in_str as it can to obtain a single
|
||||
* number. The number is parsed using the current locale information
|
||||
* and the 'monetary' flag. The routine will return TRUE if it
|
||||
* successfully parsed a number and FALSE otherwise. If TRUE is
|
||||
* returned and result is non-NULL, the value of the parsed number
|
||||
* is stored in *result. If FALSE is returned, *result is
|
||||
* unchanged. If TRUE is returned and endstr is non-NULL, the
|
||||
* location of the first character in in_str not used by the
|
||||
* parser will be returned in *endstr. If FALSE is returned
|
||||
* and endstr is non-NULL, *endstr will point to in_str.
|
||||
*/
|
||||
gboolean xaccParseAmount (const char * in_str, gboolean monetary,
|
||||
double *result, char **endstr);
|
||||
|
||||
|
||||
/** TEMPLATES ******************************************************/
|
||||
|
336
src/gnc-exp-parser.c
Normal file
336
src/gnc-exp-parser.c
Normal file
@ -0,0 +1,336 @@
|
||||
/********************************************************************\
|
||||
* gnc-exp-parser.c -- Implementation of expression parsing for *
|
||||
* GnuCash using the routines in 'calculation'. *
|
||||
* Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
|
||||
* *
|
||||
* This program 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 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "finproto.h"
|
||||
#include "fin_spl_protos.h"
|
||||
#include "gnc-exp-parser.h"
|
||||
#include "messages.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/** Data Types *****************************************************/
|
||||
|
||||
typedef struct ParserNum
|
||||
{
|
||||
double value;
|
||||
} ParserNum;
|
||||
|
||||
|
||||
/** Static Globals *************************************************/
|
||||
static GHashTable *variable_bindings = NULL;
|
||||
static ParseError last_error = PARSER_NO_ERROR;
|
||||
static gboolean parser_inited = FALSE;
|
||||
|
||||
|
||||
/** Implementations ************************************************/
|
||||
|
||||
void
|
||||
gnc_exp_parser_init (void)
|
||||
{
|
||||
if (parser_inited)
|
||||
gnc_exp_parser_shutdown ();
|
||||
|
||||
variable_bindings = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
parser_inited = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
remove_binding (gpointer key, gpointer value, gpointer not_used)
|
||||
{
|
||||
g_free(key);
|
||||
g_free(value);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_exp_parser_shutdown (void)
|
||||
{
|
||||
if (!parser_inited)
|
||||
return;
|
||||
|
||||
g_hash_table_foreach_remove (variable_bindings, remove_binding, NULL);
|
||||
g_hash_table_destroy (variable_bindings);
|
||||
variable_bindings = NULL;
|
||||
|
||||
last_error = PARSER_NO_ERROR;
|
||||
|
||||
parser_inited = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
prepend_name (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
GList **list = data;
|
||||
|
||||
*list = g_list_prepend (*list, key);
|
||||
}
|
||||
|
||||
GList *
|
||||
gnc_exp_parser_get_variable_names (void)
|
||||
{
|
||||
GList *names = NULL;
|
||||
|
||||
if (!parser_inited)
|
||||
return NULL;
|
||||
|
||||
g_hash_table_foreach (variable_bindings, prepend_name, &names);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_exp_parser_remove_variable (const char *variable_name)
|
||||
{
|
||||
gpointer key;
|
||||
gpointer value;
|
||||
|
||||
if (!parser_inited)
|
||||
return;
|
||||
|
||||
if (variable_name == NULL)
|
||||
return;
|
||||
|
||||
if (g_hash_table_lookup_extended (variable_bindings, variable_name,
|
||||
&key, &value))
|
||||
{
|
||||
g_hash_table_remove (variable_bindings, key);
|
||||
g_free(key);
|
||||
g_free(value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gnc_exp_parser_remove_variable_names (GList * variable_names)
|
||||
{
|
||||
if (!parser_inited)
|
||||
return;
|
||||
|
||||
while (variable_names != NULL)
|
||||
{
|
||||
gnc_exp_parser_remove_variable (variable_names->data);
|
||||
variable_names = variable_names->next;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gnc_exp_parser_get_value (const char * variable_name, double *value_p)
|
||||
{
|
||||
ParserNum *pnum;
|
||||
|
||||
if (!parser_inited)
|
||||
return FALSE;
|
||||
|
||||
if (variable_name == NULL)
|
||||
return FALSE;
|
||||
|
||||
pnum = g_hash_table_lookup (variable_bindings, variable_name);
|
||||
if (pnum == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (value_p != NULL)
|
||||
*value_p = pnum->value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gnc_exp_parser_set_value (const char * variable_name, double value)
|
||||
{
|
||||
char *key;
|
||||
ParserNum *pnum;
|
||||
|
||||
if (variable_name == NULL)
|
||||
return;
|
||||
|
||||
if (!parser_inited)
|
||||
gnc_exp_parser_init ();
|
||||
|
||||
gnc_exp_parser_remove_variable (variable_name);
|
||||
|
||||
key = g_strdup (variable_name);
|
||||
|
||||
pnum = g_new(ParserNum, 1);
|
||||
pnum->value = value;
|
||||
|
||||
g_hash_table_insert (variable_bindings, key, pnum);
|
||||
}
|
||||
|
||||
static void
|
||||
make_predefined_vars_helper (gpointer key, gpointer value, gpointer data)
|
||||
{
|
||||
var_store_ptr *vars_p = data;
|
||||
var_store_ptr var;
|
||||
|
||||
var = g_new0 (var_store, 1);
|
||||
|
||||
var->variable_name = key;
|
||||
var->value = value;
|
||||
var->next_var = *vars_p;
|
||||
|
||||
*vars_p = var;
|
||||
}
|
||||
|
||||
static var_store_ptr
|
||||
make_predefined_variables (void)
|
||||
{
|
||||
var_store_ptr vars = NULL;
|
||||
|
||||
g_hash_table_foreach (variable_bindings, make_predefined_vars_helper, &vars);
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
static void *
|
||||
trans_numeric(const char *digit_str,
|
||||
char radix_point,
|
||||
char group_char,
|
||||
char **rstr)
|
||||
{
|
||||
ParserNum *pnum;
|
||||
double value;
|
||||
|
||||
if (digit_str == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!xaccParseAmount (digit_str, TRUE, &value, rstr))
|
||||
return NULL;
|
||||
|
||||
pnum = g_new0(ParserNum, 1);
|
||||
pnum->value = value;
|
||||
|
||||
return pnum;
|
||||
}
|
||||
|
||||
static void *
|
||||
numeric_ops(char op_sym,
|
||||
void *left_value,
|
||||
void *right_value)
|
||||
{
|
||||
ParserNum *left = left_value;
|
||||
ParserNum *right = right_value;
|
||||
ParserNum *result;
|
||||
|
||||
if ((left == NULL) || (right == NULL))
|
||||
return NULL;
|
||||
|
||||
result = (op_sym == ASN_OP) ? left : g_new(ParserNum, 1);
|
||||
|
||||
switch (op_sym)
|
||||
{
|
||||
case ADD_OP:
|
||||
result->value = left->value + right->value;
|
||||
break;
|
||||
case SUB_OP:
|
||||
result->value = left->value - right->value;
|
||||
break;
|
||||
case DIV_OP:
|
||||
result->value = left->value / right->value;
|
||||
break;
|
||||
case MUL_OP:
|
||||
result->value = left->value * right->value;
|
||||
break;
|
||||
case ASN_OP:
|
||||
result->value = right->value;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void *
|
||||
negate_numeric(void *value)
|
||||
{
|
||||
ParserNum *result = value;
|
||||
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
|
||||
result->value = -result->value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gnc_exp_parser_parse (const char * expression, double *value_p,
|
||||
char **error_loc_p)
|
||||
{
|
||||
parser_env_ptr pe;
|
||||
var_store_ptr vars;
|
||||
struct lconv *lc;
|
||||
var_store result;
|
||||
char * error_loc;
|
||||
ParserNum *pnum;
|
||||
|
||||
if (expression == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!parser_inited)
|
||||
gnc_exp_parser_init ();
|
||||
|
||||
result.variable_name = NULL;
|
||||
result.value = NULL;
|
||||
result.next_var = NULL;
|
||||
|
||||
vars = make_predefined_variables ();
|
||||
lc = gnc_localeconv ();
|
||||
|
||||
pe = init_parser (vars, *lc->mon_decimal_point, *lc->mon_thousands_sep,
|
||||
trans_numeric, numeric_ops, negate_numeric, g_free);
|
||||
|
||||
error_loc = parse_string (&result, expression, pe);
|
||||
|
||||
pnum = result.value;
|
||||
|
||||
if (error_loc == NULL)
|
||||
{
|
||||
if ((value_p != NULL) && (pnum != NULL))
|
||||
*value_p = pnum->value;
|
||||
|
||||
if (error_loc_p != NULL)
|
||||
*error_loc_p = NULL;
|
||||
|
||||
last_error = PARSER_NO_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_loc_p != NULL)
|
||||
*error_loc_p = error_loc;
|
||||
|
||||
last_error = get_parse_error (pe);
|
||||
}
|
||||
|
||||
/* fixme: update variables and free predefined variables */
|
||||
|
||||
exit_parser (pe);
|
||||
|
||||
return (error_loc == NULL);
|
||||
}
|
||||
|
||||
const char *
|
||||
gnc_exp_parser_error_string (void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
71
src/gnc-exp-parser.h
Normal file
71
src/gnc-exp-parser.h
Normal file
@ -0,0 +1,71 @@
|
||||
/********************************************************************\
|
||||
* gnc-exp-parser.h -- Interface to expression parsing for GnuCash *
|
||||
* Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
|
||||
* *
|
||||
* This program 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 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef __GNC_EXP_PARSER_H__
|
||||
#define __GNC_EXP_PARSER_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
/* Initialize the expression parser. If this function is not
|
||||
* called before one of the other parsing routines (other than
|
||||
* gnc_exp_parser_shutdown), it will be called if needed. */
|
||||
void gnc_exp_parser_init (void);
|
||||
|
||||
/* Shutdown the expression parser and free any associated memory. */
|
||||
void gnc_exp_parser_shutdown (void);
|
||||
|
||||
/* Return a list of variable names which are currently defined
|
||||
* in the parser. The names should not be modified or freed. */
|
||||
GList * gnc_exp_parser_get_variable_names (void);
|
||||
|
||||
/* Undefine the variable name if it is already defined. */
|
||||
void gnc_exp_parser_remove_variable (const char *variable_name);
|
||||
|
||||
/* Undefine every variable name appearing in the list. Variables in
|
||||
* the list which are not defined are ignored. */
|
||||
void gnc_exp_parser_remove_variable_names (GList * variable_names);
|
||||
|
||||
/* Return TRUE if the variable is defined, FALSE otherwise. If defined
|
||||
* and value_p != NULL, return the value in *value_p, otherwise, *value_p
|
||||
* is unchanged. */
|
||||
gboolean gnc_exp_parser_get_value (const char * variable_name,
|
||||
double *value_p);
|
||||
|
||||
/* Set the value of the variable to the given value. If the variable is
|
||||
* not already defined, it will be after the call. */
|
||||
void gnc_exp_parser_set_value (const char * variable_name, double value);
|
||||
|
||||
/* Parse the given expression using the current variable definitions.
|
||||
* If the parse was successful, return TRUE and, if value_p is
|
||||
* non-NULL, return the value of the resulting expression in *value_p.
|
||||
* Otherwise, return FALSE and *value_p is unchanged. If FALSE is
|
||||
* returned and error_loc_p is non-NULL, *error_loc_p is set to the
|
||||
* character in expression where parsing aborted. If TRUE is returned
|
||||
* and error_loc_p is non-NULL, *error_loc_p is set to NULL. */
|
||||
gboolean gnc_exp_parser_parse (const char * expression, double *value_p,
|
||||
char **error_loc_p);
|
||||
|
||||
/* If the last parse returned FALSE, return an error string describing
|
||||
* the problem. Otherwise, return NULL. */
|
||||
const char * gnc_exp_parser_error_string (void);
|
||||
|
||||
#endif
|
@ -864,7 +864,8 @@ subentry_amount_entry_focus_out(GtkWidget *widget, GdkEventFocus *event,
|
||||
if ((string == NULL) || (*string == '\0'))
|
||||
return FALSE;
|
||||
|
||||
value = xaccParseAmount(string, TRUE);
|
||||
value = 0.0;
|
||||
xaccParseAmount(string, TRUE, &value, NULL);
|
||||
|
||||
new_string = xaccPrintAmount(value, PRTSEP, NULL);
|
||||
|
||||
|
@ -170,16 +170,17 @@ gui_to_fi(FinCalcDialog *fcd)
|
||||
fcd->financial_info.npp = strtol(string, NULL, 10);
|
||||
|
||||
string = gtk_entry_get_text(GTK_ENTRY(fcd->entries[INTEREST_RATE]));
|
||||
fcd->financial_info.ir = xaccParseAmount(string, FALSE);
|
||||
xaccParseAmount(string, FALSE, &fcd->financial_info.ir, NULL);
|
||||
|
||||
string = gtk_entry_get_text(GTK_ENTRY(fcd->entries[PRESENT_VALUE]));
|
||||
fcd->financial_info.pv = xaccParseAmount(string, TRUE);
|
||||
xaccParseAmount(string, TRUE, &fcd->financial_info.pv, NULL);
|
||||
|
||||
string = gtk_entry_get_text(GTK_ENTRY(fcd->entries[PERIODIC_PAYMENT]));
|
||||
fcd->financial_info.pmt = xaccParseAmount(string, TRUE);
|
||||
xaccParseAmount(string, TRUE, &fcd->financial_info.pmt, NULL);
|
||||
|
||||
string = gtk_entry_get_text(GTK_ENTRY(fcd->entries[FUTURE_VALUE]));
|
||||
fcd->financial_info.fv = -xaccParseAmount(string, TRUE);
|
||||
if (xaccParseAmount(string, TRUE, &fcd->financial_info.fv, NULL))
|
||||
fcd->financial_info.fv = -fcd->financial_info.fv;
|
||||
|
||||
i = gnc_option_menu_get_active(fcd->compounding_menu);
|
||||
fcd->financial_info.CF = periods[i];
|
||||
@ -327,7 +328,8 @@ can_calc_value(FinCalcDialog *fcd, FinCalcValue value)
|
||||
case PERIODIC_PAYMENT:
|
||||
case FUTURE_VALUE:
|
||||
string = gtk_entry_get_text(GTK_ENTRY(fcd->entries[INTEREST_RATE]));
|
||||
dvalue = xaccParseAmount(string, FALSE);
|
||||
dvalue = 0.0;
|
||||
xaccParseAmount(string, FALSE, &dvalue, NULL);
|
||||
if (DEQ(dvalue, 0.0))
|
||||
return CALC_INTEREST_MSG;
|
||||
break;
|
||||
|
@ -158,7 +158,8 @@ gnc_xfer_update_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
|
||||
if ((string == NULL) || (*string == 0))
|
||||
return FALSE;
|
||||
|
||||
value = xaccParseAmount(string, TRUE);
|
||||
value = 0.0;
|
||||
xaccParseAmount(string, TRUE, &value, NULL);
|
||||
|
||||
currency = xaccAccountGetCurrency(account);
|
||||
|
||||
@ -325,7 +326,8 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
|
||||
}
|
||||
|
||||
string = gtk_entry_get_text(GTK_ENTRY(xferData->amount_entry));
|
||||
amount = xaccParseAmount(string, TRUE);
|
||||
amount = 0.0;
|
||||
xaccParseAmount(string, TRUE, &amount, NULL);
|
||||
|
||||
time = gnc_date_edit_get_date(GNC_DATE_EDIT(xferData->date_entry));
|
||||
|
||||
|
@ -110,15 +110,16 @@ gnc_ui_AdjBWindow_cancel_cb(GtkWidget * widget, gpointer data)
|
||||
static void
|
||||
gnc_ui_AdjBWindow_ok_cb(GtkWidget * widget, gpointer data)
|
||||
{
|
||||
AdjBWindow *adjBData = (AdjBWindow *) data;
|
||||
AdjBWindow *adjBData = data;
|
||||
Transaction *trans;
|
||||
Split *source_split;
|
||||
time_t time;
|
||||
double new_balance, current_balance;
|
||||
double new_balance = 0.0;
|
||||
double current_balance;
|
||||
gchar * string;
|
||||
time_t time;
|
||||
|
||||
string = gtk_entry_get_text(GTK_ENTRY(adjBData->balance_entry));
|
||||
new_balance = xaccParseAmount(string, TRUE);
|
||||
xaccParseAmount(string, TRUE, &new_balance, NULL);
|
||||
if (gnc_reverse_balance(adjBData->account))
|
||||
new_balance = -new_balance;
|
||||
|
||||
@ -164,7 +165,8 @@ gnc_adjust_update_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
|
||||
|
||||
string = gtk_entry_get_text(entry);
|
||||
|
||||
value = xaccParseAmount(string, TRUE);
|
||||
value = 0.0;
|
||||
xaccParseAmount(string, TRUE, &value, NULL);
|
||||
|
||||
currency = xaccAccountGetCurrency(account);
|
||||
|
||||
|
@ -269,7 +269,8 @@ gnc_start_recn_update_cb(GtkWidget *widget, GdkEventFocus *event,
|
||||
|
||||
string = gtk_entry_get_text(entry);
|
||||
|
||||
value = xaccParseAmount(string, TRUE);
|
||||
value = 0.0;
|
||||
xaccParseAmount(string, TRUE, &value, NULL);
|
||||
|
||||
account_type = xaccAccountGetType(account);
|
||||
if ((account_type == STOCK) || (account_type == MUTUAL) ||
|
||||
@ -413,7 +414,8 @@ startRecnWindow(GtkWidget *parent, Account *account,
|
||||
|
||||
string = gtk_entry_get_text(GTK_ENTRY(end_value));
|
||||
|
||||
*new_ending = xaccParseAmount(string, TRUE);
|
||||
*new_ending = 0.0;
|
||||
xaccParseAmount(string, TRUE, new_ending, NULL);
|
||||
*statement_date = gnc_date_edit_get_date(GNC_DATE_EDIT(date_value));
|
||||
|
||||
if (gnc_reverse_balance(account))
|
||||
|
@ -131,8 +131,8 @@ PriceMV (BasicCell *_cell,
|
||||
if (1 < count) return NULL;
|
||||
}
|
||||
|
||||
/* parse the float pt value and store it */
|
||||
cell->amount = xaccParseAmount (newval, cell->monetary);
|
||||
/* parse the value and store it */
|
||||
xaccParseAmount (newval, cell->monetary, &cell->amount, NULL);
|
||||
SET ((&(cell->cell)), newval);
|
||||
return newval;
|
||||
}
|
||||
@ -144,7 +144,17 @@ PriceLeave (BasicCell *_cell, const char *val)
|
||||
{
|
||||
PriceCell *cell = (PriceCell *) _cell;
|
||||
char *newval;
|
||||
double amount;
|
||||
|
||||
if (val == NULL)
|
||||
val = "";
|
||||
|
||||
if (*val == '\0')
|
||||
amount = 0.0;
|
||||
else if (!xaccParseAmount (val, cell->monetary, &amount, NULL))
|
||||
amount = 0.0;
|
||||
|
||||
cell->amount = amount;
|
||||
newval = xaccPriceCellPrintValue(cell);
|
||||
|
||||
/* If they are identical, return the original */
|
||||
@ -168,7 +178,10 @@ PriceHelp (BasicCell *bcell)
|
||||
{
|
||||
char *help_str;
|
||||
|
||||
help_str = xaccPriceCellPrintValue(cell);
|
||||
if (xaccParseAmount(bcell->value, cell->monetary, NULL, NULL))
|
||||
help_str = xaccPriceCellPrintValue(cell);
|
||||
else
|
||||
help_str = bcell->value;
|
||||
|
||||
return g_strdup(help_str);
|
||||
}
|
||||
@ -371,12 +384,10 @@ PriceSetValue (BasicCell *_cell, const char *str)
|
||||
if (str == NULL)
|
||||
str = "";
|
||||
|
||||
if (!cell->blank_zero && (*str == '\0'))
|
||||
xaccSetPriceCellBlank(cell);
|
||||
else {
|
||||
amount = xaccParseAmount (str, cell->monetary);
|
||||
xaccSetPriceCellValue (cell, amount);
|
||||
}
|
||||
if (*str == '\0')
|
||||
xaccSetPriceCellValue (cell, 0.0);
|
||||
else if (xaccParseAmount (str, cell->monetary, &amount, NULL))
|
||||
xaccSetPriceCellValue (cell, amount);
|
||||
}
|
||||
|
||||
/* --------------- end of file ---------------------- */
|
||||
|
Loading…
Reference in New Issue
Block a user