GnuCash  4.11-11-ge9df8d41d2+
gnc-ui-util.c
1 /********************************************************************\
2  * gnc-ui-util.c -- utility functions for the GnuCash UI *
3  * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA gnu@gnu.org *
21 \********************************************************************/
22 
23 #include <config.h>
24 
25 #ifdef __MINGW32__
26 #define __USE_MINGW_ANSI_STDIO 1
27 #endif
28 #include "gnc-ui-util.h"
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include <gio/gio.h>
32 #include <libguile.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <locale.h>
37 #include <math.h>
38 #if defined(G_OS_WIN32) && !defined(_MSC_VER)
39 # include <pow.h>
40 #endif
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 
46 
47 #include "qof.h"
48 #include "guile-mappings.h"
49 #include "gnc-prefs.h"
50 #include "Account.h"
51 #include "Transaction.h"
52 #include "gnc-engine.h"
53 #include "gnc-features.h"
54 #include "gnc-hooks.h"
55 #include "gnc-locale-tax.h"
56 #include "gnc-session.h"
57 #include "engine-helpers.h"
58 #include "gnc-locale-utils.h"
59 #include "gnc-guile-utils.h"
60 
61 #define GNC_PREF_CURRENCY_CHOICE_LOCALE "currency-choice-locale"
62 #define GNC_PREF_CURRENCY_CHOICE_OTHER "currency-choice-other"
63 #define GNC_PREF_CURRENCY_OTHER "currency-other"
64 #define GNC_PREF_REVERSED_ACCTS_NONE "reversed-accounts-none"
65 #define GNC_PREF_REVERSED_ACCTS_CREDIT "reversed-accounts-credit"
66 #define GNC_PREF_REVERSED_ACCTS_INC_EXP "reversed-accounts-incomeexpense"
67 #define GNC_PREF_PRICES_FORCE_DECIMAL "force-price-decimal"
68 
69 static QofLogModule log_module = GNC_MOD_GUI;
70 
71 static gboolean auto_decimal_enabled = FALSE;
72 static int auto_decimal_places = 2; /* default, can be changed */
73 
74 static gboolean reverse_balance_inited = FALSE;
75 static gboolean reverse_type[NUM_ACCOUNT_TYPES];
76 
77 /* Cache currency ISO codes and only look them up in the settings when
78  * absolutely necessary. Can't cache a pointer to the data structure
79  * as that will change any time the book changes. */
80 static gchar *user_default_currency = NULL;
81 static gchar *user_report_currency = NULL;
82 const static int maximum_decimals = 15;
83 static const gint64 pow_10[] = {1, 10, 100, 1000, 10000, 100000, 1000000,
84  10000000, 100000000, 1000000000, 10000000000,
85  100000000000, 1000000000000, 10000000000000,
86  100000000000000, 1000000000000000};
87 
88 gchar *gnc_normalize_account_separator (const gchar* separator)
89 {
90  gchar *new_sep=NULL;
91 
92  if (!separator || !*separator || g_strcmp0(separator, "colon") == 0)
93  new_sep = g_strdup (":");
94  else if (g_strcmp0(separator, "slash") == 0)
95  new_sep = g_strdup ("/");
96  else if (g_strcmp0(separator, "backslash") == 0)
97  new_sep = g_strdup ("\\");
98  else if (g_strcmp0(separator, "dash") == 0)
99  new_sep = g_strdup ("-");
100  else if (g_strcmp0(separator, "period") == 0)
101  new_sep = g_strdup (".");
102  else
103  new_sep = g_strdup (separator);
104 
105  return new_sep;
106 }
107 /********************************************************************\
108  * gnc_configure_account_separator *
109  * updates the current account separator character *
110  * *
111  * Args: none *
112  \*******************************************************************/
113 static void
114 gnc_configure_account_separator (void)
115 {
116  gchar *separator;
117  char *string;
118 
119  string = gnc_prefs_get_string(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNT_SEPARATOR);
120  separator = gnc_normalize_account_separator (string);
121 
122  gnc_set_account_separator(separator);
123 
124  g_free(string);
125  g_free(separator);
126 }
127 
128 
129 static void
130 gnc_configure_reverse_balance (void)
131 {
132  gint i;
133 
134  for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
135  reverse_type[i] = FALSE;
136 
137  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_INC_EXP))
138  {
139  reverse_type[ACCT_TYPE_INCOME] = TRUE;
140  reverse_type[ACCT_TYPE_EXPENSE] = TRUE;
141  }
142  else if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_CREDIT))
143  {
144  reverse_type[ACCT_TYPE_LIABILITY] = TRUE;
145  reverse_type[ACCT_TYPE_PAYABLE] = TRUE;
146  reverse_type[ACCT_TYPE_EQUITY] = TRUE;
147  reverse_type[ACCT_TYPE_INCOME] = TRUE;
148  reverse_type[ACCT_TYPE_CREDIT] = TRUE;
149  }
150  else if (!gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_NONE))
151  PWARN("no reversed account preference set, using none");
152 
153 }
154 
155 static void
156 gnc_reverse_balance_init (void)
157 {
158  gnc_configure_reverse_balance ();
159  reverse_balance_inited = TRUE;
160 }
161 
162 gboolean
163 gnc_reverse_balance (const Account *account)
164 {
165  int type;
166 
167  if (account == NULL)
168  return FALSE;
169 
170  type = xaccAccountGetType (account);
171  if ((type < 0) || (type >= NUM_ACCOUNT_TYPES))
172  return FALSE;
173 
174  if (!reverse_balance_inited)
175  gnc_reverse_balance_init ();
176 
177  return reverse_type[type];
178 }
179 
180 gboolean gnc_using_unreversed_budgets (QofBook* book)
181 {
182  return gnc_features_check_used (book, GNC_FEATURE_BUDGET_UNREVERSED);
183 }
184 
185 /* similar to gnc_reverse_balance but also accepts a gboolean
186  unreversed which specifies the reversal strategy - FALSE = pre-4.x
187  always-assume-credit-accounts, TRUE = all amounts unreversed */
188 gboolean
189 gnc_reverse_budget_balance (const Account *account, gboolean unreversed)
190 {
191  if (unreversed == gnc_using_unreversed_budgets(gnc_account_get_book(account)))
192  return gnc_reverse_balance (account);
193 
194  return FALSE;
195 }
196 
197 gboolean gnc_using_equity_type_opening_balance_account (QofBook* book)
198 {
199  return gnc_features_check_used (book, GNC_FEATURE_EQUITY_TYPE_OPENING_BALANCE);
200 }
201 
202 void gnc_set_use_equity_type_opening_balance_account (QofBook* book)
203 {
204  gnc_features_set_used (book, GNC_FEATURE_EQUITY_TYPE_OPENING_BALANCE);
205 }
206 
207 gchar *
208 gnc_get_default_directory (const gchar *section)
209 {
210  gchar *dir;
211 
212  dir = gnc_prefs_get_string (section, GNC_PREF_LAST_PATH);
213  if (!(dir && *dir))
214  {
215  g_free (dir); // if it's ""
216 #ifdef G_OS_WIN32
217  dir = g_strdup (g_get_user_data_dir ()); /* equivalent of "My Documents" */
218 #else
219  dir = g_strdup (g_get_home_dir ());
220 #endif
221  }
222  return dir;
223 }
224 
225 void
226 gnc_set_default_directory (const gchar *section, const gchar *directory)
227 {
228  gnc_prefs_set_string(section, GNC_PREF_LAST_PATH, directory);
229 }
230 
231 QofBook *
232 gnc_get_current_book (void)
233 {
234  return qof_session_get_book (gnc_get_current_session ());
235 }
236 
237 /* If there is no current session, there is no book and we must be dealing
238  * with a new book. When gnucash is started with --nofile, there is
239  * initially no session (and no book), but by the time we check, one
240  * could have been created (for example, if an empty account tree tab is
241  * opened, a session is created which creates a new, but empty, book).
242  * A session is created and a book is loaded from a backend when gnucash is
243  * started with a file, but selecting 'new file' keeps a session open. So we
244  * need to check as well for a book with no accounts (root with no children). */
245 gboolean
246 gnc_is_new_book (void)
247 {
248  return ((!gnc_current_session_exist() ||
249  (gnc_current_session_exist() &&
251  gnc_book_get_root_account(
252  gnc_get_current_book()))))
253  ? TRUE : FALSE);
254 }
255 
256 #define OPTION_TAXUS_NAME "tax_US/name"
257 #define OPTION_TAXUS_TYPE "tax_US/type"
258 #define OLD_OPTION_TAXUS_NAME "book/tax_US/name"
259 #define OLD_OPTION_TAXUS_TYPE "book/tax_US/type"
260 
261 void
262 gnc_set_current_book_tax_name_type (gboolean name_changed, const gchar *tax_name,
263  gboolean type_changed, const gchar *tax_type)
264 {
265  if (name_changed)
266  {
267  if (type_changed)
268  {
269  QofBook* book = gnc_get_current_book();
270  if ((g_strcmp0 (tax_name, "") == 0) ||
271  (tax_name == NULL))
272  { /* change to no name */
273  if ((g_strcmp0 (tax_type, "Other") == 0) ||
274  (g_strcmp0 (tax_type, "") == 0) ||
275  (tax_type == NULL))
276  { /* need to delete both name and type and the "tax_US" frame */
277  qof_book_set_string_option(book, OPTION_TAXUS_NAME, NULL);
278  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, NULL);
279  qof_book_option_frame_delete(book, "tax_US");
280  }
281  else
282  { /* delete the name & change the type; keep the "tax_US" frame */
283  qof_book_set_string_option(book, OPTION_TAXUS_NAME, NULL);
284  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, tax_type);
285  }
286  }
287  else /* new name */
288  {
289  if ((g_strcmp0 (tax_type, "Other") == 0) ||
290  (g_strcmp0 (tax_type, "") == 0) ||
291  (tax_type == NULL))
292  { /* delete the type & change the name; keep the "tax_US" frame */
293  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, NULL);
294  qof_book_set_string_option(book, OPTION_TAXUS_NAME, tax_name);
295  }
296  else /* and new type */
297  { /* change the name & change the type */
298  qof_book_set_string_option(book, OPTION_TAXUS_NAME, tax_name);
299  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, tax_type);
300  }
301  }
302  }
303  else /* no type change but name changed */
304  {
305  QofBook* book = gnc_get_current_book();
306  if ((g_strcmp0 (tax_name, "") == 0) ||
307  (tax_name == NULL))
308  { /* change to no name */
309  if ((g_strcmp0 (tax_type, "Other") == 0) ||
310  (g_strcmp0 (tax_type, "") == 0) ||
311  (tax_type == NULL))
312  { /* delete the name; there is no type; deleted the "tax_US" frame */
313  qof_book_set_string_option(book, OPTION_TAXUS_NAME, NULL);
314  qof_book_option_frame_delete(book, "tax_US");
315  }
316  else
317  { /* need to delete the name and keep "tax_US" frame */
318  qof_book_set_string_option(book, OPTION_TAXUS_NAME, NULL);
319  }
320  }
321  else
322  { /* change the name & keep "tax_US" frame */
323  qof_book_set_string_option(book, OPTION_TAXUS_NAME, tax_name);
324  }
325  }
326  }
327  else /* no name change */
328  {
329  if (type_changed)
330  {
331  QofBook* book = gnc_get_current_book();
332  if ((g_strcmp0 (tax_type, "Other") == 0) ||
333  (g_strcmp0 (tax_type, "") == 0) ||
334  (tax_type == NULL))
335  {
336  if ((g_strcmp0 (tax_name, "") == 0) ||
337  (tax_name == NULL))
338  {/* delete the type; there is no name; delete the "tax_US" frame */
339  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, NULL);
340  qof_book_option_frame_delete(book, "tax_US");
341  }
342  else
343  { /* need to delete the type and keep "tax_US" frame */
344  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, NULL);
345  }
346  }
347  else
348  { /* change the type & keep "tax_US" frame */
349  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, tax_type);
350  }
351  } /*else no name and no type change - do nothing */
352  }
353 }
354 
355 const gchar *
356 gnc_get_current_book_tax_name (void)
357 {
358  QofBook* book = gnc_get_current_book();
359  const char* tax_name =
360  qof_book_get_string_option(book, OPTION_TAXUS_NAME);
361  if (tax_name)
362  {
363  return tax_name;
364  }
365  else
366  {
367  const char* old_option_taxus_name =
368  qof_book_get_string_option(book, OLD_OPTION_TAXUS_NAME);
369  if (old_option_taxus_name)
370  {
371  char* taxus_name = g_strdup(old_option_taxus_name);
372  const char* old_option_taxus_type =
373  qof_book_get_string_option(book, OLD_OPTION_TAXUS_TYPE);
374  if (old_option_taxus_type)
375  { /* switch both name and type and remove unused frames */
376  char* taxus_type = g_strdup(old_option_taxus_type);
377  qof_book_set_string_option(book, OPTION_TAXUS_NAME, taxus_name);
378  qof_book_set_string_option(book, OLD_OPTION_TAXUS_NAME, NULL);
379  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, taxus_type);
380  qof_book_set_string_option(book, OLD_OPTION_TAXUS_TYPE, NULL);
381  qof_book_option_frame_delete(book, "book/tax_US");
382  qof_book_option_frame_delete(book, "book");
383  g_free (taxus_type);
384  }
385  else
386  { /* switch just name and remove unused frames */
387  qof_book_set_string_option(book, OPTION_TAXUS_NAME, taxus_name);
388  qof_book_set_string_option(book, OLD_OPTION_TAXUS_NAME, NULL);
389  qof_book_option_frame_delete(book, "book/tax_US");
390  qof_book_option_frame_delete(book, "book");
391  }
392  g_free (taxus_name);
393  return qof_book_get_string_option(book, OPTION_TAXUS_NAME);
394  }
395  return NULL;
396  }
397 }
398 
399 const gchar *
400 gnc_get_current_book_tax_type (void)
401 {
402  QofBook* book = gnc_get_current_book();
403  const char* tax_type =
404  qof_book_get_string_option(book, OPTION_TAXUS_TYPE);
405  if (tax_type)
406  {
407  return tax_type;
408  }
409  else
410  {
411  const char* old_option_taxus_type =
412  qof_book_get_string_option(book, OLD_OPTION_TAXUS_TYPE);
413  if (old_option_taxus_type)
414  {
415  char* taxus_type = g_strdup(old_option_taxus_type);
416  const char* old_option_taxus_name =
417  qof_book_get_string_option(book, OLD_OPTION_TAXUS_NAME);
418  if (old_option_taxus_name)
419  { /* switch both name and type and remove unused frames */
420  char* taxus_name = g_strdup(old_option_taxus_name);
421  qof_book_set_string_option(book, OPTION_TAXUS_NAME, taxus_name);
422  qof_book_set_string_option(book, OLD_OPTION_TAXUS_NAME, NULL);
423  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, taxus_type);
424  qof_book_set_string_option(book, OLD_OPTION_TAXUS_TYPE, NULL);
425  qof_book_option_frame_delete(book, "book/tax_US");
426  qof_book_option_frame_delete(book, "book");
427  g_free (taxus_name);
428  }
429  else
430  { /* switch just type and remove unused frames */
431  qof_book_set_string_option(book, OPTION_TAXUS_TYPE, taxus_type);
432  qof_book_set_string_option(book, OLD_OPTION_TAXUS_TYPE, NULL);
433  qof_book_option_frame_delete(book, "book/tax_US");
434  qof_book_option_frame_delete(book, "book");
435  }
436  g_free (taxus_type);
437  return qof_book_get_string_option(book, OPTION_TAXUS_TYPE);
438  }
439  return NULL;
440  }
441 }
442 
445 gboolean
447 {
448  const gchar *policy;
449  const gchar *currency;
450 
451  if (!book) return FALSE;
452 
453  policy = qof_book_get_default_gains_policy (book);
454  currency = qof_book_get_book_currency_name (book);
455 
456  /* If either a default gain/loss policy or a book-currency does not exist,
457  book-currency accounting method not valid */
458  if (!policy || !currency)
459  return FALSE;
460 
461  /* If both exist, both must be valid */
462  if (!gnc_valid_policy_name (policy) || !gnc_commodity_table_lookup
464  (gnc_get_current_book()),
465  GNC_COMMODITY_NS_CURRENCY,
466  currency))
467  return FALSE;
468 
469  /* If both exist and are valid, there must be no trading accounts flag */
471  return FALSE;
472 
473  return TRUE;
474 }
475 
480 const gchar *
482 {
483  if (!book) return NULL;
484 
485  if (gnc_book_use_book_currency (book))
486  return qof_book_get_book_currency_name (book);
487 
488  return NULL;
489 }
490 
495 gnc_commodity *
497 {
498  if (!book) return NULL;
499 
500  if (gnc_book_use_book_currency (book))
501  return gnc_commodity_table_lookup
503  GNC_COMMODITY_NS_CURRENCY,
505 
506  return NULL;
507 }
508 
513 const gchar *
515 {
516  if (!book) return NULL;
517 
518  if (gnc_book_use_book_currency (book))
519  return qof_book_get_default_gains_policy (book);
520 
521  return NULL;
522 }
523 
529 Account *
531 {
532  Account *gains_account = NULL;
533 
534  if (!book) return NULL;
535 
536  if (gnc_book_use_book_currency (book))
537  {
539  gains_account = xaccAccountLookup (guid, book);
540  guid_free (guid);
541  }
542 
543  if (gains_account &&
544  !xaccAccountGetPlaceholder(gains_account) &&
545  !xaccAccountGetHidden(gains_account) &&
547  gnc_book_get_book_currency(book))) &&
548  ((xaccAccountGetType(gains_account) == ACCT_TYPE_INCOME) ||
549  (xaccAccountGetType(gains_account) == ACCT_TYPE_EXPENSE)))
550  {
551  return gains_account;
552  }
553  else
554  {
555  return NULL;
556  }
557 }
558 
559 Account *
560 gnc_get_current_root_account (void)
561 {
562  return gnc_book_get_root_account (gnc_get_current_book ());
563 }
564 
565 gnc_commodity_table *
566 gnc_get_current_commodities (void)
567 {
568  return gnc_commodity_table_get_table (gnc_get_current_book ());
569 }
570 
571 gchar *
572 gnc_get_account_name_for_split_register(const Account *account, gboolean show_leaf_accounts)
573 {
574  if (show_leaf_accounts)
575  return g_strdup (xaccAccountGetName (account));
576  else
577  return gnc_account_get_full_name (account);
578 }
579 
580 gchar *
582 {
583  gboolean show_leaf_accounts;
584  show_leaf_accounts = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL_REGISTER,
585  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
586 
587  return gnc_get_account_name_for_split_register(account, show_leaf_accounts);
588 }
589 
590 Account *
591 gnc_account_lookup_for_register(const Account *base_account, const char *name)
592 {
593  gboolean show_leaf_accounts;
594  show_leaf_accounts = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL_REGISTER,
595  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
596 
597  if (show_leaf_accounts)
598  return gnc_account_lookup_by_name (base_account, name);
599  else
600  return gnc_account_lookup_by_full_name (base_account, name);
601 }
602 
603 
604 /* Caller is responsible for g_free'ing returned memory */
605 char *
606 gnc_ui_account_get_tax_info_string (const Account *account)
607 {
608  static SCM get_form = SCM_UNDEFINED;
609  static SCM get_desc = SCM_UNDEFINED;
610 
611  gboolean tax_related = FALSE;
612  const char *code;
613 
614  if (!account)
615  return NULL;
616 
617  tax_related = xaccAccountGetTaxRelated (account);
618  code = xaccAccountGetTaxUSCode (account);
619 
620  if (!code)
621  {
622  if (!tax_related)
623  return NULL;
624  /* tax_related && !code */
625  else
626  /* Translators: This and the following strings appear on
627  the account tab if the Tax Info column is displayed,
628  i.e. if the user wants to record the tax form number
629  and location on that tax form which corresponds to this
630  gnucash account. For the US Income Tax support in
631  gnucash, each tax code that can be assigned to an
632  account generally corresponds to a specific line number
633  on a paper form and each form has a unique
634  identification (e.g., Form 1040, Schedule A). */
635  return g_strdup (_("Tax-related but has no tax code"));
636  }
637  else /* with tax code */
638  {
639  const gchar *tax_type;
640  GNCAccountType atype;
641  SCM tax_entity_type;
642  SCM category;
643  gchar *num_code = NULL;
644  const gchar *prefix = "N";
645  gchar *return_string = NULL;
646 
647  tax_type = gnc_get_current_book_tax_type ();
648  if (tax_type == NULL || (g_strcmp0 (tax_type, "") == 0))
649  return g_strdup (_("Tax entity type not specified"));
650 
651  atype = xaccAccountGetType (account);
652  tax_entity_type = scm_from_utf8_string (tax_type);
653 
654  if (get_form == SCM_UNDEFINED)
655  {
656  const gchar *tax_module;
657  /* load the tax info */
658  gnc_locale_tax_init ();
659 
660  get_form = scm_c_eval_string
661  ("(false-if-exception gnc:txf-get-form)");
662  get_desc = scm_c_eval_string
663  ("(false-if-exception gnc:txf-get-description)");
664  }
665 
666  g_return_val_if_fail (scm_is_procedure (get_form), NULL);
667  g_return_val_if_fail (scm_is_procedure (get_desc), NULL);
668 
669  category = scm_c_eval_string (atype == ACCT_TYPE_INCOME ?
670  "txf-income-categories" :
671  (atype == ACCT_TYPE_EXPENSE ?
672  "txf-expense-categories" :
673  (((atype == ACCT_TYPE_BANK) ||
674  (atype == ACCT_TYPE_CASH) ||
675  (atype == ACCT_TYPE_ASSET) ||
676  (atype == ACCT_TYPE_STOCK) ||
677  (atype == ACCT_TYPE_MUTUAL) ||
678  (atype == ACCT_TYPE_RECEIVABLE)) ?
679  "txf-asset-categories" :
680  (((atype == ACCT_TYPE_CREDIT) ||
681  (atype == ACCT_TYPE_LIABILITY) ||
682  (atype == ACCT_TYPE_EQUITY) ||
683  (atype == ACCT_TYPE_PAYABLE)) ?
684  "txf-liab-eq-categories" : ""))));
685 
686  if (g_str_has_prefix (code, prefix))
687  {
688  const gchar *num_code_tmp;
689  num_code_tmp = g_strdup (code);
690  num_code_tmp++; /* to lose the leading N */
691  num_code = g_strdup (num_code_tmp);
692  num_code_tmp--;
693  g_free ((gpointer *) num_code_tmp);
694  }
695  else
696  {
697  num_code = g_strdup (code);
698  }
699 
700  if (category == SCM_UNDEFINED)
701  {
702  if (tax_related)
703  return_string = g_strdup_printf
704  (_("Tax type %s: invalid code %s for account type"),
705  tax_type, num_code);
706  else
707  return_string = g_strdup_printf
708  (_("Not tax-related; tax type %s: invalid code %s for account type"),
709  tax_type, num_code);
710  }
711  else
712  {
713  SCM code_scm;
714  SCM form_scm;
715  code_scm = scm_from_locale_symbol (code);
716  form_scm = scm_call_3 (get_form, category, code_scm, tax_entity_type);
717  if (!scm_is_string (form_scm))
718  {
719  if (tax_related)
720  return_string = g_strdup_printf
721  (_("Invalid code %s for tax type %s"),
722  num_code, tax_type);
723  else
724  return_string = g_strdup_printf
725  (_("Not tax-related; invalid code %s for tax type %s"),
726  num_code, tax_type);
727  }
728  else
729  {
730  gchar *form = NULL;
731 
732  /* Note: using scm_to_utf8_stringn directly here instead
733  of our wrapper gnc_scm_to_utf8_string. 'form' should
734  be freed with 'free' instead of 'g_free'. This will
735  be taken care of automatically during scm_dynwind_end,
736  because we inform guile of this memory allocation via
737  scm_dynwind_free a little further. */
738  form = scm_to_utf8_stringn (form_scm, NULL);
739  if (!form)
740  {
741  if (tax_related)
742  return_string = g_strdup_printf
743  (_("No form: code %s, tax type %s"), num_code,
744  tax_type);
745  else
746  return_string = g_strdup_printf
747  (_("Not tax-related; no form: code %s, tax type %s"),
748  num_code, tax_type);
749  }
750  else
751  {
752  SCM desc_scm;
753 
754  /* Create a dynwind context because we will be calling (scm) functions
755  that potentially exit non-locally */
756  scm_dynwind_begin (0);
757  scm_dynwind_free (form);
758  desc_scm = scm_call_3 (get_desc, category, code_scm,
759  tax_entity_type);
760  if (!scm_is_string (desc_scm))
761  {
762  if (tax_related)
763  return_string = g_strdup_printf
764  (_("No description: form %s, code %s, tax type %s"),
765  form, num_code, tax_type);
766  else
767  return_string = g_strdup_printf
768  (_("Not tax-related; no description: form %s, code %s, tax type %s"),
769  form, num_code, tax_type);
770  }
771  else
772  {
773  gchar *desc = NULL;
774  desc = gnc_scm_to_utf8_string (desc_scm);
775  if (!desc)
776  {
777  if (tax_related)
778  return_string = g_strdup_printf
779  (_("No description: form %s, code %s, tax type %s"),
780  form, num_code, tax_type);
781  else
782  return_string = g_strdup_printf
783  (_("Not tax-related; no description: form %s, code %s, tax type %s"),
784  form, num_code, tax_type);
785  }
786  else
787  {
788  gint64 copy_number;
789  gchar *copy_txt = NULL;
790  copy_number = xaccAccountGetTaxUSCopyNumber (account);
791  copy_txt = (copy_number == 1) ?
792  g_strdup ("") :
793  g_strdup_printf ("(%d)",
794  (gint) copy_number);
795  if (tax_related)
796  {
797  if (g_strcmp0 (form, "") == 0)
798  return_string = g_strdup_printf ("%s", desc);
799  else
800  return_string = g_strdup_printf ("%s%s: %s",
801  form, copy_txt, desc);
802  }
803  else
804  {
805  return_string = g_strdup_printf
806  (_("Not tax-related; %s%s: %s (code %s, tax type %s)"),
807  form, copy_txt, desc, num_code, tax_type);
808  }
809  g_free (copy_txt);
810  }
811  g_free (desc);
812  }
813  scm_dynwind_end ();
814  }
815  }
816  }
817  g_free (num_code);
818  return return_string;
819  }
820 }
821 
822 /* Caller is responsible for g_free'ing returned memory */
823 char *
824 gnc_ui_account_get_tax_info_sub_acct_string (const Account *account)
825 {
826  GList *descendant, *account_descendants;
827 
828  if (!account)
829  return NULL;
830 
831  account_descendants = gnc_account_get_descendants (account);
832  if (account_descendants)
833  {
834  gint sub_acct_tax_number = 0;
835  for (descendant = account_descendants; descendant;
836  descendant = g_list_next(descendant))
837  {
838  if (xaccAccountGetTaxRelated (descendant->data))
839  sub_acct_tax_number++;
840  }
841  g_list_free (account_descendants);
842  g_list_free (descendant);
843  /* Translators: This and the following strings appear on
844  the account tab if the Tax Info column is displayed,
845  i.e. if the user wants to record the tax form number
846  and location on that tax form which corresponds to this
847  gnucash account. For the US Income Tax support in
848  gnucash, each tax code that can be assigned to an
849  account generally corresponds to a specific line number
850  on a paper form and each form has a unique
851  identification (e.g., Form 1040, Schedule A). */
852  return (sub_acct_tax_number == 0) ? NULL :
853  g_strdup_printf (_("(Tax-related subaccounts: %d)"),
854  sub_acct_tax_number);
855  }
856  else
857  return NULL;
858 }
859 
860 /********************************************************************\
861  * gnc_get_reconcile_str *
862  * return the i18n'd string for the given reconciled flag *
863  * *
864  * Args: reconciled_flag - the flag to convert into a string *
865  * Returns: the i18n'd reconciled string *
866 \********************************************************************/
867 const char *
868 gnc_get_reconcile_str (char reconciled_flag)
869 {
870  switch (reconciled_flag)
871  {
872  case NREC:
873  return C_("Reconciled flag 'not cleared'", "n");
874  case CREC:
875  return C_("Reconciled flag 'cleared'", "c");
876  case YREC:
877  return C_("Reconciled flag 'reconciled'", "y");
878  case FREC:
879  return C_("Reconciled flag 'frozen'", "f");
880  case VREC:
881  return C_("Reconciled flag 'void'", "v");
882  default:
883  PERR("Bad reconciled flag\n");
884  return NULL;
885  }
886 }
887 
888 /********************************************************************\
889  * gnc_get_reconcile_valid_flags *
890  * return a string containing the list of reconciled flags *
891  * *
892  * Returns: the i18n'd reconciled flags string *
893 \********************************************************************/
894 const char *
895 gnc_get_reconcile_valid_flags (void)
896 {
897  static const char flags[] = { NREC, CREC, YREC, FREC, VREC, 0 };
898  return flags;
899 }
900 
901 /********************************************************************\
902  * gnc_get_reconcile_flag_order *
903  * return a string containing the reconciled-flag change order *
904  * *
905  * Args: reconciled_flag - the flag to convert into a string *
906  * Returns: the i18n'd reconciled string *
907 \********************************************************************/
908 const char *
909 gnc_get_reconcile_flag_order (void)
910 {
911  static const char flags[] = { NREC, CREC, 0 };
912  return flags;
913 }
914 
915 const char *
916 gnc_get_doclink_str (char link_flag)
917 {
918  switch (link_flag)
919  {
920  case WLINK:
921  return C_("Document Link flag for 'web'", "w");
922  case FLINK:
923  return C_("Document Link flag for 'file'", "f");
924  case ' ':
925  return " ";
926  default:
927  PERR("Bad link flag");
928  return NULL;
929  }
930 }
931 
932 const char *
934 {
935  static const char flags[] = { FLINK, WLINK, ' ', 0 };
936  return flags;
937 }
938 
939 const char *
941 {
942  static const char flags[] = { FLINK, WLINK, ' ', 0 };
943  return flags;
944 }
945 
946 static const char *
947 equity_base_name (GNCEquityType equity_type)
948 {
949  switch (equity_type)
950  {
951  case EQUITY_OPENING_BALANCE:
952  return N_("Opening Balances");
953 
954  case EQUITY_RETAINED_EARNINGS:
955  return N_("Retained Earnings");
956 
957  default:
958  return NULL;
959  }
960 }
961 
962 Account *
963 gnc_find_or_create_equity_account (Account *root,
964  GNCEquityType equity_type,
965  gnc_commodity *currency)
966 {
967  Account *parent;
968  Account *account = NULL;
969  gboolean name_exists;
970  gboolean base_name_exists;
971  const char *base_name;
972  char *name;
973  gboolean use_eq_op_feature;
974 
975  g_return_val_if_fail (equity_type >= 0, NULL);
976  g_return_val_if_fail (equity_type < NUM_EQUITY_TYPES, NULL);
977  g_return_val_if_fail (currency != NULL, NULL);
978  g_return_val_if_fail (root != NULL, NULL);
979  g_return_val_if_fail (gnc_commodity_is_currency(currency), NULL);
980 
981  use_eq_op_feature = equity_type == EQUITY_OPENING_BALANCE && gnc_using_equity_type_opening_balance_account (gnc_get_current_book ());
982 
983  if (use_eq_op_feature)
984  {
985  account = gnc_account_lookup_by_opening_balance (root, currency);
986  if (account)
987  return account;
988  }
989 
990  base_name = equity_base_name (equity_type);
991 
992  account = gnc_account_lookup_by_name(root, base_name);
993  if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
994  account = NULL;
995 
996  if (!account)
997  {
998  base_name = base_name && *base_name ? _(base_name) : "";
999 
1000  account = gnc_account_lookup_by_name(root, base_name);
1001  if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
1002  account = NULL;
1003  }
1004 
1005  base_name_exists = (account != NULL);
1006 
1007  if (account &&
1008  gnc_commodity_equiv (currency, xaccAccountGetCommodity (account)))
1009  {
1010  if (use_eq_op_feature)
1011  xaccAccountSetIsOpeningBalance (account, TRUE);
1012  return account;
1013  }
1014 
1015  name = g_strconcat (base_name, " - ",
1016  gnc_commodity_get_mnemonic (currency), NULL);
1017  account = gnc_account_lookup_by_name(root, name);
1018  if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
1019  account = NULL;
1020 
1021  name_exists = (account != NULL);
1022 
1023  if (account &&
1024  gnc_commodity_equiv (currency, xaccAccountGetCommodity (account)))
1025  {
1026  if (use_eq_op_feature)
1027  xaccAccountSetIsOpeningBalance (account, TRUE);
1028  return account;
1029  }
1030 
1031  /* Couldn't find one, so create it */
1032  if (name_exists && base_name_exists)
1033  {
1034  PWARN ("equity account with unexpected currency");
1035  g_free (name);
1036  return NULL;
1037  }
1038 
1039  if (!base_name_exists &&
1041  {
1042  g_free (name);
1043  name = g_strdup (base_name);
1044  }
1045 
1046  parent = gnc_account_lookup_by_name(root, _("Equity"));
1047  if (!parent || xaccAccountGetType (parent) != ACCT_TYPE_EQUITY)
1048  parent = root;
1049  g_assert(parent);
1050 
1051  account = xaccMallocAccount (gnc_account_get_book(root));
1052 
1053  xaccAccountBeginEdit (account);
1054 
1055  xaccAccountSetName (account, name);
1057  xaccAccountSetCommodity (account, currency);
1058 
1059  if (use_eq_op_feature)
1060  xaccAccountSetIsOpeningBalance (account, TRUE);
1061 
1062  xaccAccountBeginEdit (parent);
1063  gnc_account_append_child (parent, account);
1064  xaccAccountCommitEdit (parent);
1065 
1066  xaccAccountCommitEdit (account);
1067 
1068  g_free (name);
1069 
1070  return account;
1071 }
1072 
1073 gboolean
1074 gnc_account_create_opening_balance (Account *account,
1075  gnc_numeric balance,
1076  time64 date,
1077  QofBook *book)
1078 {
1079  Account *equity_account;
1080  Transaction *trans;
1081  Split *split;
1082  gnc_commodity *commodity;
1083 
1084  if (gnc_numeric_zero_p (balance))
1085  return TRUE;
1086 
1087  g_return_val_if_fail (account != NULL, FALSE);
1088  commodity = xaccAccountGetCommodity (account);
1089  g_return_val_if_fail (gnc_commodity_is_currency (commodity), FALSE);
1090 
1091  equity_account =
1092  gnc_find_or_create_equity_account (gnc_account_get_root(account),
1093  EQUITY_OPENING_BALANCE,
1094  commodity);
1095  if (!equity_account)
1096  return FALSE;
1097 
1098  xaccAccountBeginEdit (account);
1099  xaccAccountBeginEdit (equity_account);
1100 
1101  trans = xaccMallocTransaction (book);
1102 
1103  xaccTransBeginEdit (trans);
1104 
1105  xaccTransSetCurrency (trans, gnc_account_or_default_currency (account, NULL));
1107  xaccTransSetDescription (trans, _("Opening Balance"));
1108 
1109  split = xaccMallocSplit (book);
1110 
1111  xaccTransAppendSplit (trans, split);
1112  xaccAccountInsertSplit (account, split);
1113 
1114  xaccSplitSetAmount (split, balance);
1115  xaccSplitSetValue (split, balance);
1116 
1117  balance = gnc_numeric_neg (balance);
1118 
1119  split = xaccMallocSplit (book);
1120 
1121  xaccTransAppendSplit (trans, split);
1122  xaccAccountInsertSplit (equity_account, split);
1123 
1124  xaccSplitSetAmount (split, balance);
1125  xaccSplitSetValue (split, balance);
1126 
1127  xaccTransCommitEdit (trans);
1128  xaccAccountCommitEdit (equity_account);
1129  xaccAccountCommitEdit (account);
1130 
1131  return TRUE;
1132 }
1133 
1134 
1135 gnc_commodity *
1137 {
1138  gnc_commodity * currency;
1139  gnc_commodity_table *table;
1140  const char *code;
1141 
1142  table = gnc_get_current_commodities ();
1143  code = gnc_locale_default_iso_currency_code ();
1144 
1145  currency = gnc_commodity_table_lookup (table, GNC_COMMODITY_NS_CURRENCY, code);
1146 
1147  return (currency ? currency : NULL);
1148 }
1149 
1150 gnc_commodity *
1152 {
1153  gnc_commodity * currency = gnc_locale_default_currency_nodefault ();
1154 
1155  return (currency ? currency :
1156  gnc_commodity_table_lookup (gnc_get_current_commodities (),
1157  GNC_COMMODITY_NS_CURRENCY, "USD"));
1158 }
1159 
1160 
1161 static gnc_commodity *
1162 gnc_default_currency_common (gchar *requested_currency,
1163  const gchar *section)
1164 {
1165  gnc_commodity *currency = NULL;
1166  gchar *mnemonic;
1167 
1168  if (requested_currency)
1169  return gnc_commodity_table_lookup(gnc_get_current_commodities(),
1170  GNC_COMMODITY_NS_CURRENCY,
1171  requested_currency);
1172 
1173  if (gnc_book_use_book_currency (gnc_get_current_book ()))
1174  return gnc_book_get_book_currency (gnc_get_current_book ());
1175 
1176  if (gnc_prefs_get_bool (section, GNC_PREF_CURRENCY_CHOICE_OTHER))
1177  {
1178  mnemonic = gnc_prefs_get_string(section, GNC_PREF_CURRENCY_OTHER);
1179  currency = gnc_commodity_table_lookup(gnc_get_current_commodities(),
1180  GNC_COMMODITY_NS_CURRENCY, mnemonic);
1181  DEBUG("mnemonic %s, result %p",
1182  mnemonic && *mnemonic ? mnemonic : "(null)", currency);
1183  g_free(mnemonic);
1184  }
1185 
1186  if (!currency)
1187  currency = gnc_locale_default_currency ();
1188  if (currency)
1189  {
1190  mnemonic = requested_currency;
1191  g_free(mnemonic);
1192  }
1193  return currency;
1194 }
1195 
1196 gnc_commodity *
1198 {
1199  return gnc_default_currency_common (user_default_currency, GNC_PREFS_GROUP_GENERAL);
1200 }
1201 
1202 gnc_commodity * gnc_account_or_default_currency(const Account* account, gboolean * currency_from_account_found)
1203 {
1204  gnc_commodity *currency;
1205  if (!account)
1206  {
1207  if (currency_from_account_found)
1208  *currency_from_account_found = FALSE;
1209  return gnc_default_currency();
1210  }
1211 
1212  currency = gnc_account_get_currency_or_parent(account);
1213  if (currency)
1214  {
1215  if (currency_from_account_found)
1216  *currency_from_account_found = TRUE;
1217  }
1218  else
1219  {
1220  if (currency_from_account_found)
1221  *currency_from_account_found = FALSE;
1222  currency = gnc_default_currency();
1223  }
1224  return currency;
1225 }
1226 
1227 
1228 
1229 gnc_commodity *
1231 {
1232  return gnc_default_currency_common (user_report_currency, GNC_PREFS_GROUP_GENERAL_REPORT);
1233 }
1234 
1235 static void
1236 gnc_currency_changed_cb (GSettings *settings, gchar *key, gpointer user_data)
1237 {
1238  user_default_currency = NULL;
1239  user_report_currency = NULL;
1240  gnc_hook_run(HOOK_CURRENCY_CHANGED, NULL);
1241 }
1242 
1243 
1245 gnc_default_print_info (gboolean use_symbol)
1246 {
1247  static GNCPrintAmountInfo info;
1248  static gboolean got_it = FALSE;
1249  struct lconv *lc;
1250 
1251  /* These must be updated each time. */
1252  info.use_symbol = use_symbol ? 1 : 0;
1253  info.commodity = gnc_default_currency ();
1254 
1255  if (got_it)
1256  return info;
1257 
1258  lc = gnc_localeconv ();
1259 
1260  info.max_decimal_places = lc->frac_digits;
1261  info.min_decimal_places = lc->frac_digits;
1262 
1263  info.use_separators = 1;
1264  info.use_locale = 1;
1265  info.monetary = 1;
1266  info.force_fit = 0;
1267  info.round = 0;
1268 
1269  got_it = TRUE;
1270 
1271  return info;
1272 }
1273 
1274 static gboolean
1275 is_decimal_fraction (int fraction, guint8 *max_decimal_places_p)
1276 {
1277  guint8 max_decimal_places = 0;
1278 
1279  if (fraction <= 0)
1280  return FALSE;
1281 
1282  while (fraction != 1)
1283  {
1284  if (fraction % 10 != 0)
1285  return FALSE;
1286 
1287  fraction = fraction / 10;
1288  max_decimal_places += 1;
1289  }
1290 
1291  if (max_decimal_places_p)
1292  *max_decimal_places_p = max_decimal_places;
1293 
1294  return TRUE;
1295 }
1296 
1298 gnc_commodity_print_info (const gnc_commodity *commodity,
1299  gboolean use_symbol)
1300 {
1301  GNCPrintAmountInfo info;
1302  gboolean is_iso;
1303 
1304  if (commodity == NULL)
1305  return gnc_default_print_info (use_symbol);
1306 
1307  info.commodity = commodity;
1308 
1309  is_iso = gnc_commodity_is_iso (commodity);
1310 
1311  if (is_decimal_fraction (gnc_commodity_get_fraction (commodity),
1312  &info.max_decimal_places))
1313  {
1314  if (is_iso)
1315  info.min_decimal_places = info.max_decimal_places;
1316  else
1317  info.min_decimal_places = 0;
1318  }
1319  else
1320  info.max_decimal_places = info.min_decimal_places = 0;
1321 
1322  info.use_separators = 1;
1323  info.use_symbol = use_symbol ? 1 : 0;
1324  info.use_locale = is_iso ? 1 : 0;
1325  info.monetary = 1;
1326  info.force_fit = 0;
1327  info.round = 0;
1328 
1329  return info;
1330 }
1331 
1332 static GNCPrintAmountInfo
1333 gnc_account_print_info_helper(const Account *account, gboolean use_symbol,
1334  gnc_commodity * (*efffunc)(const Account *),
1335  int (*scufunc)(const Account*))
1336 {
1337  GNCPrintAmountInfo info;
1338  gboolean is_iso;
1339  int scu;
1340 
1341  if (account == NULL)
1342  return gnc_default_print_info (use_symbol);
1343 
1344  info.commodity = efffunc (account);
1345 
1346  is_iso = gnc_commodity_is_iso (info.commodity);
1347 
1348  scu = scufunc (account);
1349 
1350  if (is_decimal_fraction (scu, &info.max_decimal_places))
1351  {
1352  if (is_iso)
1353  info.min_decimal_places = info.max_decimal_places;
1354  else
1355  info.min_decimal_places = 0;
1356  }
1357  else
1358  info.max_decimal_places = info.min_decimal_places = 0;
1359 
1360  info.use_separators = 1;
1361  info.use_symbol = use_symbol ? 1 : 0;
1362  info.use_locale = is_iso ? 1 : 0;
1363  info.monetary = 1;
1364  info.force_fit = 0;
1365  info.round = 0;
1366 
1367  return info;
1368 }
1369 
1371 gnc_account_print_info (const Account *account, gboolean use_symbol)
1372 {
1373  return gnc_account_print_info_helper(account, use_symbol,
1376 }
1377 
1379 gnc_split_amount_print_info (Split *split, gboolean use_symbol)
1380 {
1381  if (!split)
1382  {
1383  GNCPrintAmountInfo info = gnc_default_share_print_info ();
1384  info.use_symbol = use_symbol;
1385  return info;
1386  }
1387 
1388  return gnc_account_print_info (xaccSplitGetAccount (split), use_symbol);
1389 }
1390 
1391 static GNCPrintAmountInfo
1392 gnc_default_print_info_helper (int decplaces)
1393 {
1394  GNCPrintAmountInfo info;
1395 
1396  info.commodity = NULL;
1397 
1398  info.max_decimal_places = decplaces;
1399  info.min_decimal_places = 0;
1400 
1401  info.use_separators = 1;
1402  info.use_symbol = 0;
1403  info.use_locale = 1;
1404  info.monetary = 1;
1405  info.force_fit = 0;
1406  info.round = 0;
1407 
1408  return info;
1409 }
1410 
1412 gnc_default_share_print_info (void)
1413 {
1414  static GNCPrintAmountInfo info;
1415  static gboolean got_it = FALSE;
1416 
1417  if (!got_it)
1418  {
1419  info = gnc_default_print_info_helper (5);
1420  info.monetary = 0;
1421  got_it = TRUE;
1422  }
1423 
1424  return info;
1425 }
1426 
1428 gnc_share_print_info_places (int decplaces)
1429 {
1430  GNCPrintAmountInfo info;
1431 
1432  info = gnc_default_share_print_info ();
1433  info.max_decimal_places = decplaces;
1434  info.min_decimal_places = decplaces;
1435  info.force_fit = 1;
1436  info.round = 1;
1437  return info;
1438 }
1439 
1441 gnc_price_print_info (const gnc_commodity *curr, gboolean use_symbol)
1442 {
1443  GNCPrintAmountInfo info;
1444  gboolean force = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
1445  GNC_PREF_PRICES_FORCE_DECIMAL);
1446  info.commodity = curr;
1447 
1448  if (info.commodity)
1449  {
1450  int frac = gnc_commodity_get_fraction (curr);
1451  guint8 decplaces = 2;
1452  while (frac != 1 && (frac % 10) == 0 && (frac /= 10)) ++decplaces;
1453  info.max_decimal_places = decplaces;
1454  info.min_decimal_places = decplaces;
1455  }
1456  else
1457  {
1458  info.max_decimal_places = 6;
1459  info.min_decimal_places = 0;
1460  }
1461 
1462  info.use_separators = 1;
1463  info.use_symbol = use_symbol ? 1 : 0;
1464  info.use_locale = 1;
1465  info.monetary = 1;
1466 
1467  info.force_fit = force;
1468  info.round = force;
1469  return info;
1470 }
1471 
1473 gnc_default_price_print_info (const gnc_commodity *curr)
1474 {
1475  return gnc_price_print_info (curr, FALSE);
1476 }
1477 
1478 
1480 gnc_integral_print_info (void)
1481 {
1482  static GNCPrintAmountInfo info;
1483  static gboolean got_it = FALSE;
1484 
1485  if (!got_it)
1486  {
1487  info = gnc_default_print_info_helper (0);
1488  got_it = TRUE;
1489  }
1490 
1491  return info;
1492 }
1493 
1494 /* Utility function for printing non-negative amounts */
1495 static int
1496 PrintAmountInternal(char *buf, gnc_numeric val, const GNCPrintAmountInfo *info)
1497 {
1498  struct lconv *lc = gnc_localeconv();
1499  int num_whole_digits;
1500  char temp_buf[128];
1501  gnc_numeric whole, rounding;
1502  int min_dp, max_dp;
1503  gboolean value_is_negative, value_is_decimal;
1504 
1505  g_return_val_if_fail (info != NULL, 0);
1506 
1507  if (gnc_numeric_check (val))
1508  {
1509  PWARN ("Bad numeric: %s.",
1511  *buf = '\0';
1512  return 0;
1513  }
1514 
1515  /* Print the absolute value, but remember sign */
1516  value_is_negative = gnc_numeric_negative_p (val);
1517  val = gnc_numeric_abs (val);
1518 
1519  /* Try to print as decimal. */
1520  value_is_decimal = gnc_numeric_to_decimal(&val, NULL);
1521  if (!value_is_decimal && info->force_fit && info->round)
1522  {
1523  /* if there's a commodity use 100x the commodity's fraction. N.B. This
1524  * assumes that commodity fractions are multiples of 10, a reasonable
1525  * assumption in 2018. Otherwise, if there's a reasonable
1526  * max_decimal_places, use that.
1527  */
1528  const gint64 denom = info->commodity ?
1529  gnc_commodity_get_fraction(info->commodity) * 100 :
1530  (info->max_decimal_places &&
1531  info->max_decimal_places <= maximum_decimals) ?
1532  pow_10[info->max_decimal_places] : pow_10[maximum_decimals];
1534  value_is_decimal = gnc_numeric_to_decimal(&val, NULL);
1535  }
1536  min_dp = info->min_decimal_places;
1537  max_dp = info->max_decimal_places;
1538 
1539  /* Don to limit the number of decimal places _UNLESS_ force_fit is
1540  * true. */
1541  if (!info->force_fit)
1542  max_dp = 99;
1543 
1544  /* rounding? -- can only ROUND if force_fit is also true */
1545  if (value_is_decimal && info->round && info->force_fit)
1546  {
1547  rounding.num = 5; /* Limit the denom to 10^13 ~= 2^44, leaving max at ~524288 */
1548  rounding.denom = pow(10, max_dp + 1);
1549  val = gnc_numeric_add(val, rounding, val.denom,
1551 
1552  if (gnc_numeric_check(val))
1553  {
1554  PWARN ("Bad numeric from rounding: %s.",
1556  *buf = '\0';
1557  return 0;
1558  }
1559  }
1560 
1561  /* calculate the integer part and the remainder */
1562  whole = gnc_numeric_convert(val, 1, GNC_HOW_RND_TRUNC);
1563  val = gnc_numeric_sub (val, whole, GNC_DENOM_AUTO, GNC_HOW_RND_NEVER);
1564  if (gnc_numeric_check (val))
1565  {
1566  PWARN ("Problem with remainder: %s.",
1568  *buf = '\0';
1569  return 0;
1570  }
1571 
1572  // Value may now be decimal, for example if the factional part is zero
1573  value_is_decimal = gnc_numeric_to_decimal(&val, NULL);
1574  /* print the integer part without separators */
1575  sprintf(temp_buf, "%" G_GINT64_FORMAT, whole.num);
1576  num_whole_digits = strlen (temp_buf);
1577 
1578  if (!info->use_separators)
1579  strcpy (buf, temp_buf);
1580  else
1581  {
1582  int group_count;
1583  char *separator;
1584  char *temp_ptr;
1585  char *buf_ptr;
1586  char *group;
1587  gchar *rev_buf;
1588 
1589  if (info->monetary)
1590  {
1591  separator = lc->mon_thousands_sep;
1592  group = lc->mon_grouping;
1593  }
1594  else
1595  {
1596  separator = lc->thousands_sep;
1597  group = lc->grouping;
1598  }
1599 
1600  buf_ptr = buf;
1601  temp_ptr = &temp_buf[num_whole_digits - 1];
1602  group_count = 0;
1603 
1604  while (temp_ptr != temp_buf)
1605  {
1606  *buf_ptr++ = *temp_ptr--;
1607 
1608  if (*group != CHAR_MAX)
1609  {
1610  group_count++;
1611 
1612  if (group_count == *group)
1613  {
1614  g_utf8_strncpy(buf_ptr, separator, 1);
1615  buf_ptr = g_utf8_find_next_char(buf_ptr, NULL);
1616  group_count = 0;
1617 
1618  /* Peek ahead at the next group code */
1619  switch (group[1])
1620  {
1621  /* A null char means repeat the last group indefinitely */
1622  case '\0':
1623  break;
1624  /* CHAR_MAX means no more grouping allowed */
1625  case CHAR_MAX:
1626  /* fall through */
1627  /* Anything else means another group size */
1628  default:
1629  group++;
1630  break;
1631  }
1632  }
1633  }
1634  }
1635 
1636  /* We built the string backwards, now reverse */
1637  *buf_ptr++ = *temp_ptr;
1638  *buf_ptr = '\0';
1639  rev_buf = g_utf8_strreverse(buf, -1);
1640  strcpy (buf, rev_buf);
1641  g_free(rev_buf);
1642  } /* endif */
1643 
1644  /* at this point, buf contains the whole part of the number */
1645 
1646  /* If it's not decimal, print the fraction as an expression. */
1647  if (!value_is_decimal)
1648  {
1649  val = gnc_numeric_reduce (val);
1650 
1651  if (val.denom > 0)
1652  sprintf (temp_buf, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
1653  val.num, val.denom);
1654  else
1655  sprintf (temp_buf, "%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT,
1656  val.num, -val.denom);
1657 
1658  if (whole.num == 0)
1659  *buf = '\0';
1660  else if (value_is_negative)
1661  strcat(buf, " - ");
1662  else
1663  strcat(buf, " + ");
1664 
1665  strcat (buf, temp_buf);
1666  }
1667  else
1668  {
1669  char *decimal_point;
1670  guint8 num_decimal_places = 0;
1671  char *temp_ptr = temp_buf;
1672 
1673  decimal_point = info->monetary
1674  ? lc->mon_decimal_point
1675  : lc->decimal_point;
1676  g_utf8_strncpy(temp_ptr, decimal_point, 1);
1677  temp_ptr = g_utf8_find_next_char(temp_ptr, NULL);
1678 
1679  while (!gnc_numeric_zero_p (val)
1680  && (val.denom != 1)
1681  && (num_decimal_places < max_dp))
1682  {
1683  gint64 digit;
1684 
1685  val.denom = val.denom / 10;
1686 
1687  digit = val.num / val.denom;
1688 
1689  *temp_ptr++ = digit + '0';
1690  num_decimal_places++;
1691 
1692  val.num = val.num - (digit * val.denom);
1693  }
1694 
1695  while (num_decimal_places < min_dp)
1696  {
1697  *temp_ptr++ = '0';
1698  num_decimal_places++;
1699  }
1700 
1701  /* cap the end and move to the last character */
1702  *temp_ptr-- = '\0';
1703 
1704  /* Here we strip off trailing decimal zeros per the argument. */
1705  while (*temp_ptr == '0' && num_decimal_places > min_dp)
1706  {
1707  *temp_ptr-- = '\0';
1708  num_decimal_places--;
1709  }
1710 
1711  if (num_decimal_places > max_dp)
1712  {
1713  PWARN ("max_decimal_places too small; limit %d, value %s%s",
1714  info->max_decimal_places, buf, temp_buf);
1715  }
1716 
1717  if (num_decimal_places > 0)
1718  strcat (buf, temp_buf);
1719  }
1720 
1721  return strlen(buf);
1722 }
1723 
1727 int
1728 xaccSPrintAmount (char * bufp, gnc_numeric val, GNCPrintAmountInfo info)
1729 {
1730  struct lconv *lc;
1731 
1732  char *orig_bufp = bufp;
1733  const char *currency_symbol;
1734  const char *sign;
1735 
1736  char cs_precedes;
1737  char sep_by_space;
1738  char sign_posn;
1739 
1740  gboolean print_sign = TRUE;
1741  gboolean print_absolute = FALSE;
1742 
1743  if (!bufp)
1744  return 0;
1745 
1746  lc = gnc_localeconv();
1747  if (info.use_locale)
1748  if (gnc_numeric_negative_p (val))
1749  {
1750  cs_precedes = lc->n_cs_precedes;
1751  sep_by_space = lc->n_sep_by_space;
1752  }
1753  else
1754  {
1755  cs_precedes = lc->p_cs_precedes;
1756  sep_by_space = lc->p_sep_by_space;
1757  }
1758  else
1759  {
1760  cs_precedes = TRUE;
1761  sep_by_space = TRUE;
1762  }
1763 
1764  if (info.commodity && info.use_symbol)
1765  {
1766  currency_symbol = gnc_commodity_get_nice_symbol (info.commodity);
1767  if (!gnc_commodity_is_iso (info.commodity))
1768  {
1769  cs_precedes = FALSE;
1770  sep_by_space = TRUE;
1771  }
1772  }
1773  else /* !info.use_symbol || !info.commodity */
1774  currency_symbol = "";
1775 
1776  if (gnc_numeric_negative_p (val))
1777  {
1778  sign = lc->negative_sign;
1779  sign_posn = lc->n_sign_posn;
1780  }
1781  else
1782  {
1783  sign = lc->positive_sign;
1784  sign_posn = lc->p_sign_posn;
1785  }
1786 
1787  if (gnc_numeric_zero_p (val) || (sign == NULL) || (sign[0] == 0))
1788  print_sign = FALSE;
1789 
1790  /* See if we print sign now */
1791  if (print_sign && (sign_posn == 1))
1792  bufp = g_stpcpy(bufp, sign);
1793 
1794  /* Now see if we print currency */
1795  if (cs_precedes)
1796  {
1797  /* See if we print sign now */
1798  if (print_sign && (sign_posn == 3))
1799  bufp = g_stpcpy(bufp, sign);
1800 
1801  if (info.use_symbol)
1802  {
1803  bufp = g_stpcpy(bufp, currency_symbol);
1804  if (sep_by_space)
1805  bufp = g_stpcpy(bufp, " ");
1806  }
1807 
1808  /* See if we print sign now */
1809  if (print_sign && (sign_posn == 4))
1810  bufp = g_stpcpy(bufp, sign);
1811  }
1812 
1813  /* Now see if we print parentheses */
1814  if (print_sign && (sign_posn == 0))
1815  {
1816  bufp = g_stpcpy(bufp, "(");
1817  print_absolute = TRUE;
1818  }
1819 
1820  /* Now print the value */
1821  bufp += PrintAmountInternal(bufp,
1822  print_absolute ? gnc_numeric_abs(val) : val,
1823  &info);
1824 
1825  /* Now see if we print parentheses */
1826  if (print_sign && (sign_posn == 0))
1827  bufp = g_stpcpy(bufp, ")");
1828 
1829  /* Now see if we print currency */
1830  if (!cs_precedes)
1831  {
1832  /* See if we print sign now */
1833  if (print_sign && (sign_posn == 3))
1834  bufp = g_stpcpy(bufp, sign);
1835 
1836  if (info.use_symbol)
1837  {
1838  if (sep_by_space)
1839  bufp = g_stpcpy(bufp, " ");
1840  bufp = g_stpcpy(bufp, currency_symbol);
1841  }
1842 
1843  /* See if we print sign now */
1844  if (print_sign && (sign_posn == 4))
1845  bufp = g_stpcpy(bufp, sign);
1846  }
1847 
1848  /* See if we print sign now */
1849  if (print_sign && (sign_posn == 2))
1850  bufp = g_stpcpy(bufp, sign);
1851 
1852  /* return length of printed string */
1853  return (bufp - orig_bufp);
1854 }
1855 
1856 #define BUFLEN 1024
1857 
1858 const char *
1859 xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info)
1860 {
1861  /* hack alert -- this is not thread safe ... */
1862  static char buf[BUFLEN];
1863 
1864  if (!xaccSPrintAmount (buf, val, info))
1865  buf[0] = '\0';
1866 
1867  /* its OK to return buf, since we declared it static */
1868  return buf;
1869 }
1870 
1871 const char *
1873 {
1874  /* hack alert -- this is not thread safe ... */
1875  static char buf[BUFLEN];
1876  static const char ltr_isolate[] = { 0xe2, 0x81, 0xa6 };
1877  static const char ltr_pop_isolate[] = { 0xe2, 0x81, 0xa9 };
1878  size_t offset = info.use_symbol ? 3 : 0;
1879 
1880  memset (buf, 0, BUFLEN);
1881  if (!xaccSPrintAmount (buf + offset, val, info))
1882  {
1883  buf[0] = '\0';
1884  return buf;
1885  };
1886 
1887  if (!info.use_symbol)
1888  return buf;
1889 
1890  memcpy (buf, ltr_isolate, 3);
1891 
1892  if (buf[BUFLEN - 4] == '\0')
1893  {
1894  size_t length = strlen (buf);
1895  memcpy (buf + length, ltr_pop_isolate, 3);
1896  }
1897  else
1898  {
1899  buf[BUFLEN - 1] = '\0';
1900  memcpy (buf + BUFLEN - 4, ltr_pop_isolate, 3);
1901 
1902  PWARN("buffer length %d exceeded, string truncated was %s", BUFLEN, buf);
1903  }
1904  /* its OK to return buf, since we declared it static
1905  and is immediately g_strdup'd */
1906  return buf;
1907 }
1908 
1909 gchar *
1910 gnc_wrap_text_with_bidi_ltr_isolate (const gchar *text)
1911 {
1912  static const char *ltr = "\u2066"; // ltr isolate
1913  static const char *pop = "\u2069"; // pop directional formatting
1914 
1915  if (!text)
1916  return NULL;
1917 
1918  return g_strconcat (ltr, text, pop, NULL);
1919 }
1920 
1921 /********************************************************************\
1922  ********************************************************************/
1923 
1924 #define FUDGE .00001
1925 
1926 /* This function is basically untranslatable. I'd
1927  guess out of the 29 translations we have, 20 will have their number
1928  wordings in a totally different way than English has (not to
1929  mention gender-dependent number endings). Which means this
1930  word-by-word translation will be useless or even plain
1931  wrong. For this reason, we don't even start to pretend a
1932  word-by-word translation would be of any use, so we don't mark any
1933  of these strings for translation. cstim, 2007-04-15. */
1934 static gchar *small_numbers[] =
1935 {
1936  /* Translators: This section is for generating the "amount, in
1937  words" field when printing a check. This function gets the
1938  wording right for English, but unfortunately not for most other
1939  languages. Decide for yourself whether the check printing is
1940  actually needed in your language; if not, you can safely skip the
1941  translation of all of these strings. */
1942  "Zero", "One", "Two", "Three", "Four",
1943  "Five", "Six", "Seven", "Eight", "Nine",
1944  "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
1945  "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen",
1946  "Twenty"
1947 };
1948 static gchar *medium_numbers[] =
1949 {
1950  "Zero", "Ten", "Twenty", "Thirty", "Forty",
1951  "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"
1952 };
1953 static gchar *big_numbers[] =
1954 {
1955  /* Translators: This is the word for the number 10^2 */
1956  "Hundred",
1957  /* Translators: This is the word for the number 10^3 */
1958  "Thousand",
1959  /* Translators: This is the word for the number 10^6, one thousand
1960  thousands. */
1961  "Million",
1962  /* Translators: This is the word for the number 10^9, one thousand
1963  millions. WATCH OUT: In British English and many other languages
1964  this word is used for 10^12 which is one million millions! In
1965  contrast to this, here in GnuCash this is used in the American
1966  English meaning of 10^9. */
1967  "Billion",
1968  /* Translators: This is the word for the number 10^12, one million
1969  millions. */
1970  "Trillion",
1971  /* Translators: This is the word for the number 10^15 */
1972  "Quadrillion",
1973  /* Translators: This is the word for the number 10^18 */
1974  "Quintillion"
1975 };
1976 
1977 static gchar *
1978 integer_to_words(gint64 val)
1979 {
1980  gint64 log_val, pow_val, this_part;
1981  GString *result;
1982  gchar *tmp;
1983 
1984  if (val == 0)
1985  return g_strdup("zero");
1986  if (val < 0)
1987  val = -val;
1988 
1989  result = g_string_sized_new(100);
1990 
1991  while (val >= 1000)
1992  {
1993  log_val = log10(val) / 3 + FUDGE;
1994  pow_val = exp(log_val * 3 * G_LN10) + FUDGE;
1995  this_part = val / pow_val;
1996  val -= this_part * pow_val;
1997  tmp = integer_to_words(this_part);
1998  g_string_append_printf(result, "%s %s ", tmp,
1999  gettext(big_numbers[log_val]));
2000  g_free(tmp);
2001  }
2002 
2003  if (val >= 100)
2004  {
2005  this_part = val / 100;
2006  val -= this_part * 100;
2007  g_string_append_printf(result, "%s %s ",
2008  gettext(small_numbers[this_part]),
2009  gettext(big_numbers[0]));
2010  }
2011 
2012  if (val > 20)
2013  {
2014  this_part = val / 10;
2015  val -= this_part * 10;
2016  g_string_append(result, gettext(medium_numbers[this_part]));
2017  g_string_append_c(result, ' ');
2018  }
2019 
2020  if (val > 0)
2021  {
2022  this_part = val;
2023  g_string_append(result, gettext(small_numbers[this_part]));
2024  g_string_append_c(result, ' ');
2025  }
2026 
2027  result = g_string_truncate(result, result->len - 1);
2028  return g_string_free(result, FALSE);
2029 }
2030 
2031 #ifdef _MSC_VER
2032 static double round(double x)
2033 {
2034  // A simple round() implementation because MSVC doesn't seem to have that
2035  return floor(x + 0.5);
2036 }
2037 #endif
2038 
2039 gchar *
2040 number_to_words(gdouble val, gint64 denom)
2041 {
2042  gint64 int_part, frac_part;
2043  gchar *int_string, *nomin_string, *denom_string, *full_string;
2044 
2045  if (val < 0) val = -val;
2046  if (denom < 0) denom = -denom;
2047 
2048  int_part = floor(val);
2049  frac_part = round((val - int_part) * denom);
2050 
2051  int_string = integer_to_words(int_part);
2052  /* Inside of the gettext macro _(...) we must not use any macros but
2053  only plain string literals. For this reason, convert the strings
2054  separately. */
2055  nomin_string = g_strdup_printf("%02" G_GINT64_FORMAT, frac_part);
2056  denom_string = g_strdup_printf("%" G_GINT64_FORMAT, denom);
2057  full_string =
2058  /* Translators: This is for the "amount, in words" field in check
2059  printing. The first %s is the integer amount of dollars (or
2060  whatever currency), the second and third %s the cent amount as
2061  a fraction, e.g. 47/100. */
2062  g_strdup_printf("%s and %s/%s",
2063  int_string, nomin_string, denom_string);
2064  g_free(int_string);
2065  g_free(nomin_string);
2066  g_free(denom_string);
2067  return full_string;
2068 }
2069 
2070 gchar *
2071 numeric_to_words(gnc_numeric val)
2072 {
2073  return number_to_words(gnc_numeric_to_double(val),
2074  gnc_numeric_denom(val));
2075 }
2076 
2077 const gchar *
2078 printable_value (gdouble val, gint denom)
2079 {
2080  GNCPrintAmountInfo info;
2081  gnc_numeric num;
2082 
2083  num = gnc_numeric_create(round(val * denom), denom);
2084  info = gnc_share_print_info_places(log10(denom));
2085  return xaccPrintAmount (num, info);
2086 }
2087 
2088 /********************************************************************\
2089  * xaccParseAmount *
2090  * parses amount strings using locale data *
2091  * *
2092  * Args: in_str -- pointer to string rep of num *
2093  * monetary -- boolean indicating whether value is monetary *
2094  * result -- pointer to result location, may be NULL *
2095  * endstr -- used to store first digit not used in parsing *
2096  * Return: gboolean -- TRUE if a number found and parsed *
2097  * If FALSE, result is not changed *
2098 \********************************************************************/
2099 
2100 /* Parsing state machine states */
2101 typedef enum
2102 {
2103  START_ST, /* Parsing initial whitespace */
2104  NEG_ST, /* Parsed a negative sign or a left paren */
2105  NUMER_ST, /* Parsing digits before grouping and decimal characters */
2106  FRAC_ST, /* Parsing the fractional portion of a number */
2107  DONE_ST, /* Finished, number is correct module grouping constraints */
2108  NO_NUM_ST /* Finished, number was malformed */
2109 } ParseState;
2110 
2111 #define done_state(state) (((state) == DONE_ST) || ((state) == NO_NUM_ST))
2112 
2113 static inline long long int
2114 multiplier (int num_decimals)
2115 {
2116  switch (num_decimals)
2117  {
2118  case 12:
2119  return 1000000000000;
2120  case 11:
2121  return 100000000000;
2122  case 10:
2123  return 10000000000;
2124  case 9:
2125  return 1000000000;
2126  case 8:
2127  return 100000000;
2128  case 7:
2129  return 10000000;
2130  case 6:
2131  return 1000000;
2132  case 5:
2133  return 100000;
2134  case 4:
2135  return 10000;
2136  case 3:
2137  return 1000;
2138  case 2:
2139  return 100;
2140  case 1:
2141  return 10;
2142  case 0:
2143  return 1;
2144  default:
2145  PERR("bad fraction length");
2146  g_assert_not_reached();
2147  break;
2148  }
2149 
2150  return 1;
2151 }
2152 
2153 gboolean
2154 xaccParseAmount (const char * in_str, gboolean monetary, gnc_numeric *result,
2155  char **endstr)
2156 {
2157  return xaccParseAmountPosSign (in_str, monetary, result, endstr, FALSE);
2158 }
2159 
2160 gboolean
2161 xaccParseAmountPosSign (const char * in_str, gboolean monetary, gnc_numeric *result,
2162  char **endstr, gboolean skip)
2163 {
2164  struct lconv *lc = gnc_localeconv();
2165 
2166  gunichar negative_sign;
2167  gunichar decimal_point;
2168  gunichar group_separator;
2169  gchar *ignore = NULL;
2170  char *plus_sign = "+";
2171 
2172  negative_sign = g_utf8_get_char(lc->negative_sign);
2173  if (monetary)
2174  {
2175  group_separator = g_utf8_get_char(lc->mon_thousands_sep);
2176  decimal_point = g_utf8_get_char(lc->mon_decimal_point);
2177  }
2178  else
2179  {
2180  group_separator = g_utf8_get_char(lc->thousands_sep);
2181  decimal_point = g_utf8_get_char(lc->decimal_point);
2182  }
2183 
2184  if (skip)
2185  {
2186  /* We want the locale's positive sign to be ignored.
2187  * If the locale doesn't specify one, we assume "+" as
2188  * an optional positive sign and ignore that */
2189  ignore = lc->positive_sign;
2190  if (!ignore || !*ignore)
2191  ignore = plus_sign;
2192  }
2193 
2194  return xaccParseAmountExtended(in_str, monetary, negative_sign,
2195  decimal_point, group_separator,
2196  ignore, result, endstr);
2197 }
2198 
2199 gboolean
2200 xaccParseAmountExtended (const char * in_str, gboolean monetary,
2201  gunichar negative_sign, gunichar decimal_point,
2202  gunichar group_separator, const char *ignore_list,
2203  gnc_numeric *result, char **endstr)
2204 {
2205  gboolean is_negative;
2206  gboolean got_decimal;
2207  gboolean need_paren;
2208  long long int numer;
2209  long long int denom;
2210  int count;
2211 
2212  ParseState state;
2213 
2214  const gchar *in;
2215  gunichar uc;
2216  gchar *out_str;
2217  gchar *out;
2218 
2219  /* Initialize *endstr to in_str */
2220  if (endstr != NULL)
2221  *endstr = (char *) in_str;
2222 
2223  if (in_str == NULL)
2224  return FALSE;
2225 
2226  if (!g_utf8_validate(in_str, -1, &in))
2227  {
2228  printf("Invalid utf8 string '%s'. Bad character at position %ld.\n",
2229  in_str, g_utf8_pointer_to_offset (in_str, in));
2230  return FALSE;
2231  }
2232 
2233  /* 'out_str' will be used to store digits for numeric conversion.
2234  * 'out' will be used to traverse out_str. */
2235  out = out_str = g_new(gchar, strlen(in_str) + 128);
2236 
2237  /* 'in' is used to traverse 'in_str'. */
2238  in = in_str;
2239 
2240  is_negative = FALSE;
2241  got_decimal = FALSE;
2242  need_paren = FALSE;
2243  numer = 0;
2244  denom = 1;
2245 
2246  /* Initialize the state machine */
2247  state = START_ST;
2248 
2249  /* This while loop implements a state machine for parsing numbers. */
2250  while (TRUE)
2251  {
2252  ParseState next_state = state;
2253 
2254  uc = g_utf8_get_char(in);
2255 
2256  /* Ignore anything in the 'ignore list' */
2257  if (ignore_list && uc && g_utf8_strchr(ignore_list, -1, uc) != NULL)
2258  {
2259  in = g_utf8_next_char(in);
2260  continue;
2261  }
2262 
2263  /* Note we never need to check for the end of 'in_str' explicitly.
2264  * The 'else' clauses on all the state transitions will handle that. */
2265  switch (state)
2266  {
2267  /* START_ST means we have parsed 0 or more whitespace characters */
2268  case START_ST:
2269  if (g_unichar_isdigit(uc))
2270  {
2271  count = g_unichar_to_utf8(uc, out);
2272  out += count; /* we record the digits themselves in out_str
2273  * for later conversion by libc routines */
2274  next_state = NUMER_ST;
2275  }
2276  else if (uc == decimal_point)
2277  {
2278  next_state = FRAC_ST;
2279  }
2280  else if (g_unichar_isspace(uc))
2281  {
2282  }
2283  else if (uc == negative_sign)
2284  {
2285  is_negative = TRUE;
2286  next_state = NEG_ST;
2287  }
2288  else if (uc == '(')
2289  {
2290  is_negative = TRUE;
2291  need_paren = TRUE;
2292  next_state = NEG_ST;
2293  }
2294  else
2295  {
2296  next_state = NO_NUM_ST;
2297  }
2298 
2299  break;
2300 
2301  /* NEG_ST means we have just parsed a negative sign. For now,
2302  * we only recognize formats where the negative sign comes first. */
2303  case NEG_ST:
2304  if (g_unichar_isdigit(uc))
2305  {
2306  count = g_unichar_to_utf8(uc, out);
2307  out += count;
2308  next_state = NUMER_ST;
2309  }
2310  else if (uc == decimal_point)
2311  {
2312  next_state = FRAC_ST;
2313  }
2314  else if (g_unichar_isspace(uc))
2315  {
2316  }
2317  else
2318  {
2319  next_state = NO_NUM_ST;
2320  }
2321 
2322  break;
2323 
2324  /* NUMER_ST means we have started parsing the number, but
2325  * have not encountered a decimal separator. */
2326  case NUMER_ST:
2327  if (g_unichar_isdigit(uc))
2328  {
2329  count = g_unichar_to_utf8(uc, out);
2330  out += count;
2331  }
2332  else if (uc == decimal_point)
2333  {
2334  next_state = FRAC_ST;
2335  }
2336  else if (uc == group_separator)
2337  {
2338  ; //ignore it
2339  }
2340  else if (uc == ')' && need_paren)
2341  {
2342  next_state = DONE_ST;
2343  need_paren = FALSE;
2344  }
2345  else
2346  {
2347  next_state = DONE_ST;
2348  }
2349 
2350  break;
2351 
2352  /* FRAC_ST means we are now parsing fractional digits. */
2353  case FRAC_ST:
2354  if (g_unichar_isdigit(uc))
2355  {
2356  count = g_unichar_to_utf8(uc, out);
2357  out += count;
2358  }
2359  else if (uc == decimal_point)
2360  {
2361  /* If a subsequent decimal point is also whitespace,
2362  * assume it was intended as such and stop parsing.
2363  * Otherwise, there is a problem. */
2364  if (g_unichar_isspace(decimal_point))
2365  next_state = DONE_ST;
2366  else
2367  next_state = NO_NUM_ST;
2368  }
2369  else if (uc == group_separator)
2370  {
2371  /* If a subsequent group separator is also whitespace,
2372  * assume it was intended as such and stop parsing.
2373  * Otherwise ignore it. */
2374  if (g_unichar_isspace(group_separator))
2375  next_state = DONE_ST;
2376  }
2377  else if (uc == ')' && need_paren)
2378  {
2379  next_state = DONE_ST;
2380  need_paren = FALSE;
2381  }
2382  else
2383  {
2384  next_state = DONE_ST;
2385  }
2386 
2387  break;
2388 
2389  default:
2390  PERR("bad state");
2391  g_assert_not_reached();
2392  break;
2393  }
2394 
2395  /* If we're moving into the FRAC_ST or out of the machine
2396  * without going through FRAC_ST, record the integral value. */
2397  if (((next_state == FRAC_ST) && (state != FRAC_ST)) ||
2398  ((next_state == DONE_ST) && !got_decimal))
2399  {
2400  *out = '\0';
2401 
2402  if (*out_str != '\0' && sscanf(out_str, QOF_SCANF_LLD, &numer) < 1)
2403  {
2404  next_state = NO_NUM_ST;
2405  }
2406  else if (next_state == FRAC_ST)
2407  {
2408  /* reset the out pointer to record the fraction */
2409  out = out_str;
2410  *out = '\0';
2411 
2412  got_decimal = TRUE;
2413  }
2414  }
2415 
2416  state = next_state;
2417  if (done_state (state))
2418  break;
2419 
2420  in = g_utf8_next_char(in);
2421  }
2422 
2423  /* If there was an error, just quit */
2424  if (need_paren || (state == NO_NUM_ST))
2425  {
2426  g_free(out_str);
2427  return FALSE;
2428  }
2429 
2430  /* Cap the end of the fraction string, if any */
2431  *out = '\0';
2432 
2433  /* Add in fractional value */
2434  if (got_decimal && (*out_str != '\0'))
2435  {
2436  size_t len;
2437  long long int fraction;
2438 
2439  len = strlen(out_str);
2440 
2441  if (len > 12)
2442  {
2443  out_str[12] = '\0';
2444  len = 12;
2445  }
2446 
2447  if (sscanf (out_str, QOF_SCANF_LLD, &fraction) < 1)
2448  {
2449  g_free(out_str);
2450  return FALSE;
2451  }
2452 
2453  denom = multiplier(len);
2454  numer *= denom;
2455  numer += fraction;
2456  }
2457  else if (monetary && auto_decimal_enabled && !got_decimal)
2458  {
2459  if ((auto_decimal_places > 0) && (auto_decimal_places <= 12))
2460  {
2461  denom = multiplier(auto_decimal_places);
2462 
2463  /* No need to multiply numer by denom at this point,
2464  * since by specifying the auto decimal places the
2465  * user has effectively determined the scaling factor
2466  * for the numerator they entered.
2467  */
2468  }
2469  }
2470 
2471  if (result != NULL)
2472  {
2473  *result = gnc_numeric_create (numer, denom);
2474  if (is_negative)
2475  *result = gnc_numeric_neg (*result);
2476  }
2477 
2478  if (endstr != NULL)
2479  *endstr = (char *) in;
2480 
2481  g_free (out_str);
2482 
2483  return TRUE;
2484 }
2485 
2486 /* enable/disable the auto_decimal_enabled option */
2487 static void
2488 gnc_set_auto_decimal_enabled (gpointer settings, gchar *key, gpointer user_data)
2489 {
2490  auto_decimal_enabled =
2491  gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_POINT);
2492 }
2493 
2494 /* set the number of auto decimal places to use */
2495 static void
2496 gnc_set_auto_decimal_places (gpointer settings, gchar *key, gpointer user_data)
2497 {
2498  auto_decimal_places =
2499  gnc_prefs_get_int (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_PLACES);
2500 }
2501 
2502 static void
2503 gnc_auto_decimal_init (void)
2504 {
2505  auto_decimal_enabled =
2506  gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_POINT);
2507  auto_decimal_places =
2508  gnc_prefs_get_int (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_PLACES);
2509 }
2510 
2511 void
2512 gnc_ui_util_init (void)
2513 {
2514  gnc_configure_account_separator ();
2515  gnc_auto_decimal_init();
2516 
2517  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNT_SEPARATOR,
2518  gnc_configure_account_separator, NULL);
2519  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_NONE,
2520  gnc_configure_reverse_balance, NULL);
2521  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_CREDIT,
2522  gnc_configure_reverse_balance, NULL);
2523  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_INC_EXP,
2524  gnc_configure_reverse_balance, NULL);
2525  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_CURRENCY_CHOICE_LOCALE,
2526  gnc_currency_changed_cb, NULL);
2527  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_CURRENCY_CHOICE_OTHER,
2528  gnc_currency_changed_cb, NULL);
2529  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_CURRENCY_OTHER,
2530  gnc_currency_changed_cb, NULL);
2531  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_CURRENCY_CHOICE_LOCALE,
2532  gnc_currency_changed_cb, NULL);
2533  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_CURRENCY_CHOICE_OTHER,
2534  gnc_currency_changed_cb, NULL);
2535  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_CURRENCY_OTHER,
2536  gnc_currency_changed_cb, NULL);
2537  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_POINT,
2538  gnc_set_auto_decimal_enabled, NULL);
2539  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_PLACES,
2540  gnc_set_auto_decimal_places, NULL);
2541 
2542 }
2543 
2544 void
2545 gnc_ui_util_remove_registered_prefs (void)
2546 {
2547  // remove the registered pref call backs above
2548  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2549  GNC_PREF_ACCOUNT_SEPARATOR,
2550  gnc_configure_account_separator, NULL);
2551  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2552  GNC_PREF_REVERSED_ACCTS_NONE,
2553  gnc_configure_reverse_balance, NULL);
2554  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2555  GNC_PREF_REVERSED_ACCTS_CREDIT,
2556  gnc_configure_reverse_balance, NULL);
2557  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2558  GNC_PREF_REVERSED_ACCTS_INC_EXP,
2559  gnc_configure_reverse_balance, NULL);
2560  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2561  GNC_PREF_CURRENCY_CHOICE_LOCALE,
2562  gnc_currency_changed_cb, NULL);
2563  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2564  GNC_PREF_CURRENCY_CHOICE_OTHER,
2565  gnc_currency_changed_cb, NULL);
2566  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2567  GNC_PREF_CURRENCY_OTHER,
2568  gnc_currency_changed_cb, NULL);
2569  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REPORT,
2570  GNC_PREF_CURRENCY_CHOICE_LOCALE,
2571  gnc_currency_changed_cb, NULL);
2572  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REPORT,
2573  GNC_PREF_CURRENCY_CHOICE_OTHER,
2574  gnc_currency_changed_cb, NULL);
2575  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REPORT,
2576  GNC_PREF_CURRENCY_OTHER,
2577  gnc_currency_changed_cb, NULL);
2578  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2579  GNC_PREF_AUTO_DECIMAL_POINT,
2580  gnc_set_auto_decimal_enabled, NULL);
2581  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2582  GNC_PREF_AUTO_DECIMAL_PLACES,
2583  gnc_set_auto_decimal_places, NULL);
2584 }
2585 
2586 static gboolean
2587 unichar_is_cntrl (gunichar uc)
2588 {
2589  if (uc < 0x20 || (uc > 0x7e && uc < 0xa0))
2590  return TRUE;
2591  else
2592  return FALSE;
2593 }
2594 
2595 gchar *
2597 {
2598  gchar *normal_text, *nt;
2599  GString *filtered;
2600  gboolean cntrl = FALSE;
2601  gboolean text_found = FALSE;
2602 
2603  if (!text)
2604  return NULL;
2605 
2606  if (!g_utf8_validate (text, -1, NULL))
2607  return NULL;
2608 
2609  normal_text = g_utf8_normalize (text, -1, G_NORMALIZE_ALL_COMPOSE);
2610 
2611  filtered = g_string_sized_new (strlen (normal_text) + 1);
2612 
2613  nt = normal_text;
2614 
2615  while (*nt)
2616  {
2617  gunichar uc = g_utf8_get_char (nt);
2618 
2619  // check for starting with control characters
2620  if (unichar_is_cntrl (uc) && !text_found)
2621  {
2622  nt = g_utf8_next_char (nt);
2623  continue;
2624  }
2625  // check for alpha, num and punctuation
2626  if (!unichar_is_cntrl (uc))
2627  {
2628  filtered = g_string_append_unichar (filtered, uc);
2629  text_found = TRUE;
2630  }
2631  // check for control characters after text
2632  if (unichar_is_cntrl (uc))
2633  cntrl = TRUE;
2634 
2635  nt = g_utf8_next_char (nt);
2636 
2637  if (cntrl) // if control characters in text replace with space
2638  {
2639  gunichar uc2 = g_utf8_get_char (nt);
2640 
2641  if (!unichar_is_cntrl (uc2))
2642  filtered = g_string_append_unichar (filtered, ' ');
2643  }
2644  cntrl = FALSE;
2645  }
2646  g_free (normal_text);
2647  return g_string_free (filtered, FALSE);
2648 }
2649 
2650 void
2651 gnc_filter_text_set_cursor_position (const gchar *incoming_text,
2652  const gchar *symbol,
2653  gint *cursor_position)
2654 {
2655  gint text_len;
2656  gint num = 0;
2657 
2658  if (*cursor_position == 0)
2659  return;
2660 
2661  if (!incoming_text || !symbol)
2662  return;
2663 
2664  if (g_strrstr (incoming_text, symbol) == NULL)
2665  return;
2666 
2667  text_len = g_utf8_strlen (incoming_text, -1);
2668 
2669  for (gint x = 0; x < text_len; x++)
2670  {
2671  gchar *temp = g_utf8_offset_to_pointer (incoming_text, x);
2672 
2673  if (g_str_has_prefix (temp, symbol))
2674  num++;
2675 
2676  if (g_strrstr (temp, symbol) == NULL)
2677  break;
2678  }
2679  *cursor_position = *cursor_position - (num * g_utf8_strlen (symbol, -1));
2680 }
2681 
2682 gchar *
2683 gnc_filter_text_for_currency_symbol (const gchar *incoming_text,
2684  const gchar *symbol)
2685 {
2686  gchar *ret_text = NULL;
2687  gchar **split;
2688 
2689  if (!incoming_text)
2690  return NULL;
2691 
2692  if (!symbol)
2693  return g_strdup (incoming_text);
2694 
2695  if (g_strrstr (incoming_text, symbol) == NULL)
2696  return g_strdup (incoming_text);
2697 
2698  split = g_strsplit (incoming_text, symbol, -1);
2699 
2700  ret_text = g_strjoinv (NULL, split);
2701 
2702  g_strfreev (split);
2703  return ret_text;
2704 }
2705 
2706 gchar *
2707 gnc_filter_text_for_currency_commodity (const gnc_commodity *comm,
2708  const gchar *incoming_text,
2709  const gchar **symbol)
2710 {
2711  if (!incoming_text)
2712  {
2713  *symbol = NULL;
2714  return NULL;
2715  }
2716 
2717  if (!gnc_commodity_is_currency (comm))
2718  {
2719  *symbol = NULL;
2720  return g_strdup (incoming_text);
2721  }
2722 
2723  if (comm)
2724  *symbol = gnc_commodity_get_nice_symbol (comm);
2725  else
2727 
2728  return gnc_filter_text_for_currency_symbol (incoming_text, *symbol);
2729 }
gchar * gnc_filter_text_for_currency_commodity(const gnc_commodity *comm, const gchar *incoming_text, const gchar **symbol)
Returns the incoming text removed of currency symbol.
Definition: gnc-ui-util.c:2707
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Set the account&#39;s type.
Definition: Account.cpp:2426
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
Truncate fractions (round toward zero)
Definition: gnc-numeric.h:153
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:362
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:510
gboolean xaccParseAmount(const char *in_str, gboolean monetary, gnc_numeric *result, char **endstr)
Parses in_str to obtain a numeric result.
Definition: gnc-ui-util.c:2154
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency...
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
gnc_commodity * gnc_locale_default_currency_nodefault(void)
Returns the default currency of the current locale, or NULL if no sensible currency could be identifi...
Definition: gnc-ui-util.c:1136
void gnc_account_append_child(Account *new_parent, Account *child)
This function will remove from the child account any pre-existing parent relationship, and will then add the account as a child of the new parent.
Definition: Account.cpp:2801
const char * gnc_print_amount_with_bidi_ltr_isolate(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
Definition: gnc-ui-util.c:1872
gchar * gnc_prefs_get_string(const gchar *group, const gchar *pref_name)
Get a string value from the preferences backend.
gint64 xaccAccountGetTaxUSCopyNumber(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4196
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.c:128
gboolean gnc_book_use_book_currency(QofBook *book)
Returns TRUE if both book-currency and default gain/loss policy KVPs exist and are valid and trading ...
Definition: gnc-ui-util.c:446
utility functions for the GnuCash UI
Expense accounts are used to denote expenses.
Definition: Account.h:146
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3279
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2701
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
Mutual Fund accounts will typically be shown in registers which show three columns: price...
Definition: Account.h:128
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
Definition: gnc-features.c:135
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
Definition: gnc-ui-util.c:1859
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
gboolean gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
Attempt to convert the denominator to an exact power of ten without rounding.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:189
stop here; the following types just aren&#39;t ready for prime time
Definition: Account.h:164
gboolean gnc_prefs_set_string(const gchar *group, const gchar *pref_name, const gchar *value)
Store a string into the preferences backend.
Definition: gnc-prefs.c:319
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
The cash account type is used to denote a shoe-box or pillowcase stuffed with * cash.
Definition: Account.h:113
gboolean xaccParseAmountPosSign(const char *in_str, gboolean monetary, gnc_numeric *result, char **endstr, gboolean skip)
Parses in_str to a gnc_numeric, with a flag to indicate whether the locale&#39;s positive sign (or in abs...
Definition: gnc-ui-util.c:2161
gnc_commodity * gnc_default_report_currency(void)
Return the default currency for use in reports, as set by the user.
Definition: gnc-ui-util.c:1230
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Get an integer value from the preferences backend.
const gchar * qof_book_get_default_gains_policy(QofBook *book)
Returns pointer to default gain/loss policy for book, if one exists in the KVP, or NULL; does not val...
Definition: qofbook.cpp:1006
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
#define VREC
split is void
Definition: Split.h:75
gnc_numeric gnc_numeric_reduce(gnc_numeric in)
Return input after reducing it by Greater Common Factor (GCF) elimination.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1425
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
Definition: gnc-ui-util.c:1197
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
Definition: Account.cpp:3083
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
Stock accounts will typically be shown in registers which show three columns: price, number of shares, and value.
Definition: Account.h:125
gchar * gnc_get_account_name_for_register(const Account *account)
Get either the full name of the account or the simple name, depending on the configuration parameter ...
Definition: gnc-ui-util.c:581
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
Definition: qofsession.cpp:578
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3308
Account handling public routines.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
Income accounts are used to denote income.
Definition: Account.h:143
#define YREC
The Split has been reconciled.
Definition: Split.h:72
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
Returns a string representation of the given GNCNumericErrorCode.
const char * gnc_get_doclink_flag_order(void)
Get a string containing document link flag order.
Definition: gnc-ui-util.c:940
#define FREC
frozen into accounting period
Definition: Split.h:73
const gchar * gnc_book_get_book_currency_name(QofBook *book)
Returns pointer to Book Currency name for book or NULL; determines that both book-currency and defaul...
Definition: gnc-ui-util.c:481
gboolean xaccParseAmountExtended(const char *in_str, gboolean monetary, gunichar negative_sign, gunichar decimal_point, gunichar group_separator, const char *ignore_list, gnc_numeric *result, char **endstr)
Converts a string to a gnc_numeric.
Definition: gnc-ui-util.c:2200
const gchar * gnc_book_get_default_gains_policy(QofBook *book)
Returns pointer to default gain/loss policy for book or NULL; determines that both book-currency and ...
Definition: gnc-ui-util.c:514
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:110
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
Definition: Account.cpp:3163
void gnc_filter_text_set_cursor_position(const gchar *incoming_text, const gchar *symbol, gint *cursor_position)
Updates cursor_position after removal of currency symbols.
Definition: gnc-ui-util.c:2651
A/P account type.
Definition: Account.h:154
const char * gnc_commodity_get_nice_symbol(const gnc_commodity *cm)
Retrieve a symbol for the specified commodity, suitable for display to the user.
const char * xaccAccountGetTaxUSCode(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4158
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void xaccAccountSetIsOpeningBalance(Account *acc, gboolean val)
Set the "opening-balance" flag for an account.
Definition: Account.cpp:4302
gnc_commodity * gnc_book_get_book_currency(QofBook *book)
Returns pointer to Book Currency for book or NULL; determines that both book-currency and default gai...
Definition: gnc-ui-util.c:496
gchar * gnc_filter_text_for_currency_symbol(const gchar *incoming_text, const gchar *symbol)
Returns the incoming text removed of a currency symbol.
Definition: gnc-ui-util.c:2683
gboolean xaccAccountGetTaxRelated(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4146
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
asset (and liability) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:119
All type declarations for the whole Gnucash engine.
#define CREC
The Split has been cleared.
Definition: Split.h:71
int xaccSPrintAmount(char *bufp, gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
Definition: gnc-ui-util.c:1728
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Definition: Account.h:105
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: Account.cpp:3455
gboolean xaccAccountGetHidden(const Account *acc)
Get the "hidden" flag for an account.
Definition: Account.cpp:4351
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
gchar * gnc_get_account_name_for_split_register(const Account *account, gboolean show_leaf_accounts)
Get either the full name of the account or the simple name, depending on the show_leaf_accounts.
Definition: gnc-ui-util.c:572
Account * gnc_book_get_default_gain_loss_acct(QofBook *book)
Returns pointer to default gain/loss account for book or NULL; determines that both book-currency and...
Definition: gnc-ui-util.c:530
Generic api to store and retrieve preferences.
Never round at all, and signal an error if there is a fractional result in a computation.
Definition: gnc-numeric.h:178
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition: Account.cpp:3036
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: gnc-ui-util.c:1202
liability (and asset) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:122
gchar * gnc_wrap_text_with_bidi_ltr_isolate(const char *text)
This function helps with GTK&#39;s use of &#39;Unicode Bidirectional Text Algorithm&#39;.
GList * gnc_account_get_children(const Account *account)
This routine returns a GList of all children accounts of the specified account.
Definition: Account.cpp:2930
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1449
const gchar * qof_book_get_book_currency_name(QofBook *book)
Returns pointer to book-currency name for book, if one exists in the KVP, or NULL; does not validate ...
Definition: qofbook.cpp:991
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
GncGUID * qof_book_get_default_gain_loss_acct_guid(QofBook *book)
Returns pointer to default gain/loss account GUID for book, if one exists in the KVP, or NULL; does not validate contents nor determine if there is a valid book-currency, both of which are required, for the &#39;book-currency&#39; currency accounting method to apply.
Definition: qofbook.cpp:1021
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4262
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
gchar * gnc_filter_text_for_control_chars(const gchar *text)
Returns the incoming text removed of control characters.
Definition: gnc-ui-util.c:2596
A/R account type.
Definition: Account.h:152
gboolean gnc_valid_policy_name(const gchar *policy_name)
Valid Policy Name Uses the Valid Policy List to determine if a policy name is valid.
Definition: policy.c:80
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition: Account.cpp:1228
const char * gnc_get_doclink_str(char link_flag)
Get a string representing the document link type.
Definition: gnc-ui-util.c:916
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
const char * gnc_get_doclink_valid_flags(void)
Get a string containing documentation link valid flags.
Definition: gnc-ui-util.c:933
Account * gnc_account_get_root(Account *acc)
This routine returns the root account of the account tree that the specified account belongs to...
Definition: Account.cpp:2906
Account * gnc_account_lookup_by_opening_balance(Account *account, gnc_commodity *commodity)
Find the opening balance account for the currency.
Definition: Account.cpp:3111
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3301
Equity account is used to balance the balance sheet.
Definition: Account.h:149
Account * gnc_account_lookup_for_register(const Account *base_account, const gchar *name)
Retrieve the account matching the given name starting from the descendants of base_account.
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
gboolean qof_book_use_trading_accounts(const QofBook *book)
Returns flag indicating whether this book uses trading accounts.
Definition: qofbook.cpp:1033
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1490
gnc_commodity * gnc_locale_default_currency(void)
Returns the default currency of the current locale.
Definition: gnc-ui-util.c:1151
void xaccAccountSetName(Account *acc, const char *str)
Set the account&#39;s name.
Definition: Account.cpp:2447
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency.
The Credit card account is used to denote credit (e.g.
Definition: Account.h:116
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account&#39;s commodity.
Definition: Account.cpp:2632
#define NREC
not reconciled or cleared
Definition: Split.h:74
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143
Utility functions for file access.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2050