2002-05-21 Joshua Sled <jsled@asynchronous.org>

* src/gnome/dialog-sx-from-trans.c (sxftd_get_end_info): Changed
	to do the strtoul before we free the data itself; fixes "can't
	create once/number-of-occurance SXes" [in from-transaction dialog]
	bug.

	* src/gnome/dialog-scheduledxaction.c (editor_ok_button_clicked):
	Do a very lame but good-enough-for-now check to see if we can
	determine if the template transactions will still balance.  Note
	that we don't do anything with the result of that check, yet, but
	we perform it.

	* src/app-utils/gnc-exp-parser.c (gnc_exp_parser_real_init): Added
	so we can conditionaly add the "predefined variables" to the
	binding table for parsing a given expression.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6886 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Joshua Sled 2002-05-22 03:01:43 +00:00
parent b443bcf002
commit 9ca6b3d830
8 changed files with 199 additions and 89 deletions

View File

@ -1,3 +1,20 @@
2002-05-21 Joshua Sled <jsled@asynchronous.org>
* src/gnome/dialog-sx-from-trans.c (sxftd_get_end_info): Changed
to do the strtoul before we free the data itself; fixes "can't
create once/number-of-occurance SXes" [in from-transaction dialog]
bug.
* src/gnome/dialog-scheduledxaction.c (editor_ok_button_clicked):
Do a very lame but good-enough-for-now check to see if we can
determine if the template transactions will still balance. Note
that we don't do anything with the result of that check, yet, but
we perform it.
* src/app-utils/gnc-exp-parser.c (gnc_exp_parser_real_init): Added
so we can conditionaly add the "predefined variables" to the
binding table for parsing a given expression.
2002-05-18 David Hampton <hampton@employees.org>
* configure.in: Work around incompatibilities between autoconf

View File

