24 #include <glib/gi18n.h>
32 #include "fin_spl_protos.h"
35 #include "gnc-exp-parser.h"
37 #include "gnc-locale-utils.h"
38 #include "guile-mappings.h"
40 #define GEP_GROUP_NAME "Variables"
53 static GHashTable *variable_bindings = NULL;
54 static ParseError last_error = PARSER_NO_ERROR;
55 static GNCParseError last_gncp_error = NO_ERR;
56 static gboolean parser_inited = FALSE;
62 gnc_exp_parser_filname (
void)
68 gnc_exp_parser_init (
void )
70 gnc_exp_parser_real_init( TRUE );
74 gnc_exp_parser_real_init ( gboolean addPredefined )
76 gchar *filename, **keys, **key, *str_value;
81 gnc_exp_parser_shutdown ();
83 variable_bindings = g_hash_table_new (g_str_hash, g_str_equal);
90 filename = gnc_exp_parser_filname();
94 keys = g_key_file_get_keys(key_file, GEP_GROUP_NAME, NULL, NULL);
95 for (key = keys; key && *key; key++)
97 str_value = g_key_file_get_string(key_file, GEP_GROUP_NAME, *key, NULL);
104 g_key_file_free(key_file);
111 remove_binding (gpointer key, gpointer value, gpointer not_used)
120 set_one_key (gpointer key, gpointer value, gpointer data)
127 g_key_file_set_string ((GKeyFile *)data, GEP_GROUP_NAME, name, num_str);
132 gnc_exp_parser_shutdown (
void)
140 filename = gnc_exp_parser_filname();
141 key_file = g_key_file_new();
142 g_hash_table_foreach (variable_bindings, set_one_key, key_file);
143 g_key_file_set_comment(key_file, GEP_GROUP_NAME, NULL,
144 " Variables are in the form 'name=value'",
147 g_key_file_free(key_file);
150 g_hash_table_foreach_remove (variable_bindings, remove_binding, NULL);
151 g_hash_table_destroy (variable_bindings);
152 variable_bindings = NULL;
154 last_error = PARSER_NO_ERROR;
155 last_gncp_error = NO_ERR;
157 parser_inited = FALSE;
161 gnc_exp_parser_remove_variable (
const char *variable_name)
169 if (variable_name == NULL)
172 if (g_hash_table_lookup_extended (variable_bindings, variable_name,
175 g_hash_table_remove (variable_bindings, key);
182 gnc_exp_parser_set_value (
const char * variable_name,
gnc_numeric value)
187 if (variable_name == NULL)
191 gnc_exp_parser_init ();
193 gnc_exp_parser_remove_variable (variable_name);
195 key = g_strdup (variable_name);
200 g_hash_table_insert (variable_bindings, key, pnum);
204 make_predefined_vars_helper (gpointer key, gpointer value, gpointer data)
216 var->variable_name = g_strdup(key);
218 var->next_var = *vars_p;
224 make_predefined_vars_from_external_helper( gpointer key, gpointer value, gpointer data )
230 make_predefined_vars_helper( key, pnum, data );
234 make_predefined_variables (
void)
238 g_hash_table_foreach (variable_bindings, make_predefined_vars_helper, &vars);
250 next = vars->next_var;
252 g_free(vars->variable_name);
253 vars->variable_name = NULL;
267 for ( ; vars ; vars = vars->next_var )
271 gnc_exp_parser_set_value (vars->variable_name, pnum->value);
275 static char* _function_evaluation_error_msg = NULL;
277 _exception_handler(
const char *error_message)
279 _function_evaluation_error_msg = (
char*)error_message;
284 func_op(
const char *fname,
int argc,
void **argv)
286 SCM scmFn, scmArgs, scmTmp;
293 realFnName = g_string_sized_new( strlen(fname) + 5 );
294 g_string_printf( realFnName,
"gnc:%s", fname );
295 scmFn = scm_internal_catch(SCM_BOOL_T,
296 (scm_t_catch_body)scm_c_eval_string, realFnName->str,
297 scm_handle_by_message_noexit, NULL);
298 g_string_free( realFnName, TRUE );
299 if (!scm_is_procedure(scmFn))
302 printf(
"gnc:\"%s\" is not a scm procedure\n", fname );
305 scmArgs = scm_listify( SCM_UNDEFINED );
306 for ( i = 0; i < argc; i++ )
317 str = (
char*)(vs->value);
318 scmTmp = scm_from_utf8_string( str );
322 printf(
"argument %d not a numeric or string [type = %d]\n",
327 scmArgs = scm_cons( scmTmp, scmArgs );
331 scmTmp = gfec_apply(scmFn, scmArgs, _exception_handler);
332 if (_function_evaluation_error_msg != NULL)
334 PERR(
"function eval error: [%s]\n", _function_evaluation_error_msg);
335 _function_evaluation_error_msg = NULL;
345 PERR(
"Attempt to convert %f to GncNumeric Failed: %s",
346 scm_to_double(scmTmp),
352 return (
void*)result;
356 trans_numeric(
const char *digit_str,
364 if (digit_str == NULL)
367 if (!xaccParseAmount (digit_str, TRUE, &value, rstr))
377 numeric_ops(
char op_sym,
385 if ((left == NULL) || (right == NULL))
388 result = (op_sym == ASN_OP) ? left : g_new0(
ParserNum, 1);
409 result->value = right->value;
417 negate_numeric(
void *value)
431 gnc_ep_tmpvarhash_check_vals( gpointer key, gpointer value, gpointer user_data )
433 gboolean *allVarsHaveValues = (gboolean*)user_data;
440 gnc_ep_tmpvarhash_clean( gpointer key, gpointer value, gpointer user_data )
444 g_free( (gchar*)key );
453 gnc_exp_parser_parse(
const char * expression,
gnc_numeric *value_p,
456 GHashTable *tmpVarHash;
457 gboolean ret, toRet = TRUE;
458 gboolean allVarsHaveValues = TRUE;
460 tmpVarHash = g_hash_table_new( g_str_hash, g_str_equal );
461 ret = gnc_exp_parser_parse_separate_vars( expression, value_p,
462 error_loc_p, tmpVarHash );
469 g_hash_table_foreach( tmpVarHash,
470 gnc_ep_tmpvarhash_check_vals,
471 &allVarsHaveValues );
472 if ( !allVarsHaveValues )
475 last_gncp_error = VARIABLE_IN_EXP;
479 g_hash_table_foreach( tmpVarHash, gnc_ep_tmpvarhash_clean, NULL );
480 g_hash_table_destroy( tmpVarHash );
486 gnc_exp_parser_parse_separate_vars (
const char * expression,
489 GHashTable *varHash )
498 if (expression == NULL)
502 gnc_exp_parser_real_init ( (varHash == NULL) );
504 result.variable_name = NULL;
506 result.next_var = NULL;
508 vars = make_predefined_variables ();
510 if ( varHash != NULL )
512 g_hash_table_foreach( varHash, make_predefined_vars_from_external_helper, &vars);
515 lc = gnc_localeconv ();
517 pe = init_parser (vars, lc->mon_decimal_point, lc->mon_thousands_sep,
518 trans_numeric, numeric_ops, negate_numeric, g_free,
521 error_loc = parse_string (&result, expression, pe);
525 if (error_loc == NULL)
529 if (error_loc_p != NULL)
530 *error_loc_p = (
char *) expression;
532 last_error = NUMERIC_ERROR;
541 if (!result.variable_name)
545 if (error_loc_p != NULL)
548 last_error = PARSER_NO_ERROR;
553 if (error_loc_p != NULL)
554 *error_loc_p = error_loc;
556 last_error = get_parse_error (pe);
559 if ( varHash != NULL )
562 gpointer maybeKey, maybeValue;
565 newVars = parser_get_vars( pe );
566 for ( ; newVars ; newVars = newVars->next_var )
568 pnum = newVars->value;
569 if ( g_hash_table_lookup_extended( varHash, newVars->variable_name,
570 &maybeKey, &maybeValue ) )
572 g_hash_table_remove( varHash, maybeKey );
574 g_free( maybeValue );
577 *numericValue = ((
ParserNum*)newVars->value)->value;
580 g_hash_table_insert( varHash,
581 g_strdup(newVars->variable_name),
587 update_variables (vars);
590 free_predefined_variables (vars);
594 return last_error == PARSER_NO_ERROR;
598 gnc_exp_parser_error_string (
void)
600 if ( last_error == PARSER_NO_ERROR )
602 switch ( last_gncp_error )
608 case VARIABLE_IN_EXP:
609 return _(
"Illegal variable in expression." );
617 case PARSER_NO_ERROR:
619 case UNBALANCED_PARENS:
620 return _(
"Unbalanced parenthesis");
622 return _(
"Stack overflow");
623 case STACK_UNDERFLOW:
624 return _(
"Stack underflow");
625 case UNDEFINED_CHARACTER:
626 return _(
"Undefined character");
628 return _(
"Not a variable");
630 return _(
"Not a defined function");
631 case PARSER_OUT_OF_MEMORY:
632 return _(
"Out of memory");
634 return _(
"Numeric error");
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
utility functions for the GnuCash UI
gnc_numeric gnc_numeric_neg(gnc_numeric a)
GKeyFile helper routines.
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gchar * gnc_numeric_to_string(gnc_numeric n)
gchar * gnc_build_dotgnucash_path(const gchar *filename)
Make a path to filename in the user's configuration directory.
#define PERR(format, args...)
gboolean string_to_gnc_numeric(const gchar *str, gnc_numeric *n)
gnc_numeric gnc_numeric_reduce(gnc_numeric n)
gdouble gnc_numeric_to_double(gnc_numeric n)
gboolean gnc_key_file_save_to_file(const gchar *filename, GKeyFile *key_file, GError **error)
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
GKeyFile * gnc_key_file_load_from_file(const gchar *filename, gboolean ignore_error, gboolean return_empty_struct, GError **caller_error)
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
File path resolution utility functions.
#define GNC_HOW_DENOM_SIGFIGS(n)
const gchar * QofLogModule