1997-11-01 01:39:32 +00:00
|
|
|
/********************************************************************\
|
2001-07-01 21:09:09 +00:00
|
|
|
* gnc-ui-util.c -- utility functions for the GnuCash UI *
|
2000-11-01 08:52:30 +00:00
|
|
|
* Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
|
1997-11-01 01:39:32 +00:00
|
|
|
* *
|
|
|
|
|
* 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*
|
2000-04-24 21:12:41 +00:00
|
|
|
* along with this program; if not, contact: *
|
1997-11-01 01:39:32 +00:00
|
|
|
* *
|
2000-04-24 21:12:41 +00:00
|
|
|
* Free Software Foundation Voice: +1-617-542-5942 *
|
2005-11-17 05:35:02 +00:00
|
|
|
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
|
|
|
|
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
1997-11-01 01:39:32 +00:00
|
|
|
\********************************************************************/
|
|
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
2005-11-19 23:53:34 +00:00
|
|
|
#include <glib.h>
|
|
|
|
|
#include <glib/gi18n.h>
|
2006-10-15 19:02:05 +00:00
|
|
|
#include <libguile.h>
|
2000-08-31 07:16:55 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <locale.h>
|
2002-12-16 01:40:26 +00:00
|
|
|
#include <math.h>
|
2007-02-01 01:08:05 +00:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
#include <pow.h>
|
|
|
|
|
#endif
|
2000-10-31 01:27:31 +00:00
|
|
|
#include <stdarg.h>
|
2000-08-31 07:16:55 +00:00
|
|
|
#include <stdlib.h>
|
2000-11-01 08:52:30 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2000-03-22 10:10:50 +00:00
|
|
|
|
2001-11-24 12:10:42 +00:00
|
|
|
#include "Account.h"
|
2001-08-20 23:25:39 +00:00
|
|
|
#include "gnc-book.h"
|
2001-04-12 23:03:42 +00:00
|
|
|
#include "gnc-component-manager.h"
|
2005-11-02 03:32:36 +00:00
|
|
|
#include "qof.h"
|
2001-08-20 23:25:39 +00:00
|
|
|
#include "gnc-engine.h"
|
2001-08-21 00:24:20 +00:00
|
|
|
#include "gnc-euro.h"
|
2005-11-02 03:32:36 +00:00
|
|
|
#include "gnc-gconf-utils.h"
|
2006-03-08 05:14:54 +00:00
|
|
|
#include "gnc-hooks.h"
|
2001-08-19 11:15:56 +00:00
|
|
|
#include "gnc-module.h"
|
2001-08-20 23:25:39 +00:00
|
|
|
#include "gnc-ui-util.h"
|
2001-11-24 12:10:42 +00:00
|
|
|
#include "Transaction.h"
|
2003-02-22 08:15:53 +00:00
|
|
|
#include "guile-mappings.h"
|
2006-02-22 02:39:02 +00:00
|
|
|
#include "gnc-session.h"
|
2000-10-31 01:27:31 +00:00
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
#define KEY_CURRENCY_CHOICE "currency_choice"
|
|
|
|
|
#define KEY_CURRENCY_OTHER "currency_other"
|
2006-03-02 07:20:33 +00:00
|
|
|
#define KEY_REVERSED_ACCOUNTS "reversed_accounts"
|
2005-11-02 03:32:36 +00:00
|
|
|
|
|
|
|
|
static QofLogModule log_module = GNC_MOD_GUI;
|
2000-10-31 01:27:31 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
static gboolean auto_decimal_enabled = FALSE;
|
|
|
|
|
static int auto_decimal_places = 2; /* default, can be changed */
|
2000-10-31 01:27:31 +00:00
|
|
|
|
2001-08-20 10:08:09 +00:00
|
|
|
static gboolean reverse_balance_inited = FALSE;
|
|
|
|
|
static gboolean reverse_type[NUM_ACCOUNT_TYPES];
|
2000-10-31 01:27:31 +00:00
|
|
|
|
2006-03-08 05:14:54 +00:00
|
|
|
/* Cache currency ISO codes and only look them up in gconf when
|
|
|
|
|
* absolutely necessary. Can't cache a pointer to the data structure
|
|
|
|
|
* as that will change any time the book changes. */
|
|
|
|
|
static gchar *user_default_currency = NULL;
|
|
|
|
|
static gchar *user_report_currency = NULL;
|
|
|
|
|
|
2000-11-29 20:40:25 +00:00
|
|
|
/********************************************************************\
|
2006-03-04 03:04:46 +00:00
|
|
|
* gnc_configure_account_separator *
|
|
|
|
|
* updates the current account separator character *
|
2000-11-29 20:40:25 +00:00
|
|
|
* *
|
|
|
|
|
* Args: none *
|
|
|
|
|
\*******************************************************************/
|
2006-03-02 07:20:33 +00:00
|
|
|
static void
|
|
|
|
|
gnc_configure_account_separator (void)
|
2000-11-29 20:40:25 +00:00
|
|
|
{
|
2006-03-04 03:04:46 +00:00
|
|
|
const gchar *separator;
|
2000-11-29 20:40:25 +00:00
|
|
|
char *string;
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
string = gnc_gconf_get_string(GCONF_GENERAL, KEY_ACCOUNT_SEPARATOR, NULL);
|
2000-11-29 20:40:25 +00:00
|
|
|
|
2006-03-04 06:49:23 +00:00
|
|
|
if (!string || !*string || safe_strcmp(string, "colon") == 0)
|
2006-03-04 03:04:46 +00:00
|
|
|
separator = ":";
|
2000-11-29 20:40:25 +00:00
|
|
|
else if (safe_strcmp(string, "slash") == 0)
|
2006-03-04 03:04:46 +00:00
|
|
|
separator = "/";
|
2000-11-29 20:40:25 +00:00
|
|
|
else if (safe_strcmp(string, "backslash") == 0)
|
2006-03-04 03:04:46 +00:00
|
|
|
separator = "\\";
|
2000-11-29 20:40:25 +00:00
|
|
|
else if (safe_strcmp(string, "dash") == 0)
|
2006-03-04 03:04:46 +00:00
|
|
|
separator = "-";
|
2000-11-29 20:40:25 +00:00
|
|
|
else if (safe_strcmp(string, "period") == 0)
|
2006-03-04 03:04:46 +00:00
|
|
|
separator = ".";
|
|
|
|
|
else
|
|
|
|
|
separator = string;
|
|
|
|
|
|
|
|
|
|
gnc_set_account_separator(separator);
|
2000-11-29 20:40:25 +00:00
|
|
|
|
|
|
|
|
if (string != NULL)
|
|
|
|
|
free(string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-08-20 10:08:09 +00:00
|
|
|
static void
|
|
|
|
|
gnc_configure_reverse_balance (void)
|
|
|
|
|
{
|
|
|
|
|
gchar *choice;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
|
|
|
|
|
reverse_type[i] = FALSE;
|
|
|
|
|
|
2006-03-02 07:20:33 +00:00
|
|
|
choice = gnc_gconf_get_string(GCONF_GENERAL, KEY_REVERSED_ACCOUNTS, NULL);
|
2001-08-20 10:08:09 +00:00
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
if (safe_strcmp (choice, "none") == 0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else if (safe_strcmp (choice, "income_expense") == 0)
|
2001-08-20 10:08:09 +00:00
|
|
|
{
|
2006-08-06 22:07:12 +00:00
|
|
|
reverse_type[ACCT_TYPE_INCOME] = TRUE;
|
|
|
|
|
reverse_type[ACCT_TYPE_EXPENSE] = TRUE;
|
2001-08-20 10:08:09 +00:00
|
|
|
}
|
2005-11-02 03:32:36 +00:00
|
|
|
else
|
2001-08-20 10:08:09 +00:00
|
|
|
{
|
2005-11-02 03:32:36 +00:00
|
|
|
if (safe_strcmp (choice, "credit") != 0)
|
2006-09-04 16:27:31 +00:00
|
|
|
PERR("bad value '%s'", choice ? choice : "(null)");
|
2006-08-06 22:07:12 +00:00
|
|
|
reverse_type[ACCT_TYPE_LIABILITY] = TRUE;
|
|
|
|
|
reverse_type[ACCT_TYPE_PAYABLE] = TRUE;
|
|
|
|
|
reverse_type[ACCT_TYPE_EQUITY] = TRUE;
|
|
|
|
|
reverse_type[ACCT_TYPE_INCOME] = TRUE;
|
|
|
|
|
reverse_type[ACCT_TYPE_CREDIT] = TRUE;
|
2001-08-20 10:08:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (choice != NULL)
|
|
|
|
|
free (choice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_reverse_balance_init (void)
|
|
|
|
|
{
|
|
|
|
|
gnc_configure_reverse_balance ();
|
2005-11-02 03:32:36 +00:00
|
|
|
reverse_balance_inited = TRUE;
|
2001-08-20 10:08:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
gnc_reverse_balance_type (GNCAccountType type)
|
|
|
|
|
{
|
|
|
|
|
if ((type < 0) || (type >= NUM_ACCOUNT_TYPES))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!reverse_balance_inited)
|
|
|
|
|
gnc_reverse_balance_init ();
|
|
|
|
|
|
|
|
|
|
return reverse_type[type];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
2006-02-26 20:06:15 +00:00
|
|
|
gnc_reverse_balance (const Account *account)
|
2001-08-20 10:08:09 +00:00
|
|
|
{
|
|
|
|
|
int type;
|
|
|
|
|
|
|
|
|
|
if (account == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
type = xaccAccountGetType (account);
|
|
|
|
|
if ((type < 0) || (type >= NUM_ACCOUNT_TYPES))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!reverse_balance_inited)
|
|
|
|
|
gnc_reverse_balance_init ();
|
|
|
|
|
|
|
|
|
|
return reverse_type[type];
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-13 01:09:27 +00:00
|
|
|
|
2006-11-08 16:40:41 +00:00
|
|
|
gchar *
|
|
|
|
|
gnc_get_default_directory (const gchar *gconf_section)
|
2003-01-13 01:09:27 +00:00
|
|
|
{
|
2006-11-08 16:40:41 +00:00
|
|
|
gchar *dir;
|
|
|
|
|
|
|
|
|
|
dir = gnc_gconf_get_string (gconf_section, KEY_LAST_PATH, NULL);
|
|
|
|
|
if (!dir)
|
|
|
|
|
dir = g_strdup (g_get_home_dir ());
|
|
|
|
|
|
|
|
|
|
return dir;
|
2003-01-13 01:09:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2006-11-08 16:40:41 +00:00
|
|
|
gnc_set_default_directory (const gchar *gconf_section, const gchar *directory)
|
2003-01-13 01:09:27 +00:00
|
|
|
{
|
2006-11-08 16:40:41 +00:00
|
|
|
gnc_gconf_set_string(gconf_section, KEY_LAST_PATH, directory, NULL);
|
2003-01-13 01:09:27 +00:00
|
|
|
}
|
|
|
|
|
|
2003-06-27 02:38:40 +00:00
|
|
|
QofBook *
|
2001-10-02 09:10:35 +00:00
|
|
|
gnc_get_current_book (void)
|
|
|
|
|
{
|
2006-02-22 02:39:02 +00:00
|
|
|
return qof_session_get_book (gnc_get_current_session ());
|
2001-10-02 09:10:35 +00:00
|
|
|
}
|
|
|
|
|
|
2007-02-23 01:23:31 +00:00
|
|
|
Account *
|
|
|
|
|
gnc_get_current_root_account (void)
|
2001-09-18 07:26:42 +00:00
|
|
|
{
|
2007-02-23 01:23:31 +00:00
|
|
|
return gnc_book_get_root_account (gnc_get_current_book ());
|
2001-09-18 07:26:42 +00:00
|
|
|
}
|
2001-08-20 10:08:09 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
gnc_commodity_table *
|
|
|
|
|
gnc_get_current_commodities (void)
|
|
|
|
|
{
|
|
|
|
|
return gnc_book_get_commodity_table (gnc_get_current_book ());
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-13 21:28:45 +00:00
|
|
|
gchar *
|
|
|
|
|
gnc_get_account_name_for_register(const Account *account)
|
|
|
|
|
{
|
|
|
|
|
gboolean show_leaf_accounts;
|
|
|
|
|
show_leaf_accounts = gnc_gconf_get_bool(GCONF_GENERAL_REGISTER,
|
|
|
|
|
KEY_SHOW_LEAF_ACCOUNT_NAMES, NULL);
|
|
|
|
|
|
|
|
|
|
if (show_leaf_accounts)
|
|
|
|
|
return g_strdup (xaccAccountGetName (account));
|
|
|
|
|
else
|
|
|
|
|
return xaccAccountGetFullName (account);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Account *
|
|
|
|
|
gnc_account_lookup_for_register(const Account *base_account, const char *name)
|
|
|
|
|
{
|
|
|
|
|
gboolean show_leaf_accounts;
|
|
|
|
|
show_leaf_accounts = gnc_gconf_get_bool(GCONF_GENERAL_REGISTER,
|
|
|
|
|
KEY_SHOW_LEAF_ACCOUNT_NAMES, NULL);
|
|
|
|
|
|
|
|
|
|
if (show_leaf_accounts)
|
|
|
|
|
return gnc_account_lookup_by_name (base_account, name);
|
|
|
|
|
else
|
|
|
|
|
return gnc_account_lookup_by_full_name (base_account, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
/*
|
|
|
|
|
* This is a wrapper routine around an xaccGetBalanceInCurrency
|
|
|
|
|
* function that handles additional needs of the gui.
|
|
|
|
|
*
|
|
|
|
|
* @param fn The underlying function in Account.c to call to retrieve
|
|
|
|
|
* a specific balance from the account.
|
|
|
|
|
* @param account The account to retrieve data about.
|
|
|
|
|
* @param recurse Include all sub-accounts of this account.
|
|
|
|
|
* @param negative An indication of whether or not the returned value
|
|
|
|
|
* is negative. This can be used by the caller to
|
|
|
|
|
* easily decode whether or not to color the output.
|
|
|
|
|
* @param commodity The commodity in which the account balance should
|
|
|
|
|
* be returned. If NULL, the value will be returned in
|
|
|
|
|
* the commodity of the account. This is normally used
|
|
|
|
|
* to specify a currency, which forces the conversion
|
|
|
|
|
* of things like stock account values from share
|
|
|
|
|
* values to an amount the requested currency.
|
|
|
|
|
*/
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_numeric
|
|
|
|
|
gnc_ui_account_get_balance_full (xaccGetBalanceInCurrencyFn fn,
|
2006-02-26 20:06:15 +00:00
|
|
|
const Account *account,
|
2005-11-02 03:32:36 +00:00
|
|
|
gboolean recurse,
|
|
|
|
|
gboolean *negative,
|
2006-02-27 23:57:16 +00:00
|
|
|
const gnc_commodity *commodity)
|
2001-04-17 09:32:16 +00:00
|
|
|
{
|
|
|
|
|
gnc_numeric balance;
|
|
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
balance = fn(account, commodity, recurse);
|
2001-04-17 09:32:16 +00:00
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
/* reverse sign if needed */
|
|
|
|
|
if (gnc_reverse_balance (account))
|
|
|
|
|
balance = gnc_numeric_neg (balance);
|
2001-04-18 11:11:04 +00:00
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
/* Record whether the balance is negative. */
|
|
|
|
|
if (negative)
|
|
|
|
|
*negative = gnc_numeric_negative_p(balance);
|
2001-04-18 11:11:04 +00:00
|
|
|
|
|
|
|
|
return balance;
|
2001-04-17 09:32:16 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
/*
|
|
|
|
|
* This routine retrives the total balance in an account, possibly
|
|
|
|
|
* including all sub-accounts under the specified account.
|
|
|
|
|
*/
|
2001-09-23 04:29:15 +00:00
|
|
|
gnc_numeric
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_ui_account_get_balance (const Account *account, gboolean recurse)
|
2001-09-23 04:29:15 +00:00
|
|
|
{
|
2005-11-02 03:32:36 +00:00
|
|
|
return gnc_ui_account_get_balance_full (xaccAccountGetBalanceInCurrency,
|
|
|
|
|
account, recurse, NULL, NULL);
|
2001-09-23 04:29:15 +00:00
|
|
|
}
|
|
|
|
|
|
2004-01-15 23:41:53 +00:00
|
|
|
/*
|
|
|
|
|
* This routine retrives the total balance in an account converted to
|
|
|
|
|
* a given currency, possibly including all sub-accounts under the
|
|
|
|
|
* specified account.
|
|
|
|
|
*/
|
|
|
|
|
gnc_numeric
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_ui_account_get_balance_in_currency (const Account *account,
|
|
|
|
|
const gnc_commodity *currency,
|
2004-01-15 23:41:53 +00:00
|
|
|
gboolean recurse)
|
|
|
|
|
{
|
2005-11-02 03:32:36 +00:00
|
|
|
return gnc_ui_account_get_balance_full (xaccAccountGetBalanceInCurrency,
|
|
|
|
|
account, recurse, NULL, currency);
|
2004-01-15 23:41:53 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
/*
|
|
|
|
|
* This routine retrives the reconciled balance in an account,
|
|
|
|
|
* possibly including all sub-accounts under the specified account.
|
|
|
|
|
*/
|
|
|
|
|
gnc_numeric
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_ui_account_get_reconciled_balance (const Account *account,
|
2003-04-01 04:05:32 +00:00
|
|
|
gboolean recurse)
|
2001-09-23 04:29:15 +00:00
|
|
|
{
|
2005-11-02 03:32:36 +00:00
|
|
|
return gnc_ui_account_get_balance_full (xaccAccountGetReconciledBalanceInCurrency,
|
|
|
|
|
account, recurse, NULL, NULL);
|
2001-09-23 04:29:15 +00:00
|
|
|
}
|
|
|
|
|
|
2001-04-18 11:11:04 +00:00
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
/**
|
2005-11-02 03:32:36 +00:00
|
|
|
* Wrapper around gnc_ui_account_get_balance_full that converts
|
2003-04-01 04:05:32 +00:00
|
|
|
* the resulting number to a character string. The number is
|
|
|
|
|
* formatted according to the specification of the account currency.
|
2005-11-02 03:32:36 +00:00
|
|
|
* The caller is responsible for g_free'ing the returned memory.
|
2003-04-01 04:05:32 +00:00
|
|
|
*
|
|
|
|
|
* @param fn The underlying function in Account.c to call to retrieve
|
|
|
|
|
* a specific balance from the account.
|
|
|
|
|
* @param account The account to retrieve data about.
|
|
|
|
|
* @param recurse Include all sub-accounts of this account.
|
|
|
|
|
* @param negative An indication of whether or not the returned value
|
|
|
|
|
* is negative. This can be used by the caller to
|
|
|
|
|
* easily decode whether or not to color the output.
|
|
|
|
|
*/
|
2005-11-02 03:32:36 +00:00
|
|
|
gchar *
|
2003-04-01 04:05:32 +00:00
|
|
|
gnc_ui_account_get_print_balance (xaccGetBalanceInCurrencyFn fn,
|
2006-02-27 23:57:16 +00:00
|
|
|
const Account *account,
|
2003-04-01 04:05:32 +00:00
|
|
|
gboolean recurse,
|
|
|
|
|
gboolean *negative)
|
2001-04-18 11:11:04 +00:00
|
|
|
{
|
2003-04-01 04:05:32 +00:00
|
|
|
GNCPrintAmountInfo print_info;
|
2001-04-18 11:11:04 +00:00
|
|
|
gnc_numeric balance;
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
balance = gnc_ui_account_get_balance_full(fn, account, recurse,
|
|
|
|
|
negative, NULL);
|
2003-04-01 04:05:32 +00:00
|
|
|
print_info = gnc_account_print_info(account, TRUE);
|
|
|
|
|
return g_strdup(xaccPrintAmount(balance, print_info));
|
2001-04-18 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
|
|
|
|
|
/**
|
2005-11-02 03:32:36 +00:00
|
|
|
* Wrapper around gnc_ui_account_get_balance_full that converts
|
2003-04-01 04:05:32 +00:00
|
|
|
* the resulting number to a character string. The number is
|
|
|
|
|
* formatted according to the specification of the default reporting
|
|
|
|
|
* currency.
|
|
|
|
|
*
|
|
|
|
|
* @param fn The underlying function in Account.c to call to retrieve
|
|
|
|
|
* a specific balance from the account.
|
|
|
|
|
* @param account The account to retrieve data about.
|
|
|
|
|
* @param recurse Include all sub-accounts of this account.
|
|
|
|
|
* @param negative An indication of whether or not the returned value
|
|
|
|
|
* is negative. This can be used by the caller to
|
|
|
|
|
* easily decode whether or not to color the output.
|
|
|
|
|
*/
|
2005-11-02 03:32:36 +00:00
|
|
|
gchar *
|
2003-04-01 04:05:32 +00:00
|
|
|
gnc_ui_account_get_print_report_balance (xaccGetBalanceInCurrencyFn fn,
|
2006-02-27 23:57:16 +00:00
|
|
|
const Account *account,
|
2003-04-01 04:05:32 +00:00
|
|
|
gboolean recurse,
|
|
|
|
|
gboolean *negative)
|
2001-09-23 04:29:15 +00:00
|
|
|
{
|
2003-04-01 04:05:32 +00:00
|
|
|
GNCPrintAmountInfo print_info;
|
2001-09-23 04:29:15 +00:00
|
|
|
gnc_numeric balance;
|
2003-04-01 04:05:32 +00:00
|
|
|
gnc_commodity *report_commodity;
|
2001-09-23 04:29:15 +00:00
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
report_commodity = gnc_default_report_currency();
|
2005-11-02 03:32:36 +00:00
|
|
|
balance = gnc_ui_account_get_balance_full(fn, account, recurse,
|
|
|
|
|
negative, report_commodity);
|
2003-04-01 04:05:32 +00:00
|
|
|
print_info = gnc_commodity_print_info(report_commodity, TRUE);
|
|
|
|
|
return g_strdup(xaccPrintAmount(balance, print_info));
|
2001-09-23 04:29:15 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
|
2000-11-29 20:40:25 +00:00
|
|
|
gnc_numeric
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_ui_account_get_balance_as_of_date (Account *account,
|
|
|
|
|
time_t date,
|
2003-04-01 04:05:32 +00:00
|
|
|
gboolean include_children)
|
2000-11-29 20:40:25 +00:00
|
|
|
{
|
|
|
|
|
gnc_numeric balance;
|
2003-04-01 04:05:32 +00:00
|
|
|
gnc_commodity *currency;
|
2000-11-29 20:40:25 +00:00
|
|
|
|
|
|
|
|
if (account == NULL)
|
|
|
|
|
return gnc_numeric_zero ();
|
|
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
currency = xaccAccountGetCommodity (account);
|
|
|
|
|
balance = xaccAccountGetBalanceAsOfDate (account, date);
|
2000-11-29 20:40:25 +00:00
|
|
|
|
|
|
|
|
if (include_children)
|
|
|
|
|
{
|
2003-04-01 04:05:32 +00:00
|
|
|
GList *children, *node;
|
2000-11-29 20:40:25 +00:00
|
|
|
|
2007-02-23 01:23:31 +00:00
|
|
|
children = gnc_account_get_descendants(account);
|
2001-04-18 11:11:04 +00:00
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
for (node = children; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
Account *child;
|
|
|
|
|
gnc_commodity *child_currency;
|
|
|
|
|
gnc_numeric child_balance;
|
2001-04-18 11:11:04 +00:00
|
|
|
|
2003-04-01 04:05:32 +00:00
|
|
|
child = node->data;
|
|
|
|
|
child_currency = xaccAccountGetCommodity (child);
|
|
|
|
|
child_balance = xaccAccountGetBalanceAsOfDate (child, date);
|
|
|
|
|
child_balance = xaccAccountConvertBalanceToCurrency (child,
|
|
|
|
|
child_balance, child_currency, currency);
|
|
|
|
|
balance = gnc_numeric_add_fixed (balance, child_balance);
|
|
|
|
|
}
|
2007-02-23 01:23:31 +00:00
|
|
|
|
|
|
|
|
g_list_free(children);
|
2000-11-29 20:40:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* reverse sign if needed */
|
|
|
|
|
if (gnc_reverse_balance (account))
|
|
|
|
|
balance = gnc_numeric_neg (balance);
|
|
|
|
|
|
|
|
|
|
return balance;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/* Caller is responsible for g_free'ing returned memory */
|
|
|
|
|
char *
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_ui_account_get_tax_info_string (const Account *account)
|
2001-08-19 11:15:56 +00:00
|
|
|
{
|
|
|
|
|
static SCM get_form = SCM_UNDEFINED;
|
|
|
|
|
static SCM get_desc = SCM_UNDEFINED;
|
|
|
|
|
|
|
|
|
|
GNCAccountType atype;
|
|
|
|
|
const char *code;
|
|
|
|
|
SCM category;
|
|
|
|
|
SCM code_scm;
|
2005-11-02 03:32:36 +00:00
|
|
|
const gchar *form, *desc;
|
2001-08-19 11:15:56 +00:00
|
|
|
SCM scm;
|
|
|
|
|
|
|
|
|
|
if (get_form == SCM_UNDEFINED)
|
|
|
|
|
{
|
|
|
|
|
GNCModule module;
|
2007-04-22 00:48:03 +00:00
|
|
|
const gchar *tax_module;
|
2005-01-16 16:41:39 +00:00
|
|
|
/* load the tax info */
|
2005-01-29 12:54:31 +00:00
|
|
|
#ifdef LOCALE_SPECIFIC_TAX
|
2005-01-16 16:41:39 +00:00
|
|
|
/* This is a very simple hack that loads the (new, special) German
|
|
|
|
|
tax definition file in a German locale, or (default) loads the
|
|
|
|
|
previous US tax file. */
|
2007-04-22 00:48:03 +00:00
|
|
|
# ifdef G_OS_WIN32
|
|
|
|
|
gchar *thislocale = g_win32_getlocale();
|
2007-04-22 09:03:34 +00:00
|
|
|
gboolean is_de_DE = (strncmp(thislocale, "de_DE", 5) == 0);
|
2007-04-22 00:48:03 +00:00
|
|
|
g_free(thislocale);
|
|
|
|
|
# else /* !G_OS_WIN32 */
|
|
|
|
|
const char *thislocale = setlocale(LC_ALL, NULL);
|
2005-01-16 16:41:39 +00:00
|
|
|
gboolean is_de_DE = (strncmp(thislocale, "de_DE", 5) == 0);
|
2007-04-22 00:48:03 +00:00
|
|
|
# endif /* G_OS_WIN32 */
|
|
|
|
|
#else /* LOCALE_SPECIFIC_TAX */
|
2005-01-29 12:54:31 +00:00
|
|
|
gboolean is_de_DE = FALSE;
|
|
|
|
|
#endif /* LOCALE_SPECIFIC_TAX */
|
2007-04-22 00:48:03 +00:00
|
|
|
tax_module = is_de_DE ?
|
2005-01-16 16:41:39 +00:00
|
|
|
"gnucash/tax/de_DE" :
|
|
|
|
|
"gnucash/tax/us";
|
|
|
|
|
|
|
|
|
|
module = gnc_module_load ((char *)tax_module, 0);
|
2001-08-19 11:15:56 +00:00
|
|
|
|
|
|
|
|
g_return_val_if_fail (module, NULL);
|
|
|
|
|
|
2003-02-22 08:15:53 +00:00
|
|
|
get_form = scm_c_eval_string ("(false-if-exception gnc:txf-get-form)");
|
|
|
|
|
get_desc = scm_c_eval_string ("(false-if-exception gnc:txf-get-description)");
|
2001-08-19 11:15:56 +00:00
|
|
|
}
|
|
|
|
|
|
2003-02-22 08:15:53 +00:00
|
|
|
g_return_val_if_fail (SCM_PROCEDUREP (get_form), NULL);
|
|
|
|
|
g_return_val_if_fail (SCM_PROCEDUREP (get_desc), NULL);
|
2001-08-19 11:15:56 +00:00
|
|
|
|
|
|
|
|
if (!account)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (!xaccAccountGetTaxRelated (account))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
atype = xaccAccountGetType (account);
|
2006-08-06 22:07:12 +00:00
|
|
|
if (atype != ACCT_TYPE_INCOME && atype != ACCT_TYPE_EXPENSE)
|
2001-08-19 11:15:56 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
code = xaccAccountGetTaxUSCode (account);
|
|
|
|
|
if (!code)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2006-08-06 22:07:12 +00:00
|
|
|
category = scm_c_eval_string (atype == ACCT_TYPE_INCOME ?
|
2003-02-22 08:15:53 +00:00
|
|
|
"txf-income-categories" :
|
|
|
|
|
"txf-expense-categories");
|
2001-08-19 11:15:56 +00:00
|
|
|
|
2003-02-22 08:15:53 +00:00
|
|
|
code_scm = scm_str2symbol (code);
|
2001-08-19 11:15:56 +00:00
|
|
|
|
2003-02-22 08:15:53 +00:00
|
|
|
scm = scm_call_2 (get_form, category, code_scm);
|
|
|
|
|
if (!SCM_STRINGP (scm))
|
2001-08-19 11:15:56 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
form = SCM_STRING_CHARS (scm);
|
2001-08-19 11:15:56 +00:00
|
|
|
if (!form)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2003-02-22 08:15:53 +00:00
|
|
|
scm = scm_call_2 (get_desc, category, code_scm);
|
|
|
|
|
if (!SCM_STRINGP (scm))
|
2001-08-19 11:15:56 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
desc = SCM_STRING_CHARS (scm);
|
2001-08-19 11:15:56 +00:00
|
|
|
if (!desc)
|
2000-11-29 20:40:25 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
return g_strdup_printf ("%s %s", form, desc);
|
2000-11-29 20:40:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-04-30 10:32:34 +00:00
|
|
|
static const char *
|
|
|
|
|
string_after_colon (const char *msgstr)
|
|
|
|
|
{
|
|
|
|
|
const char *string_at_colon;
|
|
|
|
|
g_assert(msgstr);
|
|
|
|
|
string_at_colon = strchr(msgstr, ':');
|
|
|
|
|
if (string_at_colon)
|
|
|
|
|
return string_at_colon + 1;
|
|
|
|
|
else
|
|
|
|
|
/* No colon found; we assume the translation contains only the
|
|
|
|
|
part after the colon, similar to the disambiguation prefixes */
|
|
|
|
|
return msgstr;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-29 20:40:25 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
* gnc_get_reconcile_str *
|
|
|
|
|
* return the i18n'd string for the given reconciled flag *
|
|
|
|
|
* *
|
|
|
|
|
* Args: reconciled_flag - the flag to stringize *
|
|
|
|
|
* Returns: the i18n'd reconciled string *
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
const char *
|
|
|
|
|
gnc_get_reconcile_str (char reconciled_flag)
|
|
|
|
|
{
|
|
|
|
|
switch (reconciled_flag)
|
|
|
|
|
{
|
2002-10-29 18:24:21 +00:00
|
|
|
/* Translators: For the following strings, the single letters
|
|
|
|
|
after the colon are abbreviations of the word before the
|
2006-04-30 10:32:34 +00:00
|
|
|
colon. You should only translate the letter *after* the colon. */
|
|
|
|
|
case NREC: return string_after_colon(_("not cleared:n"));
|
|
|
|
|
/* Translators: Please only translate the letter *after* the colon. */
|
|
|
|
|
case CREC: return string_after_colon(_("cleared:c"));
|
|
|
|
|
/* Translators: Please only translate the letter *after* the colon. */
|
|
|
|
|
case YREC: return string_after_colon(_("reconciled:y"));
|
|
|
|
|
/* Translators: Please only translate the letter *after* the colon. */
|
|
|
|
|
case FREC: return string_after_colon(_("frozen:f"));
|
|
|
|
|
/* Translators: Please only translate the letter *after* the colon. */
|
|
|
|
|
case VREC: return string_after_colon(_("void:v"));
|
2000-11-29 20:40:25 +00:00
|
|
|
default:
|
|
|
|
|
PERR("Bad reconciled flag\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-29 03:00:06 +00:00
|
|
|
/********************************************************************\
|
2001-11-30 02:11:24 +00:00
|
|
|
* gnc_get_reconcile_valid_flags *
|
|
|
|
|
* return a string containing the list of reconciled flags *
|
2001-11-29 03:00:06 +00:00
|
|
|
* *
|
|
|
|
|
* Returns: the i18n'd reconciled flags string *
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
const char *
|
2001-11-30 02:11:24 +00:00
|
|
|
gnc_get_reconcile_valid_flags (void)
|
2001-11-29 03:00:06 +00:00
|
|
|
{
|
2001-11-30 04:25:17 +00:00
|
|
|
static const char flags[] = { NREC, CREC, YREC, FREC, VREC, 0 };
|
2001-11-30 02:11:24 +00:00
|
|
|
return flags;
|
2001-11-29 03:00:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************************************************************\
|
2001-11-30 02:11:24 +00:00
|
|
|
* gnc_get_reconcile_flag_order *
|
|
|
|
|
* return a string containing the reconciled-flag change order *
|
2001-11-29 03:00:06 +00:00
|
|
|
* *
|
|
|
|
|
* Args: reconciled_flag - the flag to stringize *
|
|
|
|
|
* Returns: the i18n'd reconciled string *
|
|
|
|
|
\********************************************************************/
|
|
|
|
|
const char *
|
2001-11-30 02:11:24 +00:00
|
|
|
gnc_get_reconcile_flag_order (void)
|
2001-11-29 03:00:06 +00:00
|
|
|
{
|
2001-11-30 02:11:24 +00:00
|
|
|
static const char flags[] = { NREC, CREC, 0 };
|
|
|
|
|
return flags;
|
2001-11-29 03:00:06 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-29 20:40:25 +00:00
|
|
|
|
2001-04-03 10:18:59 +00:00
|
|
|
static const char *
|
|
|
|
|
equity_base_name (GNCEquityType equity_type)
|
|
|
|
|
{
|
|
|
|
|
switch (equity_type)
|
|
|
|
|
{
|
|
|
|
|
case EQUITY_OPENING_BALANCE:
|
2001-06-09 06:50:25 +00:00
|
|
|
return N_("Opening Balances");
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
case EQUITY_RETAINED_EARNINGS:
|
2001-06-09 06:50:25 +00:00
|
|
|
return N_("Retained Earnings");
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Account *
|
2007-03-03 16:41:42 +00:00
|
|
|
gnc_find_or_create_equity_account (Account *root,
|
2001-06-09 07:35:24 +00:00
|
|
|
GNCEquityType equity_type,
|
2007-02-23 01:23:31 +00:00
|
|
|
gnc_commodity *currency)
|
2001-04-03 10:18:59 +00:00
|
|
|
{
|
|
|
|
|
Account *parent;
|
|
|
|
|
Account *account;
|
|
|
|
|
gboolean name_exists;
|
|
|
|
|
gboolean base_name_exists;
|
|
|
|
|
const char *base_name;
|
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (equity_type >= 0, NULL);
|
|
|
|
|
g_return_val_if_fail (equity_type < NUM_EQUITY_TYPES, NULL);
|
|
|
|
|
g_return_val_if_fail (currency != NULL, NULL);
|
2007-03-03 16:41:42 +00:00
|
|
|
g_return_val_if_fail (root != NULL, NULL);
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
base_name = equity_base_name (equity_type);
|
|
|
|
|
|
2007-02-23 01:23:31 +00:00
|
|
|
account = gnc_account_lookup_by_name(root, base_name);
|
2006-08-06 22:07:12 +00:00
|
|
|
if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
|
2001-04-03 10:18:59 +00:00
|
|
|
account = NULL;
|
|
|
|
|
|
2001-06-09 06:50:25 +00:00
|
|
|
if (!account)
|
|
|
|
|
{
|
2006-02-11 11:14:43 +00:00
|
|
|
base_name = base_name && *base_name ? _(base_name) : "";
|
2001-06-09 06:50:25 +00:00
|
|
|
|
2007-02-23 01:23:31 +00:00
|
|
|
account = gnc_account_lookup_by_name(root, base_name);
|
2006-08-06 22:07:12 +00:00
|
|
|
if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
|
2001-06-09 06:50:25 +00:00
|
|
|
account = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-03 10:18:59 +00:00
|
|
|
base_name_exists = (account != NULL);
|
|
|
|
|
|
|
|
|
|
if (account &&
|
2001-07-12 00:13:21 +00:00
|
|
|
gnc_commodity_equiv (currency, xaccAccountGetCommodity (account)))
|
2001-04-03 10:18:59 +00:00
|
|
|
return account;
|
|
|
|
|
|
|
|
|
|
name = g_strconcat (base_name, " - ",
|
|
|
|
|
gnc_commodity_get_mnemonic (currency), NULL);
|
2007-02-23 01:23:31 +00:00
|
|
|
account = gnc_account_lookup_by_name(root, name);
|
2006-08-06 22:07:12 +00:00
|
|
|
if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
|
2001-04-03 10:18:59 +00:00
|
|
|
account = NULL;
|
|
|
|
|
|
|
|
|
|
name_exists = (account != NULL);
|
|
|
|
|
|
|
|
|
|
if (account &&
|
2001-07-12 00:13:21 +00:00
|
|
|
gnc_commodity_equiv (currency, xaccAccountGetCommodity (account)))
|
2001-04-03 10:18:59 +00:00
|
|
|
return account;
|
|
|
|
|
|
|
|
|
|
/* Couldn't find one, so create it */
|
|
|
|
|
if (name_exists && base_name_exists)
|
|
|
|
|
{
|
|
|
|
|
PWARN ("equity account with unexpected currency");
|
|
|
|
|
g_free (name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!base_name_exists &&
|
2001-06-02 21:15:40 +00:00
|
|
|
gnc_commodity_equiv (currency, gnc_default_currency ()))
|
2001-04-03 10:18:59 +00:00
|
|
|
{
|
|
|
|
|
g_free (name);
|
|
|
|
|
name = g_strdup (base_name);
|
|
|
|
|
}
|
|
|
|
|
|
2007-02-23 01:23:31 +00:00
|
|
|
parent = gnc_account_lookup_by_name(root, _("Equity"));
|
2007-05-11 17:35:00 +00:00
|
|
|
if (!parent || xaccAccountGetType (parent) != ACCT_TYPE_EQUITY)
|
2007-02-23 01:23:31 +00:00
|
|
|
parent = root;
|
|
|
|
|
g_assert(parent);
|
2001-04-03 10:18:59 +00:00
|
|
|
|
2007-03-03 16:41:42 +00:00
|
|
|
account = xaccMallocAccount (gnc_account_get_book(root));
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
xaccAccountBeginEdit (account);
|
|
|
|
|
|
|
|
|
|
xaccAccountSetName (account, name);
|
2006-08-06 22:07:12 +00:00
|
|
|
xaccAccountSetType (account, ACCT_TYPE_EQUITY);
|
2001-07-12 00:13:21 +00:00
|
|
|
xaccAccountSetCommodity (account, currency);
|
2001-04-03 10:18:59 +00:00
|
|
|
|
2007-02-23 01:23:31 +00:00
|
|
|
xaccAccountBeginEdit (parent);
|
|
|
|
|
gnc_account_append_child (parent, account);
|
|
|
|
|
xaccAccountCommitEdit (parent);
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
xaccAccountCommitEdit (account);
|
|
|
|
|
|
|
|
|
|
g_free (name);
|
|
|
|
|
|
|
|
|
|
return account;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
gnc_account_create_opening_balance (Account *account,
|
|
|
|
|
gnc_numeric balance,
|
2001-10-04 00:36:28 +00:00
|
|
|
time_t date,
|
2003-06-27 02:38:40 +00:00
|
|
|
QofBook *book)
|
2001-04-03 10:18:59 +00:00
|
|
|
{
|
|
|
|
|
Account *equity_account;
|
|
|
|
|
Transaction *trans;
|
|
|
|
|
Split *split;
|
|
|
|
|
|
|
|
|
|
if (gnc_numeric_zero_p (balance))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (account != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
equity_account =
|
2007-03-03 16:41:42 +00:00
|
|
|
gnc_find_or_create_equity_account (gnc_account_get_root(account),
|
2001-06-09 07:35:24 +00:00
|
|
|
EQUITY_OPENING_BALANCE,
|
2007-02-23 01:23:31 +00:00
|
|
|
xaccAccountGetCommodity (account));
|
2001-04-03 10:18:59 +00:00
|
|
|
if (!equity_account)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
xaccAccountBeginEdit (account);
|
|
|
|
|
xaccAccountBeginEdit (equity_account);
|
|
|
|
|
|
2001-11-24 12:10:42 +00:00
|
|
|
trans = xaccMallocTransaction (book);
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
xaccTransBeginEdit (trans);
|
|
|
|
|
|
2001-07-12 00:13:21 +00:00
|
|
|
xaccTransSetCurrency (trans, xaccAccountGetCommodity (account));
|
2001-04-03 10:18:59 +00:00
|
|
|
xaccTransSetDateSecs (trans, date);
|
|
|
|
|
xaccTransSetDescription (trans, _("Opening Balance"));
|
|
|
|
|
|
2001-11-24 12:10:42 +00:00
|
|
|
split = xaccMallocSplit (book);
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
xaccTransAppendSplit (trans, split);
|
|
|
|
|
xaccAccountInsertSplit (account, split);
|
|
|
|
|
|
2001-07-12 00:13:21 +00:00
|
|
|
xaccSplitSetAmount (split, balance);
|
2001-04-03 10:18:59 +00:00
|
|
|
xaccSplitSetValue (split, balance);
|
|
|
|
|
|
|
|
|
|
balance = gnc_numeric_neg (balance);
|
|
|
|
|
|
2001-11-24 12:10:42 +00:00
|
|
|
split = xaccMallocSplit (book);
|
2001-04-03 10:18:59 +00:00
|
|
|
|
|
|
|
|
xaccTransAppendSplit (trans, split);
|
|
|
|
|
xaccAccountInsertSplit (equity_account, split);
|
|
|
|
|
|
2001-07-12 00:13:21 +00:00
|
|
|
xaccSplitSetAmount (split, balance);
|
2001-04-03 10:18:59 +00:00
|
|
|
xaccSplitSetValue (split, balance);
|
|
|
|
|
|
|
|
|
|
xaccTransCommitEdit (trans);
|
|
|
|
|
xaccAccountCommitEdit (equity_account);
|
|
|
|
|
xaccAccountCommitEdit (account);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2000-11-29 20:40:25 +00:00
|
|
|
|
2001-09-11 07:41:26 +00:00
|
|
|
char *
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_account_get_full_name (const Account *account)
|
2001-09-11 07:41:26 +00:00
|
|
|
{
|
|
|
|
|
if (!account) return NULL;
|
|
|
|
|
|
2006-03-02 07:20:33 +00:00
|
|
|
return xaccAccountGetFullName (account);
|
2001-09-11 07:41:26 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
static void
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_lconv_set_utf8 (char **p_value, char *default_value)
|
2000-10-31 01:27:31 +00:00
|
|
|
{
|
2000-11-01 08:52:30 +00:00
|
|
|
char *value = *p_value;
|
2007-02-06 03:37:17 +00:00
|
|
|
*p_value = NULL;
|
2000-10-31 01:27:31 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if ((value == NULL) || (value[0] == 0))
|
2007-02-06 03:37:17 +00:00
|
|
|
value = default_value;
|
2001-03-30 12:43:11 +00:00
|
|
|
|
2007-02-06 03:37:17 +00:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
{
|
|
|
|
|
/* get number of resulting wide characters */
|
|
|
|
|
size_t count = mbstowcs (NULL, value, 0);
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
/* malloc and convert */
|
|
|
|
|
wchar_t *wvalue = g_malloc ((count+1) * sizeof(wchar_t));
|
|
|
|
|
count = mbstowcs (wvalue, value, count+1);
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
*p_value = g_utf16_to_utf8 (wvalue, -1, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
g_free (wvalue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else /* !G_OS_WIN32 */
|
|
|
|
|
*p_value = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
|
2006-12-11 22:28:36 +00:00
|
|
|
if (*p_value == NULL) {
|
|
|
|
|
// The g_locale_to_utf8 conversion failed. FIXME: Should we rather
|
|
|
|
|
// use an empty string instead of the default_value? Not sure.
|
|
|
|
|
*p_value = default_value;
|
|
|
|
|
}
|
2000-10-31 01:27:31 +00:00
|
|
|
}
|
2000-06-05 05:51:39 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
static void
|
2000-11-29 20:40:25 +00:00
|
|
|
gnc_lconv_set_char (char *p_value, char default_value)
|
2000-06-30 06:12:37 +00:00
|
|
|
{
|
2000-11-01 08:52:30 +00:00
|
|
|
if ((p_value != NULL) && (*p_value == CHAR_MAX))
|
|
|
|
|
*p_value = default_value;
|
2000-08-27 08:25:53 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
struct lconv *
|
2000-11-29 20:40:25 +00:00
|
|
|
gnc_localeconv (void)
|
2000-08-27 08:25:53 +00:00
|
|
|
{
|
2000-11-01 08:52:30 +00:00
|
|
|
static struct lconv lc;
|
|
|
|
|
static gboolean lc_set = FALSE;
|
2000-06-30 06:12:37 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (lc_set)
|
|
|
|
|
return &lc;
|
2000-06-30 06:12:37 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
lc = *localeconv();
|
2000-05-14 20:54:20 +00:00
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_lconv_set_utf8(&lc.decimal_point, ".");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.thousands_sep, ",");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.grouping, "\003");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.int_curr_symbol, "USD ");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.currency_symbol, "$");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.mon_decimal_point, ".");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.mon_thousands_sep, ",");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.mon_grouping, "\003");
|
|
|
|
|
gnc_lconv_set_utf8(&lc.negative_sign, "-");
|
2006-12-20 15:27:39 +00:00
|
|
|
gnc_lconv_set_utf8(&lc.positive_sign, "");
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
gnc_lconv_set_char(&lc.frac_digits, 2);
|
|
|
|
|
gnc_lconv_set_char(&lc.int_frac_digits, 2);
|
|
|
|
|
gnc_lconv_set_char(&lc.p_cs_precedes, 1);
|
|
|
|
|
gnc_lconv_set_char(&lc.p_sep_by_space, 0);
|
|
|
|
|
gnc_lconv_set_char(&lc.n_cs_precedes, 1);
|
|
|
|
|
gnc_lconv_set_char(&lc.n_sep_by_space, 0);
|
|
|
|
|
gnc_lconv_set_char(&lc.p_sign_posn, 1);
|
|
|
|
|
gnc_lconv_set_char(&lc.n_sign_posn, 1);
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
lc_set = TRUE;
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
return &lc;
|
2000-05-25 18:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
const char *
|
|
|
|
|
gnc_locale_default_iso_currency_code (void)
|
2000-05-25 18:30:24 +00:00
|
|
|
{
|
2001-10-03 10:07:45 +00:00
|
|
|
static char *code = NULL;
|
|
|
|
|
struct lconv *lc;
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
if (code)
|
|
|
|
|
return code;
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
lc = gnc_localeconv ();
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
code = g_strdup (lc->int_curr_symbol);
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
/* The int_curr_symbol includes a space at the end! Note: you
|
|
|
|
|
* can't just change "USD " to "USD" in gnc_localeconv, because
|
|
|
|
|
* that is only used if int_curr_symbol was not defined in the
|
|
|
|
|
* current locale. If it was, it will have the space! */
|
|
|
|
|
g_strstrip (code);
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
return code;
|
|
|
|
|
}
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
gnc_commodity *
|
2002-11-30 13:38:34 +00:00
|
|
|
gnc_locale_default_currency_nodefault (void)
|
2001-10-03 10:07:45 +00:00
|
|
|
{
|
|
|
|
|
gnc_commodity * currency;
|
|
|
|
|
gnc_commodity_table *table;
|
|
|
|
|
const char *code;
|
2001-04-30 06:56:00 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
table = gnc_get_current_commodities ();
|
|
|
|
|
code = gnc_locale_default_iso_currency_code ();
|
|
|
|
|
|
2006-04-14 02:36:00 +00:00
|
|
|
currency = gnc_commodity_table_lookup (table, GNC_COMMODITY_NS_CURRENCY, code);
|
2001-10-03 10:07:45 +00:00
|
|
|
|
2007-06-19 19:40:49 +00:00
|
|
|
/* Some very old locales (notably on win32) still announce a euro
|
|
|
|
|
currency as default, although it has been replaced by EUR in
|
|
|
|
|
2001. We use EUR as default in that case, but the user can always
|
|
|
|
|
override from gconf. */
|
|
|
|
|
if (gnc_is_euro_currency (currency))
|
|
|
|
|
currency = gnc_get_euro();
|
|
|
|
|
|
2002-11-30 13:38:34 +00:00
|
|
|
return (currency ? currency : NULL);
|
|
|
|
|
}
|
2000-05-25 18:30:24 +00:00
|
|
|
|
2002-11-30 13:38:34 +00:00
|
|
|
gnc_commodity *
|
|
|
|
|
gnc_locale_default_currency (void)
|
|
|
|
|
{
|
|
|
|
|
gnc_commodity * currency = gnc_locale_default_currency_nodefault ();
|
|
|
|
|
|
|
|
|
|
return (currency ? currency :
|
|
|
|
|
gnc_commodity_table_lookup (gnc_get_current_commodities (),
|
2006-04-14 02:36:00 +00:00
|
|
|
GNC_COMMODITY_NS_CURRENCY, "USD"));
|
2000-05-25 18:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_commodity *
|
|
|
|
|
gnc_default_currency (void)
|
|
|
|
|
{
|
2006-03-08 05:14:54 +00:00
|
|
|
gnc_commodity *currency = NULL;
|
2005-11-02 03:32:36 +00:00
|
|
|
gchar *choice, *mnemonic;
|
|
|
|
|
|
2006-03-08 05:14:54 +00:00
|
|
|
if (user_default_currency)
|
|
|
|
|
return gnc_commodity_table_lookup(gnc_get_current_commodities(),
|
2006-04-14 02:36:00 +00:00
|
|
|
GNC_COMMODITY_NS_CURRENCY,
|
2006-03-08 05:14:54 +00:00
|
|
|
user_default_currency);
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
choice = gnc_gconf_get_string(GCONF_GENERAL, KEY_CURRENCY_CHOICE, NULL);
|
|
|
|
|
if (choice && strcmp(choice, "other") == 0) {
|
|
|
|
|
mnemonic = gnc_gconf_get_string(GCONF_GENERAL, KEY_CURRENCY_OTHER, NULL);
|
|
|
|
|
currency = gnc_commodity_table_lookup(gnc_get_current_commodities(),
|
2006-04-14 02:36:00 +00:00
|
|
|
GNC_COMMODITY_NS_CURRENCY, mnemonic);
|
2007-06-14 20:01:49 +00:00
|
|
|
DEBUG("mnemonic %s, result %p", mnemonic ? mnemonic : "(null)", currency);
|
2005-11-02 03:32:36 +00:00
|
|
|
g_free(mnemonic);
|
|
|
|
|
}
|
2007-05-12 19:36:39 +00:00
|
|
|
g_free(choice);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2006-03-08 05:14:54 +00:00
|
|
|
if (!currency)
|
|
|
|
|
currency = gnc_locale_default_currency ();
|
|
|
|
|
if (currency) {
|
|
|
|
|
mnemonic = user_default_currency;
|
|
|
|
|
user_default_currency = g_strdup(gnc_commodity_get_mnemonic(currency));
|
|
|
|
|
g_free(mnemonic);
|
|
|
|
|
}
|
|
|
|
|
return currency;
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gnc_commodity *
|
|
|
|
|
gnc_default_report_currency (void)
|
|
|
|
|
{
|
2006-03-08 05:14:54 +00:00
|
|
|
gnc_commodity *currency = NULL;
|
2005-11-02 03:32:36 +00:00
|
|
|
gchar *choice, *mnemonic;
|
|
|
|
|
|
2006-03-08 05:14:54 +00:00
|
|
|
if (user_report_currency)
|
|
|
|
|
return gnc_commodity_table_lookup(gnc_get_current_commodities(),
|
2006-04-14 02:36:00 +00:00
|
|
|
GNC_COMMODITY_NS_CURRENCY,
|
2006-03-08 05:14:54 +00:00
|
|
|
user_report_currency);
|
2005-11-02 03:32:36 +00:00
|
|
|
choice = gnc_gconf_get_string(GCONF_GENERAL_REPORT,
|
|
|
|
|
KEY_CURRENCY_CHOICE, NULL);
|
|
|
|
|
if (choice && strcmp(choice, "other") == 0) {
|
|
|
|
|
mnemonic = gnc_gconf_get_string(GCONF_GENERAL_REPORT,
|
|
|
|
|
KEY_CURRENCY_OTHER, NULL);
|
|
|
|
|
currency = gnc_commodity_table_lookup(gnc_get_current_commodities(),
|
2006-04-14 02:36:00 +00:00
|
|
|
GNC_COMMODITY_NS_CURRENCY, mnemonic);
|
2007-04-27 14:44:26 +00:00
|
|
|
DEBUG("mnemonic %s, result %p", mnemonic ? mnemonic : "(null)", currency);
|
2006-03-08 05:14:54 +00:00
|
|
|
g_free(mnemonic);
|
|
|
|
|
}
|
2007-05-12 19:36:39 +00:00
|
|
|
g_free(choice);
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2006-03-08 05:14:54 +00:00
|
|
|
if (!currency)
|
|
|
|
|
currency = gnc_locale_default_currency ();
|
|
|
|
|
if (currency) {
|
|
|
|
|
mnemonic = user_report_currency;
|
|
|
|
|
user_report_currency = g_strdup(gnc_commodity_get_mnemonic(currency));
|
|
|
|
|
g_free(mnemonic);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
2006-03-08 05:14:54 +00:00
|
|
|
return currency;
|
|
|
|
|
}
|
2005-11-02 03:32:36 +00:00
|
|
|
|
2006-03-08 05:14:54 +00:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnc_currency_changed_cb (GConfEntry *entry, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
user_default_currency = NULL;
|
|
|
|
|
user_report_currency = NULL;
|
|
|
|
|
gnc_hook_run(HOOK_CURRENCY_CHANGED, NULL);
|
2005-11-02 03:32:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
/* Return the number of decimal places for this locale. */
|
1998-09-21 03:42:58 +00:00
|
|
|
int
|
2000-11-08 10:53:39 +00:00
|
|
|
gnc_locale_decimal_places (void)
|
2000-03-22 10:10:50 +00:00
|
|
|
{
|
2000-11-01 08:52:30 +00:00
|
|
|
static gboolean got_it = FALSE;
|
|
|
|
|
static int places;
|
|
|
|
|
struct lconv *lc;
|
1998-10-18 21:13:40 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (got_it)
|
|
|
|
|
return places;
|
1998-10-18 21:13:40 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
lc = gnc_localeconv();
|
|
|
|
|
places = lc->frac_digits;
|
1998-10-18 21:13:40 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
/* frac_digits is already initialized by gnc_localeconv, hopefully
|
|
|
|
|
* to a reasonable default. */
|
|
|
|
|
got_it = TRUE;
|
1998-10-18 21:13:40 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
return places;
|
1998-10-18 21:13:40 +00:00
|
|
|
}
|
|
|
|
|
|
1999-12-31 00:05:41 +00:00
|
|
|
|
2001-03-30 12:43:11 +00:00
|
|
|
static GList *locale_stack = NULL;
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gnc_push_locale (const char *locale)
|
|
|
|
|
{
|
|
|
|
|
char *saved_locale;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (locale != NULL);
|
|
|
|
|
|
|
|
|
|
saved_locale = g_strdup (setlocale (LC_ALL, NULL));
|
|
|
|
|
locale_stack = g_list_prepend (locale_stack, saved_locale);
|
|
|
|
|
setlocale (LC_ALL, locale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gnc_pop_locale (void)
|
|
|
|
|
{
|
|
|
|
|
char *saved_locale;
|
|
|
|
|
GList *node;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (locale_stack != NULL);
|
|
|
|
|
|
|
|
|
|
node = locale_stack;
|
|
|
|
|
saved_locale = node->data;
|
|
|
|
|
|
|
|
|
|
setlocale (LC_ALL, saved_locale);
|
|
|
|
|
|
|
|
|
|
locale_stack = g_list_remove_link (locale_stack, node);
|
|
|
|
|
g_list_free_1 (node);
|
|
|
|
|
g_free (saved_locale);
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
GNCPrintAmountInfo
|
|
|
|
|
gnc_default_print_info (gboolean use_symbol)
|
|
|
|
|
{
|
|
|
|
|
static GNCPrintAmountInfo info;
|
|
|
|
|
static gboolean got_it = FALSE;
|
|
|
|
|
struct lconv *lc;
|
2000-03-24 09:47:27 +00:00
|
|
|
|
2001-10-03 10:07:45 +00:00
|
|
|
/* These must be updated each time. */
|
2001-02-18 15:05:38 +00:00
|
|
|
info.use_symbol = use_symbol ? 1 : 0;
|
2001-10-03 10:07:45 +00:00
|
|
|
info.commodity = gnc_default_currency ();
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (got_it)
|
|
|
|
|
return info;
|
2000-03-24 09:47:27 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
lc = gnc_localeconv ();
|
2000-03-24 09:47:27 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
info.max_decimal_places = lc->frac_digits;
|
|
|
|
|
info.min_decimal_places = lc->frac_digits;
|
2000-03-24 09:47:27 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
info.use_separators = 1;
|
|
|
|
|
info.use_locale = 1;
|
|
|
|
|
info.monetary = 1;
|
2002-12-16 01:40:26 +00:00
|
|
|
info.force_fit = 0;
|
|
|
|
|
info.round = 0;
|
1999-07-05 22:47:57 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
got_it = TRUE;
|
|
|
|
|
|
|
|
|
|
return info;
|
1999-07-05 22:47:57 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
static gboolean
|
2000-11-08 10:53:39 +00:00
|
|
|
is_decimal_fraction (int fraction, guint8 *max_decimal_places_p)
|
2000-11-01 08:52:30 +00:00
|
|
|
{
|
2000-11-08 10:53:39 +00:00
|
|
|
guint8 max_decimal_places = 0;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-11-08 10:53:39 +00:00
|
|
|
if (fraction <= 0)
|
|
|
|
|
return FALSE;
|
1997-12-06 02:59:44 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
while (fraction != 1)
|
|
|
|
|
{
|
2000-11-08 10:53:39 +00:00
|
|
|
if (fraction % 10 != 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
fraction = fraction / 10;
|
2000-11-08 10:53:39 +00:00
|
|
|
max_decimal_places += 1;
|
2000-11-01 08:52:30 +00:00
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-11-08 10:53:39 +00:00
|
|
|
if (max_decimal_places_p)
|
|
|
|
|
*max_decimal_places_p = max_decimal_places;
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
return TRUE;
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
GNCPrintAmountInfo
|
2001-04-30 06:56:00 +00:00
|
|
|
gnc_commodity_print_info (const gnc_commodity *commodity,
|
2000-11-01 08:52:30 +00:00
|
|
|
gboolean use_symbol)
|
2000-02-27 21:33:56 +00:00
|
|
|
{
|
2000-11-01 08:52:30 +00:00
|
|
|
GNCPrintAmountInfo info;
|
|
|
|
|
gboolean is_iso;
|
|
|
|
|
|
|
|
|
|
if (commodity == NULL)
|
|
|
|
|
return gnc_default_print_info (use_symbol);
|
|
|
|
|
|
|
|
|
|
info.commodity = commodity;
|
|
|
|
|
|
2003-04-29 06:15:34 +00:00
|
|
|
is_iso = gnc_commodity_is_iso (commodity);
|
2000-11-01 08:52:30 +00:00
|
|
|
|
|
|
|
|
if (is_decimal_fraction (gnc_commodity_get_fraction (commodity),
|
|
|
|
|
&info.max_decimal_places))
|
|
|
|
|
{
|
|
|
|
|
if (is_iso)
|
|
|
|
|
info.min_decimal_places = info.max_decimal_places;
|
|
|
|
|
else
|
|
|
|
|
info.min_decimal_places = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
info.max_decimal_places = info.min_decimal_places = 0;
|
|
|
|
|
|
|
|
|
|
info.use_separators = 1;
|
|
|
|
|
info.use_symbol = use_symbol ? 1 : 0;
|
|
|
|
|
info.use_locale = is_iso ? 1 : 0;
|
|
|
|
|
info.monetary = 1;
|
2002-12-16 01:40:26 +00:00
|
|
|
info.force_fit = 0;
|
|
|
|
|
info.round = 0;
|
2000-11-01 08:52:30 +00:00
|
|
|
|
|
|
|
|
return info;
|
2000-02-27 21:33:56 +00:00
|
|
|
}
|
|
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
static GNCPrintAmountInfo
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_account_print_info_helper(const Account *account, gboolean use_symbol,
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_commodity * (*efffunc)(const Account *),
|
|
|
|
|
int (*scufunc)(const Account*))
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
2000-11-01 21:37:15 +00:00
|
|
|
GNCPrintAmountInfo info;
|
|
|
|
|
gboolean is_iso;
|
|
|
|
|
int scu;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-11-01 21:37:15 +00:00
|
|
|
if (account == NULL)
|
2000-11-01 08:52:30 +00:00
|
|
|
return gnc_default_print_info (use_symbol);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
info.commodity = efffunc (account);
|
2000-11-01 21:37:15 +00:00
|
|
|
|
2003-04-29 06:15:34 +00:00
|
|
|
is_iso = gnc_commodity_is_iso (info.commodity);
|
2000-11-01 21:37:15 +00:00
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
scu = scufunc (account);
|
2000-11-01 21:37:15 +00:00
|
|
|
|
|
|
|
|
if (is_decimal_fraction (scu, &info.max_decimal_places))
|
|
|
|
|
{
|
|
|
|
|
if (is_iso)
|
|
|
|
|
info.min_decimal_places = info.max_decimal_places;
|
|
|
|
|
else
|
|
|
|
|
info.min_decimal_places = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
info.max_decimal_places = info.min_decimal_places = 0;
|
|
|
|
|
|
|
|
|
|
info.use_separators = 1;
|
|
|
|
|
info.use_symbol = use_symbol ? 1 : 0;
|
|
|
|
|
info.use_locale = is_iso ? 1 : 0;
|
|
|
|
|
info.monetary = 1;
|
2002-12-16 01:40:26 +00:00
|
|
|
info.force_fit = 0;
|
|
|
|
|
info.round = 0;
|
2000-11-01 21:37:15 +00:00
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
GNCPrintAmountInfo
|
2006-02-27 23:57:16 +00:00
|
|
|
gnc_account_print_info (const Account *account, gboolean use_symbol)
|
2001-03-09 22:04:07 +00:00
|
|
|
{
|
|
|
|
|
return gnc_account_print_info_helper(account, use_symbol,
|
2001-07-05 08:32:40 +00:00
|
|
|
xaccAccountGetCommodity,
|
|
|
|
|
xaccAccountGetCommoditySCU);
|
2000-11-01 08:52:30 +00:00
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
GNCPrintAmountInfo
|
2001-07-12 22:21:13 +00:00
|
|
|
gnc_split_amount_print_info (Split *split, gboolean use_symbol)
|
2000-11-01 08:52:30 +00:00
|
|
|
{
|
2001-03-09 22:20:02 +00:00
|
|
|
if (!split)
|
|
|
|
|
{
|
|
|
|
|
GNCPrintAmountInfo info = gnc_default_share_print_info ();
|
|
|
|
|
info.use_symbol = use_symbol;
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-05 08:32:40 +00:00
|
|
|
return gnc_account_print_info (xaccSplitGetAccount (split), use_symbol);
|
2000-11-01 08:52:30 +00:00
|
|
|
}
|
1998-11-16 07:01:09 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
GNCPrintAmountInfo
|
|
|
|
|
gnc_split_value_print_info (Split *split, gboolean use_symbol)
|
|
|
|
|
{
|
2001-07-12 00:13:21 +00:00
|
|
|
Transaction *trans;
|
|
|
|
|
|
2001-03-09 22:20:02 +00:00
|
|
|
if (!split) return gnc_default_print_info (use_symbol);
|
2001-07-12 00:13:21 +00:00
|
|
|
|
|
|
|
|
trans = xaccSplitGetParent (split);
|
|
|
|
|
|
|
|
|
|
return gnc_commodity_print_info (xaccTransGetCurrency (trans), use_symbol);
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
static GNCPrintAmountInfo
|
2001-03-09 22:20:02 +00:00
|
|
|
gnc_default_print_info_helper (int decplaces)
|
2001-03-09 22:04:07 +00:00
|
|
|
{
|
|
|
|
|
GNCPrintAmountInfo info;
|
|
|
|
|
|
|
|
|
|
info.commodity = NULL;
|
2001-03-09 22:20:02 +00:00
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
info.max_decimal_places = decplaces;
|
|
|
|
|
info.min_decimal_places = 0;
|
2001-03-09 22:20:02 +00:00
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
info.use_separators = 1;
|
|
|
|
|
info.use_symbol = 0;
|
|
|
|
|
info.use_locale = 1;
|
|
|
|
|
info.monetary = 1;
|
2002-12-16 01:40:26 +00:00
|
|
|
info.force_fit = 0;
|
|
|
|
|
info.round = 0;
|
2001-03-09 22:04:07 +00:00
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
2001-03-09 22:20:02 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
GNCPrintAmountInfo
|
|
|
|
|
gnc_default_share_print_info (void)
|
2000-10-23 10:16:07 +00:00
|
|
|
{
|
2000-11-01 08:52:30 +00:00
|
|
|
static GNCPrintAmountInfo info;
|
|
|
|
|
static gboolean got_it = FALSE;
|
2000-10-23 09:41:51 +00:00
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
if (!got_it)
|
|
|
|
|
{
|
2001-03-09 22:20:02 +00:00
|
|
|
info = gnc_default_print_info_helper (5);
|
2001-03-09 22:04:07 +00:00
|
|
|
got_it = TRUE;
|
|
|
|
|
}
|
2001-03-09 22:20:02 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
return info;
|
2000-03-23 11:31:40 +00:00
|
|
|
}
|
|
|
|
|
|
2002-12-16 01:40:26 +00:00
|
|
|
GNCPrintAmountInfo
|
|
|
|
|
gnc_share_print_info_places (int decplaces)
|
|
|
|
|
{
|
|
|
|
|
GNCPrintAmountInfo info;
|
|
|
|
|
|
|
|
|
|
info = gnc_default_share_print_info ();
|
|
|
|
|
info.max_decimal_places = decplaces;
|
|
|
|
|
info.min_decimal_places = decplaces;
|
|
|
|
|
info.force_fit = 1;
|
|
|
|
|
info.round = 1;
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
GNCPrintAmountInfo
|
|
|
|
|
gnc_default_price_print_info (void)
|
2000-08-27 08:25:53 +00:00
|
|
|
{
|
2000-11-01 08:52:30 +00:00
|
|
|
static GNCPrintAmountInfo info;
|
2000-08-27 08:25:53 +00:00
|
|
|
static gboolean got_it = FALSE;
|
|
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
if (!got_it)
|
|
|
|
|
{
|
2001-03-09 22:20:02 +00:00
|
|
|
info = gnc_default_print_info_helper (6);
|
|
|
|
|
got_it = TRUE;
|
2001-03-09 22:04:07 +00:00
|
|
|
}
|
2000-08-27 08:25:53 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
return info;
|
2000-08-27 08:25:53 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-09 06:09:04 +00:00
|
|
|
GNCPrintAmountInfo
|
|
|
|
|
gnc_integral_print_info (void)
|
|
|
|
|
{
|
|
|
|
|
static GNCPrintAmountInfo info;
|
|
|
|
|
static gboolean got_it = FALSE;
|
|
|
|
|
|
2001-03-09 22:04:07 +00:00
|
|
|
if (!got_it)
|
|
|
|
|
{
|
2001-03-09 22:20:02 +00:00
|
|
|
info = gnc_default_print_info_helper (0);
|
|
|
|
|
got_it = TRUE;
|
2001-03-09 22:04:07 +00:00
|
|
|
}
|
2000-11-09 06:09:04 +00:00
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
/* Utility function for printing non-negative amounts */
|
1998-11-16 06:28:13 +00:00
|
|
|
static int
|
2000-11-03 08:43:55 +00:00
|
|
|
PrintAmountInternal(char *buf, gnc_numeric val, const GNCPrintAmountInfo *info)
|
1998-11-16 06:28:13 +00:00
|
|
|
{
|
2000-01-17 21:39:42 +00:00
|
|
|
struct lconv *lc = gnc_localeconv();
|
2000-11-09 09:14:34 +00:00
|
|
|
int num_whole_digits;
|
2006-03-01 23:01:43 +00:00
|
|
|
char temp_buf[128];
|
2002-12-16 01:40:26 +00:00
|
|
|
gnc_numeric whole, rounding;
|
|
|
|
|
int min_dp, max_dp;
|
1999-12-31 00:05:41 +00:00
|
|
|
|
2001-10-11 11:35:50 +00:00
|
|
|
g_return_val_if_fail (info != NULL, 0);
|
2000-11-01 08:52:30 +00:00
|
|
|
|
2000-11-03 08:43:55 +00:00
|
|
|
if (gnc_numeric_check (val))
|
|
|
|
|
{
|
|
|
|
|
PWARN ("Bad numeric.");
|
|
|
|
|
*buf = '\0';
|
|
|
|
|
return 0;
|
1999-12-31 00:05:41 +00:00
|
|
|
}
|
1998-11-16 06:28:13 +00:00
|
|
|
|
2003-02-05 16:01:19 +00:00
|
|
|
/* print the absolute value */
|
|
|
|
|
val = gnc_numeric_abs (val);
|
|
|
|
|
|
2002-12-16 01:40:26 +00:00
|
|
|
/* Force at least auto_decimal_places zeros */
|
|
|
|
|
if (auto_decimal_enabled) {
|
|
|
|
|
min_dp = MAX(auto_decimal_places, info->min_decimal_places);
|
|
|
|
|
max_dp = MAX(auto_decimal_places, info->max_decimal_places);
|
|
|
|
|
} else {
|
|
|
|
|
min_dp = info->min_decimal_places;
|
|
|
|
|
max_dp = info->max_decimal_places;
|
|
|
|
|
}
|
2003-02-05 16:01:19 +00:00
|
|
|
|
|
|
|
|
/* Don to limit the number of decimal places _UNLESS_ force_fit is
|
|
|
|
|
* true. */
|
2002-12-16 01:40:26 +00:00
|
|
|
if (!info->force_fit)
|
|
|
|
|
max_dp = 99;
|
|
|
|
|
|
2003-02-05 16:01:19 +00:00
|
|
|
/* rounding? -- can only ROUND if force_fit is also true */
|
|
|
|
|
if (info->round && info->force_fit) {
|
|
|
|
|
rounding.num = 5; /* Limit the denom to 10^13 ~= 2^44, leaving max at ~524288 */
|
2002-12-16 01:40:26 +00:00
|
|
|
rounding.denom = pow(10, max_dp + 1);
|
|
|
|
|
val = gnc_numeric_add(val, rounding, GNC_DENOM_AUTO, GNC_DENOM_LCD);
|
2006-01-06 22:28:38 +00:00
|
|
|
/* Yes, rounding up can cause overflow. Check for it. */
|
|
|
|
|
if (gnc_numeric_check(val)) {
|
|
|
|
|
PWARN("Bad numeric from rounding.");
|
|
|
|
|
*buf = '\0';
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2002-12-16 01:40:26 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-03 08:43:55 +00:00
|
|
|
/* calculate the integer part and the remainder */
|
2006-02-04 15:06:19 +00:00
|
|
|
whole = gnc_numeric_convert(val, 1, GNC_HOW_RND_TRUNC);
|
|
|
|
|
val = gnc_numeric_sub (val, whole, GNC_DENOM_AUTO, GNC_HOW_RND_NEVER);
|
2000-11-03 08:43:55 +00:00
|
|
|
if (gnc_numeric_check (val))
|
2000-02-27 21:33:56 +00:00
|
|
|
{
|
2000-11-03 08:43:55 +00:00
|
|
|
PWARN ("Problem with remainder.");
|
|
|
|
|
*buf = '\0';
|
|
|
|
|
return 0;
|
2000-02-27 21:33:56 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-03 08:43:55 +00:00
|
|
|
/* print the integer part without separators */
|
2006-04-14 16:45:10 +00:00
|
|
|
sprintf(temp_buf, "%" G_GINT64_FORMAT, whole.num);
|
2000-11-03 08:43:55 +00:00
|
|
|
num_whole_digits = strlen (temp_buf);
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (!info->use_separators)
|
2000-11-03 08:43:55 +00:00
|
|
|
strcpy (buf, temp_buf);
|
1999-12-31 00:05:41 +00:00
|
|
|
else
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
2000-09-26 00:45:16 +00:00
|
|
|
int group_count;
|
2006-03-01 23:01:43 +00:00
|
|
|
char *separator;
|
2000-09-26 00:45:16 +00:00
|
|
|
char *temp_ptr;
|
|
|
|
|
char *buf_ptr;
|
|
|
|
|
char *group;
|
2006-03-01 23:01:43 +00:00
|
|
|
gchar *rev_buf;
|
2000-09-26 00:45:16 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (info->monetary)
|
2000-09-26 00:45:16 +00:00
|
|
|
{
|
2006-03-01 23:01:43 +00:00
|
|
|
separator = lc->mon_thousands_sep;
|
2000-09-26 00:45:16 +00:00
|
|
|
group = lc->mon_grouping;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-03-01 23:01:43 +00:00
|
|
|
separator = lc->thousands_sep;
|
2000-09-26 00:45:16 +00:00
|
|
|
group = lc->grouping;
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
2000-09-26 00:45:16 +00:00
|
|
|
buf_ptr = buf;
|
|
|
|
|
temp_ptr = &temp_buf[num_whole_digits - 1];
|
|
|
|
|
group_count = 0;
|
|
|
|
|
|
|
|
|
|
while (temp_ptr != temp_buf)
|
|
|
|
|
{
|
|
|
|
|
*buf_ptr++ = *temp_ptr--;
|
|
|
|
|
|
|
|
|
|
if (*group != CHAR_MAX)
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
2000-09-26 00:45:16 +00:00
|
|
|
group_count++;
|
|
|
|
|
|
|
|
|
|
if (group_count == *group)
|
|
|
|
|
{
|
2006-03-01 23:01:43 +00:00
|
|
|
g_utf8_strncpy(buf_ptr, separator, 1);
|
|
|
|
|
buf_ptr = g_utf8_find_next_char(buf_ptr, NULL);
|
2000-09-26 00:45:16 +00:00
|
|
|
group_count = 0;
|
|
|
|
|
|
|
|
|
|
/* 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:
|
|
|
|
|
/* fall through */
|
|
|
|
|
/* Anything else means another group size */
|
|
|
|
|
default:
|
|
|
|
|
group++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-12-31 00:05:41 +00:00
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
2000-09-26 00:45:16 +00:00
|
|
|
/* We built the string backwards, now reverse */
|
|
|
|
|
*buf_ptr++ = *temp_ptr;
|
|
|
|
|
*buf_ptr = '\0';
|
2006-03-01 23:01:43 +00:00
|
|
|
rev_buf = g_utf8_strreverse(buf, -1);
|
|
|
|
|
strcpy (buf, rev_buf);
|
|
|
|
|
g_free(rev_buf);
|
2000-01-17 21:39:42 +00:00
|
|
|
} /* endif */
|
1998-11-16 06:28:13 +00:00
|
|
|
|
2000-11-03 08:43:55 +00:00
|
|
|
/* at this point, buf contains the whole part of the number */
|
|
|
|
|
|
|
|
|
|
/* If it's not decimal, print the fraction as an expression */
|
|
|
|
|
if (!is_decimal_fraction (val.denom, NULL))
|
|
|
|
|
{
|
|
|
|
|
if (!gnc_numeric_zero_p (val))
|
|
|
|
|
{
|
|
|
|
|
val = gnc_numeric_reduce (val);
|
|
|
|
|
|
2006-02-04 15:06:19 +00:00
|
|
|
if (val.denom > 0)
|
|
|
|
|
sprintf (temp_buf, " + %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT,
|
|
|
|
|
val.num, val.denom);
|
|
|
|
|
else
|
|
|
|
|
sprintf (temp_buf, " + %" G_GINT64_FORMAT " * %" G_GINT64_FORMAT,
|
|
|
|
|
val.num, -val.denom);
|
2000-11-03 08:43:55 +00:00
|
|
|
|
|
|
|
|
strcat (buf, temp_buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-03-01 23:01:43 +00:00
|
|
|
char *decimal_point;
|
2000-11-03 08:43:55 +00:00
|
|
|
guint8 num_decimal_places = 0;
|
|
|
|
|
char *temp_ptr = temp_buf;
|
|
|
|
|
|
2007-04-11 22:00:35 +00:00
|
|
|
decimal_point = info->monetary
|
|
|
|
|
? lc->mon_decimal_point
|
|
|
|
|
: lc->decimal_point;
|
2006-03-01 23:01:43 +00:00
|
|
|
g_utf8_strncpy(temp_ptr, decimal_point, 1);
|
|
|
|
|
temp_ptr = g_utf8_find_next_char(temp_ptr, NULL);
|
2000-11-03 08:43:55 +00:00
|
|
|
|
2007-04-11 22:00:35 +00:00
|
|
|
while (!gnc_numeric_zero_p (val)
|
|
|
|
|
&& (val.denom != 1)
|
|
|
|
|
&& (num_decimal_places < max_dp))
|
2000-11-03 08:43:55 +00:00
|
|
|
{
|
|
|
|
|
gint64 digit;
|
|
|
|
|
|
|
|
|
|
val.denom = val.denom / 10;
|
|
|
|
|
|
|
|
|
|
digit = val.num / val.denom;
|
|
|
|
|
|
|
|
|
|
*temp_ptr++ = digit + '0';
|
|
|
|
|
num_decimal_places++;
|
|
|
|
|
|
|
|
|
|
val.num = val.num - (digit * val.denom);
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-03 05:59:51 +00:00
|
|
|
while (num_decimal_places < min_dp)
|
2000-11-03 08:43:55 +00:00
|
|
|
{
|
|
|
|
|
*temp_ptr++ = '0';
|
|
|
|
|
num_decimal_places++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* cap the end and move to the last character */
|
|
|
|
|
*temp_ptr-- = '\0';
|
|
|
|
|
|
|
|
|
|
/* Here we strip off trailing decimal zeros per the argument. */
|
2002-07-03 05:59:51 +00:00
|
|
|
while (*temp_ptr == '0' && num_decimal_places > min_dp)
|
2000-11-03 08:43:55 +00:00
|
|
|
{
|
|
|
|
|
*temp_ptr-- = '\0';
|
|
|
|
|
num_decimal_places--;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-03 05:59:51 +00:00
|
|
|
if (num_decimal_places > max_dp)
|
2000-11-03 08:43:55 +00:00
|
|
|
{
|
2002-05-07 03:22:04 +00:00
|
|
|
PWARN ("max_decimal_places too small; limit %d, value %s%s",
|
|
|
|
|
info->max_decimal_places, buf, temp_buf);
|
2000-11-03 08:43:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (num_decimal_places > 0)
|
|
|
|
|
strcat (buf, temp_buf);
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-31 00:05:41 +00:00
|
|
|
return strlen(buf);
|
1998-11-16 06:28:13 +00:00
|
|
|
}
|
|
|
|
|
|
2002-12-16 00:35:27 +00:00
|
|
|
/**
|
|
|
|
|
* @param bufp Should be at least 64 chars.
|
|
|
|
|
**/
|
1999-01-30 21:22:13 +00:00
|
|
|
int
|
2000-11-08 10:53:39 +00:00
|
|
|
xaccSPrintAmount (char * bufp, gnc_numeric val, GNCPrintAmountInfo info)
|
1997-12-06 02:59:44 +00:00
|
|
|
{
|
2000-01-17 21:39:42 +00:00
|
|
|
struct lconv *lc;
|
|
|
|
|
|
|
|
|
|
char *orig_bufp = bufp;
|
2000-04-24 23:20:36 +00:00
|
|
|
const char *currency_symbol;
|
|
|
|
|
const char *sign;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
char cs_precedes;
|
|
|
|
|
char sep_by_space;
|
|
|
|
|
char sign_posn;
|
|
|
|
|
|
2000-08-21 10:26:57 +00:00
|
|
|
gboolean print_sign = TRUE;
|
2001-03-21 00:08:57 +00:00
|
|
|
gboolean is_shares = FALSE;
|
1999-01-30 21:22:13 +00:00
|
|
|
|
2000-11-08 10:53:39 +00:00
|
|
|
if (!bufp)
|
|
|
|
|
return 0;
|
1998-11-16 06:28:13 +00:00
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
lc = gnc_localeconv();
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (info.use_symbol)
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
2002-11-30 13:38:34 +00:00
|
|
|
/* There was a bug here: don't use gnc_locale_default_currency */
|
|
|
|
|
if (gnc_commodity_equiv (info.commodity,
|
|
|
|
|
gnc_locale_default_currency_nodefault ()))
|
|
|
|
|
{
|
2000-04-21 10:49:15 +00:00
|
|
|
currency_symbol = lc->currency_symbol;
|
2002-11-30 13:38:34 +00:00
|
|
|
}
|
2000-04-21 10:49:15 +00:00
|
|
|
else
|
|
|
|
|
{
|
2003-04-29 06:15:34 +00:00
|
|
|
if (info.commodity && !gnc_commodity_is_iso (info.commodity))
|
2001-03-21 00:08:57 +00:00
|
|
|
is_shares = TRUE;
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
currency_symbol = gnc_commodity_get_mnemonic (info.commodity);
|
|
|
|
|
info.use_locale = 0;
|
2000-04-21 10:49:15 +00:00
|
|
|
}
|
2000-04-24 21:28:25 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (currency_symbol == NULL)
|
|
|
|
|
currency_symbol = "";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
currency_symbol = NULL;
|
|
|
|
|
|
|
|
|
|
if (!info.use_locale)
|
|
|
|
|
{
|
2001-03-21 00:08:57 +00:00
|
|
|
cs_precedes = is_shares ? 0 : 1;
|
|
|
|
|
sep_by_space = 1;
|
2000-11-01 08:52:30 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2000-11-08 10:53:39 +00:00
|
|
|
if (gnc_numeric_negative_p (val))
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
|
|
|
|
cs_precedes = lc->n_cs_precedes;
|
|
|
|
|
sep_by_space = lc->n_sep_by_space;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cs_precedes = lc->p_cs_precedes;
|
|
|
|
|
sep_by_space = lc->p_sep_by_space;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-08 10:53:39 +00:00
|
|
|
if (gnc_numeric_negative_p (val))
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
|
|
|
|
sign = lc->negative_sign;
|
|
|
|
|
sign_posn = lc->n_sign_posn;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sign = lc->positive_sign;
|
|
|
|
|
sign_posn = lc->p_sign_posn;
|
|
|
|
|
}
|
1999-12-31 00:05:41 +00:00
|
|
|
|
2000-11-08 10:53:39 +00:00
|
|
|
if (gnc_numeric_zero_p (val) || (sign == NULL) || (sign[0] == 0))
|
2000-08-21 10:26:57 +00:00
|
|
|
print_sign = FALSE;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 1))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, sign);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
/* Now see if we print currency */
|
|
|
|
|
if (cs_precedes)
|
|
|
|
|
{
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 3))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, sign);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (info.use_symbol)
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, currency_symbol);
|
2000-01-17 21:39:42 +00:00
|
|
|
if (sep_by_space)
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, " ");
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 4))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, sign);
|
1997-12-06 02:59:44 +00:00
|
|
|
}
|
|
|
|
|
|
2000-01-17 21:39:42 +00:00
|
|
|
/* Now see if we print parentheses */
|
2000-02-27 21:33:56 +00:00
|
|
|
if (print_sign && (sign_posn == 0))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, "(");
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
/* Now print the value */
|
2000-11-08 10:53:39 +00:00
|
|
|
bufp += PrintAmountInternal(bufp, val, &info);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
/* Now see if we print parentheses */
|
2000-02-27 21:33:56 +00:00
|
|
|
if (print_sign && (sign_posn == 0))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, ")");
|
2000-01-17 21:39:42 +00:00
|
|
|
|
|
|
|
|
/* Now see if we print currency */
|
|
|
|
|
if (!cs_precedes)
|
|
|
|
|
{
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 3))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, sign);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
if (info.use_symbol)
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
|
|
|
|
if (sep_by_space)
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, " ");
|
|
|
|
|
bufp = g_stpcpy(bufp, currency_symbol);
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 4))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, sign);
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See if we print sign now */
|
|
|
|
|
if (print_sign && (sign_posn == 2))
|
2006-04-07 18:52:28 +00:00
|
|
|
bufp = g_stpcpy(bufp, sign);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
1999-01-30 21:22:13 +00:00
|
|
|
/* return length of printed string */
|
2000-01-17 21:39:42 +00:00
|
|
|
return (bufp - orig_bufp);
|
1999-01-30 21:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
2000-08-22 01:35:47 +00:00
|
|
|
const char *
|
2000-11-08 10:53:39 +00:00
|
|
|
xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info)
|
1999-01-30 21:22:13 +00:00
|
|
|
{
|
2000-11-08 10:53:39 +00:00
|
|
|
/* hack alert -- this is not thread safe ... */
|
|
|
|
|
static char buf[1024];
|
1999-01-30 21:22:13 +00:00
|
|
|
|
2006-01-09 03:33:46 +00:00
|
|
|
if (!xaccSPrintAmount (buf, val, info))
|
|
|
|
|
buf[0] = '\0';
|
1999-01-30 21:22:13 +00:00
|
|
|
|
2000-11-08 10:53:39 +00:00
|
|
|
/* its OK to return buf, since we declared it static */
|
|
|
|
|
return buf;
|
1997-12-06 02:59:44 +00:00
|
|
|
}
|
|
|
|
|
|
1998-02-02 23:25:44 +00:00
|
|
|
|
2007-03-13 03:43:24 +00:00
|
|
|
/********************************************************************\
|
|
|
|
|
********************************************************************/
|
|
|
|
|
|
|
|
|
|
#define FUDGE .00001
|
|
|
|
|
|
2007-04-15 18:53:56 +00:00
|
|
|
/* This function is basically untranslatable. I'd
|
2007-04-14 11:24:15 +00:00
|
|
|
guess out of the 29 translations we have, 20 will have their number
|
|
|
|
|
wordings in a totally different way than English has (not to
|
|
|
|
|
mention gender-dependent number endings). Which means this
|
|
|
|
|
word-by-word translation will be useless or even plain
|
2007-04-15 18:53:56 +00:00
|
|
|
wrong. For this reason, we don't even start to pretend a
|
|
|
|
|
word-by-word translation would be of any use, so we don't mark any
|
|
|
|
|
of these strings for translation. cstim, 2007-04-15. */
|
2007-03-13 03:43:24 +00:00
|
|
|
static gchar *small_numbers[] = {
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This section is for generating the "amount, in
|
|
|
|
|
words" field when printing a check. This function gets the
|
|
|
|
|
wording right for English, but unfortunately not for most other
|
|
|
|
|
languages. Decide for yourself whether the check printing is
|
|
|
|
|
actually needed in your language; if not, you can safely skip the
|
|
|
|
|
translation of all of these strings. */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Zero", "One", "Two", "Three", "Four",
|
|
|
|
|
"Five", "Six", "Seven", "Eight", "Nine",
|
|
|
|
|
"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
|
|
|
|
|
"Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen",
|
|
|
|
|
"Twenty"};
|
2007-03-13 03:43:24 +00:00
|
|
|
static gchar *medium_numbers[] = {
|
2007-04-15 18:53:56 +00:00
|
|
|
"Zero", "Ten", "Twenty", "Thirty", "Forty",
|
|
|
|
|
"Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
|
2007-03-13 03:43:24 +00:00
|
|
|
static gchar *big_numbers[] = {
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is the word for the number 10^2 */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Hundred",
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is the word for the number 10^3 */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Thousand",
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is the word for the number 10^6, one thousand
|
|
|
|
|
thousands. */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Million",
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is the word for the number 10^9, one thousand
|
|
|
|
|
millions. WATCH OUT: In British english and many other languages
|
|
|
|
|
this word is used for 10^12 which is one million millions! In
|
|
|
|
|
contrast to this, here in GnuCash this is used in the American
|
|
|
|
|
english meaning of 10^9. */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Billion",
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is the word for the number 10^12, one million
|
|
|
|
|
millions. */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Trillion",
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is the word for the number 10^15 */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Quadrillion",
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is the word for the number 10^18 */
|
2007-04-15 18:53:56 +00:00
|
|
|
"Quintillion"};
|
2007-03-13 03:43:24 +00:00
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
|
integer_to_words(gint64 val)
|
|
|
|
|
{
|
|
|
|
|
gint64 log_val, pow_val, this_part;
|
|
|
|
|
GString *result;
|
|
|
|
|
gchar *tmp;
|
|
|
|
|
|
|
|
|
|
if (val == 0)
|
|
|
|
|
return g_strdup("zero");
|
|
|
|
|
if (val < 0)
|
|
|
|
|
val = -val;
|
|
|
|
|
|
|
|
|
|
result = g_string_sized_new(100);
|
|
|
|
|
|
|
|
|
|
while (val >= 1000) {
|
|
|
|
|
log_val = log10(val) / 3 + FUDGE;
|
2007-03-14 09:55:32 +00:00
|
|
|
pow_val = exp(log_val * 3 * G_LN10) + FUDGE;
|
2007-03-13 03:43:24 +00:00
|
|
|
this_part = val / pow_val;
|
|
|
|
|
val -= this_part * pow_val;
|
|
|
|
|
tmp = integer_to_words(this_part);
|
|
|
|
|
g_string_append_printf(result, "%s %s ", tmp,
|
|
|
|
|
gettext(big_numbers[log_val]));
|
|
|
|
|
g_free(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (val >= 100) {
|
|
|
|
|
this_part = val / 100;
|
|
|
|
|
val -= this_part * 100;
|
|
|
|
|
g_string_append_printf(result, "%s %s ",
|
|
|
|
|
gettext(small_numbers[this_part]),
|
|
|
|
|
gettext(big_numbers[0]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (val > 20) {
|
|
|
|
|
this_part = val / 10;
|
|
|
|
|
val -= this_part * 10;
|
|
|
|
|
g_string_append(result, gettext(medium_numbers[this_part]));
|
|
|
|
|
g_string_append_c(result, ' ');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (val > 0) {
|
|
|
|
|
this_part = val;
|
|
|
|
|
val -= this_part;
|
|
|
|
|
g_string_append(result, gettext(small_numbers[this_part]));
|
|
|
|
|
g_string_append_c(result, ' ');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = g_string_truncate(result, result->len - 1);
|
|
|
|
|
return g_string_free(result, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gchar *
|
|
|
|
|
number_to_words(gdouble val, gint64 denom)
|
|
|
|
|
{
|
|
|
|
|
gint64 int_part, frac_part;
|
2007-04-14 11:24:15 +00:00
|
|
|
gchar *int_string, *nomin_string, *denom_string, *full_string;
|
2007-03-13 03:43:24 +00:00
|
|
|
|
|
|
|
|
if (val < 0) val = -val;
|
|
|
|
|
if (denom < 0) denom = -denom;
|
|
|
|
|
|
|
|
|
|
int_part = trunc(val);
|
|
|
|
|
frac_part = round((val - int_part) * denom);
|
|
|
|
|
|
|
|
|
|
int_string = integer_to_words(int_part);
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Inside of the gettext macro _(...) we must not use any macros but
|
|
|
|
|
only plain string literals. For this reason, convert the strings
|
|
|
|
|
separately. */
|
|
|
|
|
nomin_string = g_strdup_printf("%" G_GINT64_FORMAT, frac_part);
|
|
|
|
|
denom_string = g_strdup_printf("%" G_GINT64_FORMAT, denom);
|
2007-03-13 03:43:24 +00:00
|
|
|
full_string =
|
2007-04-14 11:24:15 +00:00
|
|
|
/* Translators: This is for the "amount, in words" field in check
|
|
|
|
|
printing. The first %s is the integer amount of dollars (or
|
|
|
|
|
whatever currency), the second and third %s the cent amount as
|
|
|
|
|
a fraction, e.g. 47/100. */
|
2007-04-15 18:53:56 +00:00
|
|
|
g_strdup_printf("%s and %s/%s",
|
2007-04-14 11:24:15 +00:00
|
|
|
int_string, nomin_string, denom_string);
|
2007-03-13 03:43:24 +00:00
|
|
|
g_free(int_string);
|
2007-04-14 11:24:15 +00:00
|
|
|
g_free(nomin_string);
|
|
|
|
|
g_free(denom_string);
|
2007-03-13 03:43:24 +00:00
|
|
|
return full_string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gchar *
|
|
|
|
|
numeric_to_words(gnc_numeric val)
|
|
|
|
|
{
|
|
|
|
|
return number_to_words(gnc_numeric_to_double(val),
|
|
|
|
|
gnc_numeric_denom(val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
|
printable_value (gdouble val, gint denom)
|
|
|
|
|
{
|
|
|
|
|
GNCPrintAmountInfo info;
|
|
|
|
|
gnc_numeric num;
|
|
|
|
|
|
|
|
|
|
num = gnc_numeric_create(round(val * denom), denom);
|
|
|
|
|
info = gnc_share_print_info_places(log10(denom));
|
|
|
|
|
return xaccPrintAmount (num, info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-02-02 23:25:44 +00:00
|
|
|
/********************************************************************\
|
2000-11-08 10:53:39 +00:00
|
|
|
* xaccParseAmount *
|
2000-01-17 21:39:42 +00:00
|
|
|
* parses amount strings using locale data *
|
|
|
|
|
* *
|
2000-08-31 07:16:55 +00:00
|
|
|
* 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 *
|
2000-01-17 21:39:42 +00:00
|
|
|
\********************************************************************/
|
|
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* Parsing state machine states */
|
|
|
|
|
typedef enum
|
2000-01-17 21:39:42 +00:00
|
|
|
{
|
2000-08-31 07:16:55 +00:00
|
|
|
START_ST, /* Parsing initial whitespace */
|
2000-10-27 20:30:30 +00:00
|
|
|
NEG_ST, /* Parsed a negative sign or a left paren */
|
2000-08-31 07:16:55 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
#define done_state(state) (((state) == DONE_ST) || ((state) == NO_NUM_ST))
|
|
|
|
|
|
2001-04-15 23:07:30 +00:00
|
|
|
G_INLINE_FUNC long long int multiplier (int num_decimals);
|
2000-09-13 22:33:15 +00:00
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
long long int
|
2000-10-29 20:32:38 +00:00
|
|
|
multiplier (int num_decimals)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
switch (num_decimals)
|
|
|
|
|
{
|
|
|
|
|
case 8:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 100000000;
|
2000-08-31 07:16:55 +00:00
|
|
|
case 7:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 10000000;
|
2000-08-31 07:16:55 +00:00
|
|
|
case 6:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 1000000;
|
2000-08-31 07:16:55 +00:00
|
|
|
case 5:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 100000;
|
2000-08-31 07:16:55 +00:00
|
|
|
case 4:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 10000;
|
2000-08-31 07:16:55 +00:00
|
|
|
case 3:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 1000;
|
2000-08-31 07:16:55 +00:00
|
|
|
case 2:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 100;
|
2000-08-31 07:16:55 +00:00
|
|
|
case 1:
|
2000-10-29 20:32:38 +00:00
|
|
|
return 10;
|
2000-08-31 07:16:55 +00:00
|
|
|
default:
|
|
|
|
|
PERR("bad fraction length");
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-10-29 20:32:38 +00:00
|
|
|
return 1;
|
2000-08-31 07:16:55 +00:00
|
|
|
}
|
2000-05-19 10:27:33 +00:00
|
|
|
|
2000-10-29 20:32:38 +00:00
|
|
|
gboolean
|
|
|
|
|
xaccParseAmount (const char * in_str, gboolean monetary, gnc_numeric *result,
|
|
|
|
|
char **endstr)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
struct lconv *lc = gnc_localeconv();
|
2003-07-10 03:10:08 +00:00
|
|
|
|
2006-03-02 00:24:54 +00:00
|
|
|
gunichar negative_sign;
|
|
|
|
|
gunichar decimal_point;
|
|
|
|
|
gunichar group_separator;
|
2003-07-10 03:10:08 +00:00
|
|
|
char *group;
|
|
|
|
|
|
2006-03-02 00:24:54 +00:00
|
|
|
negative_sign = g_utf8_get_char(lc->negative_sign);
|
2003-07-10 03:10:08 +00:00
|
|
|
if (monetary)
|
|
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
group_separator = g_utf8_get_char(lc->mon_thousands_sep);
|
|
|
|
|
decimal_point = g_utf8_get_char(lc->mon_decimal_point);
|
2003-07-10 03:10:08 +00:00
|
|
|
group = lc->mon_grouping;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
group_separator = g_utf8_get_char(lc->thousands_sep);
|
|
|
|
|
decimal_point = g_utf8_get_char(lc->decimal_point);
|
2003-07-10 03:10:08 +00:00
|
|
|
group = lc->grouping;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return xaccParseAmountExtended(in_str, monetary, negative_sign, decimal_point,
|
|
|
|
|
group_separator, group, NULL, result, endstr);
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-14 16:45:10 +00:00
|
|
|
/* 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.
|
|
|
|
|
*/
|
2003-07-10 03:10:08 +00:00
|
|
|
gboolean
|
|
|
|
|
xaccParseAmountExtended (const char * in_str, gboolean monetary,
|
2006-03-02 00:24:54 +00:00
|
|
|
gunichar negative_sign, gunichar decimal_point,
|
|
|
|
|
gunichar group_separator, char *group, char *ignore_list,
|
2003-07-10 03:10:08 +00:00
|
|
|
gnc_numeric *result, char **endstr)
|
|
|
|
|
{
|
2000-08-31 07:16:55 +00:00
|
|
|
gboolean is_negative;
|
|
|
|
|
gboolean got_decimal;
|
2000-10-27 20:30:30 +00:00
|
|
|
gboolean need_paren;
|
2000-11-09 06:09:04 +00:00
|
|
|
GList * group_data;
|
2001-04-15 23:07:30 +00:00
|
|
|
long long int numer;
|
|
|
|
|
long long int denom;
|
2006-03-02 00:24:54 +00:00
|
|
|
int count, group_count;
|
2000-08-31 07:16:55 +00:00
|
|
|
|
|
|
|
|
ParseState state;
|
|
|
|
|
|
2006-03-02 00:24:54 +00:00
|
|
|
const gchar *in;
|
|
|
|
|
gunichar uc;
|
|
|
|
|
gchar *out_str;
|
|
|
|
|
gchar *out;
|
2000-08-31 07:16:55 +00:00
|
|
|
|
|
|
|
|
/* Initialize *endstr to in_str */
|
|
|
|
|
if (endstr != NULL)
|
|
|
|
|
*endstr = (char *) in_str;
|
|
|
|
|
|
|
|
|
|
if (in_str == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2006-03-02 00:24:54 +00:00
|
|
|
if (!g_utf8_validate(in_str, -1, &in)) {
|
|
|
|
|
printf("Invalid utf8 string '%s'. Bad character at position %ld.\n",
|
|
|
|
|
in_str, g_utf8_pointer_to_offset (in_str, in));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* 'out_str' will be used to store digits for numeric conversion.
|
|
|
|
|
* 'out' will be used to traverse out_str. */
|
2006-03-02 00:24:54 +00:00
|
|
|
out = out_str = g_new(gchar, strlen(in_str) + 128);
|
2000-05-19 10:27:33 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* 'in' is used to traverse 'in_str'. */
|
|
|
|
|
in = in_str;
|
2000-05-19 10:27:33 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
is_negative = FALSE;
|
|
|
|
|
got_decimal = FALSE;
|
2000-10-27 20:30:30 +00:00
|
|
|
need_paren = FALSE;
|
2000-08-31 07:16:55 +00:00
|
|
|
group_data = NULL;
|
|
|
|
|
group_count = 0;
|
2000-10-29 20:32:38 +00:00
|
|
|
numer = 0;
|
|
|
|
|
denom = 1;
|
2000-05-19 10:27:33 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* Initialize the state machine */
|
|
|
|
|
state = START_ST;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* This while loop implements a state machine for parsing numbers. */
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
ParseState next_state = state;
|
2000-05-19 10:27:33 +00:00
|
|
|
|
2006-03-02 00:24:54 +00:00
|
|
|
uc = g_utf8_get_char(in);
|
|
|
|
|
|
2003-07-10 03:10:08 +00:00
|
|
|
/* Ignore anything in the 'ignore list' */
|
2006-03-02 00:24:54 +00:00
|
|
|
if (ignore_list && uc && g_utf8_strchr(ignore_list, -1, uc) != NULL) {
|
|
|
|
|
in = g_utf8_next_char(in);
|
2003-07-10 03:10:08 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-02 03:32:36 +00:00
|
|
|
/* Note we never need to check for the end of 'in_str' explicitly.
|
2000-08-31 07:16:55 +00:00
|
|
|
* 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:
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isdigit(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
count = g_unichar_to_utf8(uc, out);
|
|
|
|
|
out += count; /* we record the digits themselves in out_str
|
2000-08-31 07:16:55 +00:00
|
|
|
* for later conversion by libc routines */
|
|
|
|
|
next_state = PRE_GROUP_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == decimal_point)
|
2000-09-26 00:45:16 +00:00
|
|
|
{
|
|
|
|
|
next_state = FRAC_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (g_unichar_isspace(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == negative_sign)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
is_negative = TRUE;
|
|
|
|
|
next_state = NEG_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == '(')
|
2000-10-27 20:30:30 +00:00
|
|
|
{
|
|
|
|
|
is_negative = TRUE;
|
|
|
|
|
need_paren = TRUE;
|
|
|
|
|
next_state = NEG_ST;
|
|
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
next_state = NO_NUM_ST;
|
|
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
break;
|
2000-05-19 10:27:33 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* 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:
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isdigit(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
count = g_unichar_to_utf8(uc, out);
|
|
|
|
|
out += count;
|
2000-08-31 07:16:55 +00:00
|
|
|
next_state = PRE_GROUP_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == decimal_point)
|
2000-10-01 09:23:36 +00:00
|
|
|
{
|
|
|
|
|
next_state = FRAC_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (g_unichar_isspace(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
next_state = NO_NUM_ST;
|
|
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
break;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* 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:
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isdigit(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
count = g_unichar_to_utf8(uc, out);
|
|
|
|
|
out += count;
|
2000-08-31 07:16:55 +00:00
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == decimal_point)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
next_state = FRAC_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == group_separator)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
next_state = START_GROUP_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == ')' && need_paren)
|
2000-10-27 20:30:30 +00:00
|
|
|
{
|
|
|
|
|
next_state = DONE_ST;
|
|
|
|
|
need_paren = FALSE;
|
|
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
next_state = DONE_ST;
|
|
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
break;
|
2000-06-21 09:48:39 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* 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:
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isdigit(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
count = g_unichar_to_utf8(uc, out);
|
|
|
|
|
out += count;
|
2000-08-31 07:16:55 +00:00
|
|
|
group_count++; /* We record the number of digits
|
|
|
|
|
* in the group for later checking. */
|
|
|
|
|
next_state = IN_GROUP_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == decimal_point)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
/* 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. */
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isspace(group_separator) &&
|
|
|
|
|
g_unichar_isspace(decimal_point))
|
2000-08-31 07:16:55 +00:00
|
|
|
next_state = DONE_ST;
|
|
|
|
|
else
|
|
|
|
|
next_state = NO_NUM_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == ')' && need_paren)
|
2000-10-27 20:30:30 +00:00
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isspace(group_separator))
|
2000-10-27 20:30:30 +00:00
|
|
|
{
|
|
|
|
|
next_state = DONE_ST;
|
|
|
|
|
need_paren = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
next_state = NO_NUM_ST;
|
|
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* If the last group separator is also whitespace,
|
|
|
|
|
* assume it was intended as such and stop parsing.
|
|
|
|
|
* Otherwise, there is a problem. */
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isspace(group_separator))
|
2000-08-31 07:16:55 +00:00
|
|
|
next_state = DONE_ST;
|
|
|
|
|
else
|
|
|
|
|
next_state = NO_NUM_ST;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2000-06-21 09:48:39 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
/* IN_GROUP_ST means we are in the middle of parsing
|
|
|
|
|
* a group of digits. */
|
|
|
|
|
case IN_GROUP_ST:
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isdigit(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
count = g_unichar_to_utf8(uc, out);
|
|
|
|
|
out += count;
|
2000-08-31 07:16:55 +00:00
|
|
|
group_count++; /* We record the number of digits
|
|
|
|
|
* in the group for later checking. */
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == decimal_point)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
next_state = FRAC_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == group_separator)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
next_state = START_GROUP_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == ')' && need_paren)
|
2000-10-27 20:30:30 +00:00
|
|
|
{
|
|
|
|
|
next_state = DONE_ST;
|
|
|
|
|
need_paren = FALSE;
|
|
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
next_state = DONE_ST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* FRAC_ST means we are now parsing fractional digits. */
|
|
|
|
|
case FRAC_ST:
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isdigit(uc))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
2006-03-02 00:24:54 +00:00
|
|
|
count = g_unichar_to_utf8(uc, out);
|
|
|
|
|
out += count;
|
2000-08-31 07:16:55 +00:00
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == decimal_point)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
/* If a subsequent decimal point is also whitespace,
|
|
|
|
|
* assume it was intended as such and stop parsing.
|
|
|
|
|
* Otherwise, there is a problem. */
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isspace(decimal_point))
|
2000-08-31 07:16:55 +00:00
|
|
|
next_state = DONE_ST;
|
|
|
|
|
else
|
|
|
|
|
next_state = NO_NUM_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == group_separator)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
/* If a subsequent group separator is also whitespace,
|
|
|
|
|
* assume it was intended as such and stop parsing.
|
|
|
|
|
* Otherwise, there is a problem. */
|
2006-03-02 00:24:54 +00:00
|
|
|
if (g_unichar_isspace(group_separator))
|
2000-08-31 07:16:55 +00:00
|
|
|
next_state = DONE_ST;
|
|
|
|
|
else
|
|
|
|
|
next_state = NO_NUM_ST;
|
|
|
|
|
}
|
2006-03-02 00:24:54 +00:00
|
|
|
else if (uc == ')' && need_paren)
|
2000-10-27 20:30:30 +00:00
|
|
|
{
|
|
|
|
|
next_state = DONE_ST;
|
|
|
|
|
need_paren = FALSE;
|
|
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
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';
|
|
|
|
|
|
2006-04-14 16:45:10 +00:00
|
|
|
if (*out_str != '\0' && sscanf(out_str, QOF_SCANF_LLD, &numer) < 1)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
next_state = NO_NUM_ST;
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
else if (next_state == FRAC_ST)
|
|
|
|
|
{
|
|
|
|
|
/* reset the out pointer to record the fraction */
|
|
|
|
|
out = out_str;
|
|
|
|
|
*out = '\0';
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
got_decimal = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state = next_state;
|
|
|
|
|
if (done_state (state))
|
|
|
|
|
break;
|
|
|
|
|
|
2006-03-02 00:24:54 +00:00
|
|
|
in = g_utf8_next_char(in);
|
2000-08-31 07:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there was an error, just quit */
|
2000-10-27 20:30:30 +00:00
|
|
|
if (need_paren || (state == NO_NUM_ST))
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
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. */
|
2003-07-10 03:10:08 +00:00
|
|
|
for (node = group_data; group && node; node = node->next)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
/* 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';
|
|
|
|
|
|
|
|
|
|
/* Add in fractional value */
|
|
|
|
|
if (got_decimal && (*out_str != '\0'))
|
|
|
|
|
{
|
|
|
|
|
size_t len;
|
2001-04-15 23:07:30 +00:00
|
|
|
long long int fraction;
|
2000-08-31 07:16:55 +00:00
|
|
|
|
|
|
|
|
len = strlen(out_str);
|
|
|
|
|
|
|
|
|
|
if (len > 8)
|
|
|
|
|
{
|
|
|
|
|
out_str[8] = '\0';
|
|
|
|
|
len = 8;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-14 16:45:10 +00:00
|
|
|
if (sscanf (out_str, QOF_SCANF_LLD, &fraction) < 1)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
g_free(out_str);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2000-10-29 20:32:38 +00:00
|
|
|
|
|
|
|
|
denom = multiplier(len);
|
|
|
|
|
numer *= denom;
|
|
|
|
|
numer += fraction;
|
2000-08-31 07:16:55 +00:00
|
|
|
}
|
2002-07-03 05:59:51 +00:00
|
|
|
else if (monetary && auto_decimal_enabled && !got_decimal)
|
2000-08-31 07:16:55 +00:00
|
|
|
{
|
|
|
|
|
if ((auto_decimal_places > 0) && (auto_decimal_places < 9))
|
2000-10-29 20:32:38 +00:00
|
|
|
{
|
|
|
|
|
denom = multiplier(auto_decimal_places);
|
2001-01-23 20:34:42 +00:00
|
|
|
|
|
|
|
|
/* No need to multiply numer by denom at this point,
|
|
|
|
|
* since by specifying the auto decimal places the
|
|
|
|
|
* user has effectively determined the scaling factor
|
|
|
|
|
* for the numerator they entered.
|
|
|
|
|
*/
|
2000-10-29 20:32:38 +00:00
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result != NULL)
|
2000-10-29 20:32:38 +00:00
|
|
|
{
|
2000-10-30 10:46:46 +00:00
|
|
|
*result = gnc_numeric_create (numer, denom);
|
|
|
|
|
if (is_negative)
|
|
|
|
|
*result = gnc_numeric_neg (*result);
|
2000-10-29 20:32:38 +00:00
|
|
|
}
|
2000-08-31 07:16:55 +00:00
|
|
|
|
|
|
|
|
if (endstr != NULL)
|
|
|
|
|
*endstr = (char *) in;
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
g_free (out_str);
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-08-31 07:16:55 +00:00
|
|
|
return TRUE;
|
2000-01-17 21:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
/* enable/disable the auto_decimal_enabled option */
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_set_auto_decimal_enabled (GConfEntry *entry, gpointer user_data)
|
2000-11-01 08:52:30 +00:00
|
|
|
{
|
2005-11-02 03:32:36 +00:00
|
|
|
GConfValue *value;
|
|
|
|
|
|
|
|
|
|
value = gconf_entry_get_value(entry);
|
|
|
|
|
auto_decimal_enabled = gconf_value_get_bool(value);
|
2000-11-01 08:52:30 +00:00
|
|
|
}
|
2000-01-17 21:39:42 +00:00
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
/* set the number of auto decimal places to use */
|
2005-11-02 03:32:36 +00:00
|
|
|
static void
|
|
|
|
|
gnc_set_auto_decimal_places (GConfEntry *entry, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
GConfValue *value;
|
|
|
|
|
|
|
|
|
|
value = gconf_entry_get_value(entry);
|
|
|
|
|
auto_decimal_places = gconf_value_get_float(value);
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-15 03:54:53 +00:00
|
|
|
static void
|
|
|
|
|
gnc_auto_decimal_init (void)
|
|
|
|
|
{
|
|
|
|
|
auto_decimal_enabled =
|
|
|
|
|
gnc_gconf_get_bool(GCONF_GENERAL, "auto_decimal_point", NULL);
|
|
|
|
|
auto_decimal_places =
|
|
|
|
|
gnc_gconf_get_float(GCONF_GENERAL, "auto_decimal_places", NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
void
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_ui_util_init (void)
|
2000-11-01 08:52:30 +00:00
|
|
|
{
|
2006-03-02 07:20:33 +00:00
|
|
|
gnc_configure_account_separator ();
|
2006-06-15 03:54:53 +00:00
|
|
|
gnc_auto_decimal_init();
|
|
|
|
|
|
2006-03-02 07:20:33 +00:00
|
|
|
gnc_gconf_general_register_cb(KEY_ACCOUNT_SEPARATOR,
|
|
|
|
|
(GncGconfGeneralCb)gnc_configure_account_separator,
|
|
|
|
|
NULL);
|
|
|
|
|
gnc_gconf_general_register_cb(KEY_REVERSED_ACCOUNTS,
|
2005-11-02 03:32:36 +00:00
|
|
|
(GncGconfGeneralCb)gnc_configure_reverse_balance,
|
|
|
|
|
NULL);
|
2006-03-08 05:14:54 +00:00
|
|
|
gnc_gconf_general_register_cb(KEY_CURRENCY_CHOICE,
|
|
|
|
|
gnc_currency_changed_cb, NULL);
|
|
|
|
|
gnc_gconf_general_register_cb(KEY_CURRENCY_OTHER,
|
|
|
|
|
gnc_currency_changed_cb, NULL);
|
2005-11-02 03:32:36 +00:00
|
|
|
gnc_gconf_general_register_cb("auto_decimal_point",
|
|
|
|
|
gnc_set_auto_decimal_enabled,
|
|
|
|
|
NULL);
|
|
|
|
|
gnc_gconf_general_register_cb("auto_decimal_places",
|
|
|
|
|
gnc_set_auto_decimal_places,
|
|
|
|
|
NULL);
|
|
|
|
|
|
2000-11-01 08:52:30 +00:00
|
|
|
}
|
2001-04-12 23:03:42 +00:00
|
|
|
|
2001-07-01 21:09:09 +00:00
|
|
|
/* These implementations are rather lame. */
|
|
|
|
|
#ifndef HAVE_TOWUPPER
|
|
|
|
|
gint32
|
|
|
|
|
towupper (gint32 wc)
|
|
|
|
|
{
|
|
|
|
|
if (wc > 127)
|
|
|
|
|
return wc;
|
|
|
|
|
|
|
|
|
|
return toupper ((int) wc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
iswlower (gint32 wc)
|
|
|
|
|
{
|
|
|
|
|
if (wc > 127)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return islower ((int) wc);
|
|
|
|
|
}
|
|
|
|
|
#endif
|