@ -50,7 +50,13 @@ static gboolean parser_inited = FALSE;
/** Implementations ************************************************/
void
gnc_exp_parser_init (void)
gnc_exp_parser_init ( void )
{
gnc_exp_parser_real_init( TRUE );
}
void
gnc_exp_parser_real_init ( gboolean addPredefined )
{
SCM alist;
@ -62,57 +68,60 @@ gnc_exp_parser_init (void)
/* This comes after the statics have been initialized. Not at the end! */
parser_inited = TRUE;
alist = gnc_lookup_option ("__exp_parser", "defined_variables", SCM_EOL);
if ( addPredefined ) {
alist = gnc_lookup_option ("__exp_parser", "defined_variables", SCM_EOL);
while (gh_list_p(alist) && !gh_null_p(alist))
{
char *name;
SCM assoc;
SCM val_scm;
gnc_numeric value;
gboolean good;
while (gh_list_p(alist) && !gh_null_p(alist))
{
char *name;
SCM assoc;
SCM val_scm;
gnc_numeric value;
gboolean good;
assoc = gh_car (alist);
alist = gh_cdr (alist);
assoc = gh_car (alist);
alist = gh_cdr (alist);
if (!gh_pair_p (assoc))
continue;
if (!gh_pair_p (assoc))
continue;
name = gh_scm2newstr (gh_car (assoc), NULL);
if (name == NULL)
continue;
name = gh_scm2newstr (gh_car (assoc), NULL);
if (name == NULL)
continue;
val_scm = gh_cdr (assoc);
good = TRUE;
val_scm = gh_cdr (assoc);
good = TRUE;
if (gh_number_p (val_scm))
{
double dvalue;
if (gh_number_p (val_scm))
{
double dvalue;
dvalue = gh_scm2double (val_scm);
value = double_to_gnc_numeric (dvalue, GNC_DENOM_AUTO,
GNC_DENOM_SIGFIGS(6) | GNC_RND_ROUND);
}
else if (gh_string_p (val_scm))
{
char *s;
const char *err;
dvalue = gh_scm2double (val_scm);
value = double_to_gnc_numeric (dvalue, GNC_DENOM_AUTO,
GNC_DENOM_SIGFIGS(6)
| GNC_RND_ROUND);
}
else if (gh_string_p (val_scm))
{
char *s;
const char *err;
s = gh_scm2newstr (val_scm, NULL);
s = gh_scm2newstr (val_scm, NULL);
err = string_to_gnc_numeric (s, &value);
if (err == NULL)
good = FALSE;
err = string_to_gnc_numeric (s, &value);
if (err == NULL)
good = FALSE;
free (s);
}
else
good = FALSE;
free (s);
}
else
good = FALSE;
if (good)
gnc_exp_parser_set_value (name, gnc_numeric_reduce (value));
if (good)
gnc_exp_parser_set_value (name, gnc_numeric_reduce (value));
free (name);
free (name);
}
}
}
@ -431,7 +440,7 @@ gnc_exp_parser_parse_separate_vars (const char * expression,
return FALSE;
if (!parser_inited)
gnc_exp_parser_init ();
gnc_exp_parser_real_init ( (varHash == NULL) );
result.variable_name = NULL;
result.value = NULL;
@ -509,7 +518,6 @@ gnc_exp_parser_parse_separate_vars (const char * expression,
}
} else {
update_variables (vars);
update_variables (parser_get_vars (pe));
}
free_predefined_variables (vars);

View File

@ -32,6 +32,15 @@
*/
void gnc_exp_parser_init (void);
/**
* The real init function, which takes an option to add the pre-defined vars
* to the variable table. This option is used by
* gnc_exp_parser_parse_seperate_vars [itself used by the Scheduled
* Transaction code] to parse without using any "predefined" application
* variables.
**/
void gnc_exp_parser_real_init( gboolean addPredefined );
/* Shutdown the expression parser and free any associated memory in the ParserState. */
void gnc_exp_parser_shutdown (void);

View File

@ -121,8 +121,6 @@ X create a template register
. make-from-transaction
. bugs
. number-of-instances in 'simple' results in "Warning:
sxftd_advanced_clicked: something bad happened in sxftd_compute_sx"
. general: there's going to be all sorts of interaction issues like these
between these things [SX-from-trans, SX list, SX editor] that should be
handled.
@ -138,6 +136,8 @@ X create a template register
X 20020419 - Wilddev manages to create two SXes from one; the first is
okay, but the second is h0rk3d [deleting it causes segfault, though it
can be instantiated correctly].
X number-of-instances in 'simple' results in "Warning:
sxftd_advanced_clicked: something bad happened in sxftd_compute_sx"
. tab-order
. better frequency guess?
[ related... ]
@ -237,9 +237,10 @@ X create a template register
. recn?
. deal better with formulas in template transactions [real FormulaCell]
. recognize purely numeric template transactions and balance at
. actually do something with the result of the balancing computation
/ recognize purely numeric template transactions and balance at
template-creation time.
. balance transaction with vars?
/ balance transaction with vars?
. GNCFrequency
. initial-settings synchronization [start date, optionmenus]

View File

@ -230,6 +230,16 @@ local_print_helper( gpointer key, gpointer value, gpointer ud )
}
#endif
static void
set_var_to_random_value( gpointer key, gpointer value, gpointer ud )
{
gnc_numeric *val;
val = g_new0( gnc_numeric, 1 );
*val = double_to_gnc_numeric( rand() + 2, 1,
GNC_NUMERIC_RND_MASK | GNC_RND_FLOOR );
g_hash_table_insert( ud, key, val );
}
static
void
editor_ok_button_clicked( GtkButton *b, SchedXactionEditorDialog *sxed )
@ -259,20 +269,37 @@ editor_ok_button_clicked( GtkButton *b, SchedXactionEditorDialog *sxed )
gnc_split_register_save ( gnc_ledger_display_get_split_register(sxed->ledger),
FALSE );
#if 0
/* FIXME: leave for now; will use for numeric-formulas-get-balanced
* determination later. */
/* numeric-formulas-get-balanced determination */
{
GHashTable *ht;
GHashTable *vars;
GList *splitList = NULL;
char *str;
kvp_frame *f;
kvp_value *v;
Split *s;
gnc_numeric creditSum, debitSum, tmp;
ht = g_hash_table_new( NULL, NULL );
creditSum = debitSum = gnc_numeric_zero();
vars = g_hash_table_new( g_str_hash, g_str_equal );
splitList = xaccSchedXactionGetSplits( sxed->sx );
/**
* Plan:
* . Do a first pass to get the variables.
* . Set each variable to random values.
* . see if we balance after that
* . true: all good
* . false: indicate to user, allow decision.
*/
sxsl_get_sx_vars( sxed->sx, vars );
if ( g_hash_table_size( vars ) == 0 ) {
/* FIXME: just balance as is, DTRT. */
}
/* FIXME: since we have variables, we can deal with any
* possible auto-create flaggage. */
g_hash_table_foreach( vars, set_var_to_random_value,
(gpointer)vars );
for ( ; splitList; splitList = splitList->next ) {
s = (Split*)splitList->data;
f = xaccSplitGetSlots( s );
@ -283,7 +310,14 @@ editor_ok_button_clicked( GtkButton *b, SchedXactionEditorDialog *sxed )
if ( v
&& (str = kvp_value_get_string(v))
&& strlen( str ) != 0 ) {
parse_vars_from_formula( str, ht );
if ( parse_vars_from_formula( str, vars, &tmp ) < 0 ) {
PERR( "Couldn't parse credit formula for "
"\"%s\" on second pass",
xaccSchedXactionGetName( sxed->sx ) );
return;
}
creditSum = gnc_numeric_add_fixed( creditSum, tmp );
tmp = gnc_numeric_zero();
}
v = kvp_frame_get_slot_path( f,
GNC_SX_ID,
@ -292,16 +326,29 @@ editor_ok_button_clicked( GtkButton *b, SchedXactionEditorDialog *sxed )
if ( v
&& (str = kvp_value_get_string(v))
&& strlen(str) != 0 ) {
parse_vars_from_formula( str, ht );
if ( parse_vars_from_formula( str, vars, &tmp ) < 0 ) {
PERR( "Couldn't parse debit formula for "
"\"%s\" on second pass",
xaccSchedXactionGetName( sxed->sx ) );
return;
}
debitSum = gnc_numeric_add_fixed( debitSum, tmp );
tmp = gnc_numeric_zero();
}
g_hash_table_foreach( ht, local_print_helper, NULL );
}
if ( g_hash_table_size( ht ) == 0 ) {
if ( gnc_numeric_zero_p( gnc_numeric_sub_fixed( debitSum, creditSum ) ) ) {
printf( "true [%s - %s = %s]\n",
gnc_numeric_to_string( debitSum ),
gnc_numeric_to_string( creditSum ),
gnc_numeric_to_string(gnc_numeric_sub_fixed( debitSum, creditSum )) );
} else {
printf( "false [%s - %s = %s]\n",
gnc_numeric_to_string( debitSum ),
gnc_numeric_to_string( creditSum ),
gnc_numeric_to_string(gnc_numeric_sub_fixed( debitSum, creditSum )) );
}
g_hash_table_destroy( ht );
g_hash_table_destroy( vars );
}
#endif /* 0 */
/* read out data back into SchedXaction object. */

View File

@ -128,8 +128,9 @@ sxftd_get_end_info(SXFromTransInfo *sxfti)
getEndTuple retval;
GtkWidget *w;
retval.type = BAD_END;
w = glade_xml_get_widget(sxfti->gxml, SXFTD_NEVER_END_BUTTON);
if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(w)))
{
retval.type = NEVER_END;
@ -137,7 +138,6 @@ sxftd_get_end_info(SXFromTransInfo *sxfti)
}
w = glade_xml_get_widget(sxfti->gxml, SXFTD_END_ON_DATE_BUTTON);
if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(w)))
{
time_t end_tt;
@ -160,9 +160,11 @@ sxftd_get_end_info(SXFromTransInfo *sxfti)
text = gtk_editable_get_chars(GTK_EDITABLE(w), 0, -1);
n_occs = strtoul(text, &endptr, 10);
free(text);
if(!endptr && n_occs > 0)
if ( !endptr ) {
n_occs = -1;
}
g_free(text);
if(n_occs > 0)
{
retval.type = END_AFTER_N_OCCS;
retval.n_occurrences = n_occs;
@ -170,7 +172,6 @@ sxftd_get_end_info(SXFromTransInfo *sxfti)
}
}
retval.type = BAD_END;
return retval;
}
@ -386,7 +387,7 @@ sxftd_compute_sx(SXFromTransInfo *sxfti)
break;
}
sxftd_add_template_trans( sxfti);
sxftd_add_template_trans( sxfti );
return sxftd_errno;
}
@ -415,7 +416,11 @@ sxftd_ok_clicked(GtkWidget *w, gpointer user_data)
GList *sx_list;
guint sx_error = sxftd_compute_sx(sxfti);
if (sx_error == 0)
if (sx_error != 0)
{
PERR( "Error in sxftd_compute_sx after ok_clicked [%d]", sx_error );
}
else
{
book = gnc_get_current_book ();
sx_list = gnc_book_get_schedxactions(book);
@ -474,7 +479,7 @@ sxftd_advanced_clicked(GtkWidget *w, gpointer user_data)
if (sx_error != 0)
{
PWARN( "something bad happened in sxftd_compute_sx" );
PWARN( "something bad happened in sxftd_compute_sx [%d]", sx_error );
return;
}
gtk_widget_hide( sxfti->dialog );

View File

@ -257,8 +257,6 @@ static gboolean inform_or_add( GList *reminders,
reminderTuple *rt, gboolean okFlag,
GList *badList, GList **goodList );
int parse_vars_from_formula( const char *formula, GHashTable *varHash );
static void sx_obsolete_select_all_clicked(GtkButton *button,
gpointer user_data);
static void sx_obsolete_unselect_all_clicked(GtkButton *button,
@ -1383,7 +1381,7 @@ sxsincelast_entry_changed( GtkEditable *e, gpointer ud )
gchar *varName;
toCreateTuple *tct;
gchar *entryText;
gnc_numeric *num;
gnc_numeric *num, *ourNum;
GHashTable *dummyVarHash;
sxsld = (sxSinceLastData*)ud;
@ -1397,17 +1395,14 @@ sxsincelast_entry_changed( GtkEditable *e, gpointer ud )
if ( !gnc_exp_parser_parse_separate_vars( entryText, num,
NULL, dummyVarHash ) ) {
DEBUG( "error parsing entry \"%s\"", entryText );
g_free( num );
num = NULL;
} else if ( g_hash_table_size( dummyVarHash ) != 0 ) {
DEBUG( "no new variables allowed in variable "
"bindings for expression \"%s\"", entryText );
g_free( num );
num = NULL;
} else if ( gnc_numeric_check( *num ) != GNC_ERROR_OK ) {
DEBUG( "entry \"%s\" is not "
"gnc_numeric-parseable", entryText );
g_free( num );
num = NULL;
} else {
DEBUG( "\"%s\" parses as \"%f\"", entryText,
@ -1419,13 +1414,21 @@ sxsincelast_entry_changed( GtkEditable *e, gpointer ud )
{
gpointer maybeKey, maybeValue;
ourNum = NULL;
if ( num ) {
ourNum = g_new0( gnc_numeric, 1 );
*ourNum = *num;
}
if ( g_hash_table_lookup_extended( tct->varBindings, varName,
&maybeKey, &maybeValue ) ) {
g_hash_table_remove( tct->varBindings, maybeKey );
g_free( maybeValue );
/* only if not null. */
if ( maybeValue ) {
g_free( maybeValue );
}
/* FIXME: Does the maybeKey need to be freed? */
}
g_hash_table_insert( tct->varBindings, maybeKey, num );
g_hash_table_insert( tct->varBindings, maybeKey, ourNum );
}
{
@ -1810,7 +1813,7 @@ sxsl_get_sx_vars( SchedXaction *sx, GHashTable *varHash )
if ( kvp_val != NULL ) {
str = kvp_value_get_string( kvp_val );
if ( str && strlen(str) != 0 ) {
parse_vars_from_formula( str, varHash );
parse_vars_from_formula( str, varHash, NULL );
}
}
@ -1821,7 +1824,7 @@ sxsl_get_sx_vars( SchedXaction *sx, GHashTable *varHash )
if ( kvp_val != NULL ) {
str = kvp_value_get_string( kvp_val );
if ( str && strlen(str) != 0 ) {
parse_vars_from_formula( str, varHash );
parse_vars_from_formula( str, varHash, NULL );
}
}
}
@ -2014,6 +2017,7 @@ sxsincelast_tc_row_unsel( GtkCList *clist,
sxsld = (sxSinceLastData*)user_data;
clean_variable_table( sxsld );
/* FIXME: need to cleanup the gnc_numerics we allocated */
}
void
@ -2025,18 +2029,34 @@ print_vars_helper( gpointer key, gpointer value, gpointer user_data )
}
int
parse_vars_from_formula( const char *formula, GHashTable *varHash )
parse_vars_from_formula( const char *formula,
GHashTable *varHash,
gnc_numeric *result )
{
gnc_numeric numeric;
char *foo;
if ( ! gnc_exp_parser_parse_separate_vars( formula, &numeric,
&foo, varHash ) ) {
PERR( "Error parsing at \"%s\": %s",
foo, gnc_exp_parser_error_string() );
return -1;
gnc_numeric *num;
char *errLoc;
int toRet;
if ( result ) {
num = result;
} else {
num = g_new0( gnc_numeric, 1 );
}
return 0;
if ( ! gnc_exp_parser_parse_separate_vars( formula, num,
&errLoc, varHash ) ) {
PERR( "Error parsing at \"%s\": %s",
errLoc, gnc_exp_parser_error_string() );
toRet = -1;
goto cleanup;
}
toRet = 0;
cleanup:
if ( !result ) {
g_free( num );
}
return toRet;
}
/**

View File

@ -35,8 +35,11 @@ void sxsl_get_sx_vars( SchedXaction *sx, GHashTable *varHash );
/**
* Returns the variables from the given formula [free-form non-numeric
* character strings] as the keys of the given GHashTable.
* @param result can be NULL if you're not interested in the result
**/
int parse_vars_from_formula( const char *formula, GHashTable *varHash );
int parse_vars_from_formula( const char *formula,
GHashTable *varHash,
gnc_numeric *result );
void print_vars_helper( gpointer key, gpointer value, gpointer user_data );