GnuCash 2.4.99
Split.c
00001 /********************************************************************\
00002  * Split.c -- split implementation                                  *
00003  * Copyright (C) 1997 Robin D. Clark                                *
00004  * Copyright (C) 1997-2003 Linas Vepstas <linas@linas.org>          *
00005  * Copyright (C) 2000 Bill Gribble <grib@billgribble.com>           *
00006  * Copyright (c) 2006 David Hampton <hampton@employees.org>         *
00007  *                                                                  *
00008  * This program is free software; you can redistribute it and/or    *
00009  * modify it under the terms of the GNU General Public License as   *
00010  * published by the Free Software Foundation; either version 2 of   *
00011  * the License, or (at your option) any later version.              *
00012  *                                                                  *
00013  * This program is distributed in the hope that it will be useful,  *
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00016  * GNU General Public License for more details.                     *
00017  *                                                                  *
00018  * You should have received a copy of the GNU General Public License*
00019  * along with this program; if not, contact:                        *
00020  *                                                                  *
00021  * Free Software Foundation           Voice:  +1-617-542-5942       *
00022  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00023  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00024  *                                                                  *
00025 \********************************************************************/
00026 
00027 #include "config.h"
00028 
00029 #include <glib.h>
00030 #include <glib/gi18n.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #ifdef HAVE_SYS_TIME_H
00034 # include <sys/time.h>
00035 #endif
00036 #include <time.h>
00037 #ifdef HAVE_UNISTD_H
00038 # include <unistd.h>
00039 #endif
00040 
00041 #include "qof.h"
00042 #include "Split.h"
00043 #include "AccountP.h"
00044 #include "Scrub.h"
00045 #include "Scrub3.h"
00046 #include "TransactionP.h"
00047 #include "TransLog.h"
00048 #include "cap-gains.h"
00049 #include "gnc-commodity.h"
00050 #include "gnc-engine.h"
00051 #include "gnc-lot.h"
00052 #include "gnc-event.h"
00053 
00054 const char *void_former_amt_str = "void-former-amount";
00055 const char *void_former_val_str = "void-former-value";
00056 
00057 #define PRICE_SIGFIGS 6
00058 
00059 /* This static indicates the debugging module that this .o belongs to.  */
00060 static QofLogModule log_module = GNC_MOD_ENGINE;
00061 
00062 enum
00063 {
00064     PROP_0,
00065     PROP_ACTION,
00066     PROP_MEMO,
00067     PROP_VALUE,
00068     PROP_AMOUNT,
00069     PROP_RECONCILE_DATE,
00070     PROP_TX,
00071     PROP_ACCOUNT,
00072     PROP_LOT
00073 };
00074 
00075 /* GObject Initialization */
00076 G_DEFINE_TYPE(Split, gnc_split, QOF_TYPE_INSTANCE)
00077 
00078 static void
00079 gnc_split_init(Split* split)
00080 {
00081     /* fill in some sane defaults */
00082     split->acc         = NULL;
00083     split->orig_acc    = NULL;
00084     split->parent      = NULL;
00085     split->lot         = NULL;
00086 
00087     split->action      = CACHE_INSERT("");
00088     split->memo        = CACHE_INSERT("");
00089     split->reconciled  = NREC;
00090     split->amount      = gnc_numeric_zero();
00091     split->value       = gnc_numeric_zero();
00092 
00093     split->date_reconciled.tv_sec  = 0;
00094     split->date_reconciled.tv_nsec = 0;
00095 
00096     split->balance             = gnc_numeric_zero();
00097     split->cleared_balance     = gnc_numeric_zero();
00098     split->reconciled_balance  = gnc_numeric_zero();
00099 
00100     split->gains = GAINS_STATUS_UNKNOWN;
00101     split->gains_split = NULL;
00102 }
00103 
00104 static void
00105 gnc_split_dispose(GObject *splitp)
00106 {
00107     G_OBJECT_CLASS(gnc_split_parent_class)->dispose(splitp);
00108 }
00109 
00110 static void
00111 gnc_split_finalize(GObject* splitp)
00112 {
00113     G_OBJECT_CLASS(gnc_split_parent_class)->finalize(splitp);
00114 }
00115 
00116 static void
00117 gnc_split_get_property(GObject         *object,
00118                        guint            prop_id,
00119                        GValue          *value,
00120                        GParamSpec      *pspec)
00121 {
00122     Split *split;
00123 
00124     g_return_if_fail(GNC_IS_SPLIT(object));
00125 
00126     split = GNC_SPLIT(object);
00127     switch (prop_id)
00128     {
00129     case PROP_ACTION:
00130         g_value_set_string(value, split->action);
00131         break;
00132     case PROP_MEMO:
00133         g_value_set_string(value, split->memo);
00134         break;
00135     case PROP_VALUE:
00136         g_value_set_boxed(value, &split->value);
00137         break;
00138     case PROP_AMOUNT:
00139         g_value_set_boxed(value, &split->amount);
00140         break;
00141     case PROP_RECONCILE_DATE:
00142         g_value_set_boxed(value, &split->date_reconciled);
00143         break;
00144     case PROP_TX:
00145         g_value_set_object(value, split->parent);
00146         break;
00147     case PROP_ACCOUNT:
00148         g_value_set_object(value, split->acc);
00149         break;
00150     case PROP_LOT:
00151         g_value_set_object(value, split->lot);
00152         break;
00153     default:
00154         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
00155         break;
00156     }
00157 }
00158 
00159 static void
00160 gnc_split_set_property(GObject         *object,
00161                        guint            prop_id,
00162                        const GValue     *value,
00163                        GParamSpec      *pspec)
00164 {
00165     Split *split;
00166     gnc_numeric* number;
00167 
00168     g_return_if_fail(GNC_IS_SPLIT(object));
00169 
00170     split = GNC_SPLIT(object);
00171     switch (prop_id)
00172     {
00173     case PROP_ACTION:
00174         xaccSplitSetAction(split, g_value_get_string(value));
00175         break;
00176     case PROP_MEMO:
00177         xaccSplitSetMemo(split, g_value_get_string(value));
00178         break;
00179     case PROP_VALUE:
00180         number = g_value_get_boxed(value);
00181         xaccSplitSetValue(split, *number);
00182         break;
00183     case PROP_AMOUNT:
00184         number = g_value_get_boxed(value);
00185         xaccSplitSetAmount(split, *number);
00186         break;
00187     case PROP_RECONCILE_DATE:
00188         xaccSplitSetDateReconciledTS(split, g_value_get_boxed(value));
00189         break;
00190     case PROP_TX:
00191         xaccSplitSetParent(split, g_value_get_object(value));
00192         break;
00193     case PROP_ACCOUNT:
00194         xaccSplitSetAccount(split, g_value_get_object(value));
00195         break;
00196     case PROP_LOT:
00197         xaccSplitSetLot(split, g_value_get_object(value));
00198         break;
00199     default:
00200         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
00201         break;
00202     }
00203 }
00204 
00205 static void
00206 gnc_split_class_init(SplitClass* klass)
00207 {
00208     GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
00209 
00210     gobject_class->dispose = gnc_split_dispose;
00211     gobject_class->finalize = gnc_split_finalize;
00212     gobject_class->set_property = gnc_split_set_property;
00213     gobject_class->get_property = gnc_split_get_property;
00214 
00215     g_object_class_install_property
00216     (gobject_class,
00217      PROP_ACTION,
00218      g_param_spec_string("action",
00219                          "Action",
00220                          "The action is an arbitrary string assigned "
00221                          "by the user.  It is intended to be a short "
00222                          "string that contains extra information about "
00223                          "this split.",
00224                          NULL,
00225                          G_PARAM_READWRITE));
00226 
00227     g_object_class_install_property
00228     (gobject_class,
00229      PROP_MEMO,
00230      g_param_spec_string("memo",
00231                          "Memo",
00232                          "The action is an arbitrary string assigned "
00233                          "by the user.  It is intended to be a short "
00234                          "string that describes the purpose of "
00235                          "this split.",
00236                          NULL,
00237                          G_PARAM_READWRITE));
00238 
00239     g_object_class_install_property
00240     (gobject_class,
00241      PROP_VALUE,
00242      g_param_spec_boxed("value",
00243                         "Split Value",
00244                         "The value for this split in the common currency. "
00245                         "The value and the amount provide enough information to "
00246                         "calculate a conversion rate.",
00247                         GNC_TYPE_NUMERIC,
00248                         G_PARAM_READWRITE));
00249 
00250     g_object_class_install_property
00251     (gobject_class,
00252      PROP_AMOUNT,
00253      g_param_spec_boxed("amount",
00254                         "Split Amount",
00255                         "The value for this split in the currency of its account. "
00256                         "The value and the amount provide enough information to "
00257                         "calculate a conversion rate.",
00258                         GNC_TYPE_NUMERIC,
00259                         G_PARAM_READWRITE));
00260 
00261     g_object_class_install_property
00262     (gobject_class,
00263      PROP_RECONCILE_DATE,
00264      g_param_spec_boxed("reconcile-date",
00265                         "Reconcile Date",
00266                         "The date this split was reconciled.",
00267                         GNC_TYPE_TIMESPEC,
00268                         G_PARAM_READWRITE));
00269 
00270     g_object_class_install_property
00271     (gobject_class,
00272      PROP_TX,
00273      g_param_spec_object ("transaction",
00274                           "Transaction",
00275                           "The transaction that this split belongs to.",
00276                           GNC_TYPE_TRANSACTION,
00277                           G_PARAM_READWRITE));
00278 
00279     g_object_class_install_property
00280     (gobject_class,
00281      PROP_ACCOUNT,
00282      g_param_spec_object ("account",
00283                           "Account",
00284                           "The account that this split belongs to.",
00285                           GNC_TYPE_ACCOUNT,
00286                           G_PARAM_READWRITE));
00287 
00288     g_object_class_install_property
00289     (gobject_class,
00290      PROP_LOT,
00291      g_param_spec_object ("lot",
00292                           "Lot",
00293                           "The lot that this split belongs to.",
00294                           GNC_TYPE_LOT,
00295                           G_PARAM_READWRITE));
00296 }
00297 
00298 /********************************************************************\
00299  * xaccInitSplit
00300  * Initialize a Split structure
00301 \********************************************************************/
00302 
00303 static void
00304 xaccInitSplit(Split * split, QofBook *book)
00305 {
00306     qof_instance_init_data(&split->inst, GNC_ID_SPLIT, book);
00307 }
00308 
00309 void
00310 xaccSplitReinit(Split * split)
00311 {
00312     /* fill in some sane defaults */
00313     split->acc         = NULL;
00314     split->orig_acc    = NULL;
00315     split->parent      = NULL;
00316     split->lot         = NULL;
00317 
00318     CACHE_REPLACE(split->action, "");
00319     CACHE_REPLACE(split->memo, "");
00320     split->reconciled  = NREC;
00321     split->amount      = gnc_numeric_zero();
00322     split->value       = gnc_numeric_zero();
00323 
00324     split->date_reconciled.tv_sec  = 0;
00325     split->date_reconciled.tv_nsec = 0;
00326 
00327     split->balance             = gnc_numeric_zero();
00328     split->cleared_balance     = gnc_numeric_zero();
00329     split->reconciled_balance  = gnc_numeric_zero();
00330 
00331     if (split->inst.kvp_data)
00332         kvp_frame_delete(split->inst.kvp_data);
00333     split->inst.kvp_data = kvp_frame_new();
00334     qof_instance_set_idata(split, 0);
00335 
00336     split->gains = GAINS_STATUS_UNKNOWN;
00337     split->gains_split = NULL;
00338 }
00339 
00340 /********************************************************************\
00341 \********************************************************************/
00342 
00343 Split *
00344 xaccMallocSplit(QofBook *book)
00345 {
00346     Split *split;
00347     g_return_val_if_fail (book, NULL);
00348 
00349     split = g_object_new (GNC_TYPE_SPLIT, NULL);
00350     xaccInitSplit (split, book);
00351 
00352     return split;
00353 }
00354 
00355 /********************************************************************\
00356 \********************************************************************/
00357 /* This routine is not exposed externally, since it does weird things,
00358  * like not really setting up the parent account correctly, and ditto
00359  * the parent transaction.  This routine is prone to programmer error
00360  * if not used correctly.  It is used only by the edit-rollback code.
00361  * Don't get duped!
00362  */
00363 
00364 Split *
00365 xaccDupeSplit (const Split *s)
00366 {
00367     Split *split = g_object_new (GNC_TYPE_SPLIT, NULL);
00368 
00369     /* Trash the entity table. We don't want to mistake the cloned
00370      * splits as something official.  If we ever use this split, we'll
00371      * have to fix this up.
00372      */
00373     split->inst.e_type = NULL;
00374     qof_instance_copy_guid(split, s);
00375     qof_instance_copy_book(split, s);
00376 
00377     split->parent = s->parent;
00378     split->acc = s->acc;
00379     split->orig_acc = s->orig_acc;
00380     split->lot = s->lot;
00381 
00382     split->memo = CACHE_INSERT(s->memo);
00383     split->action = CACHE_INSERT(s->action);
00384 
00385     split->inst.kvp_data = kvp_frame_copy (s->inst.kvp_data);
00386 
00387     split->reconciled = s->reconciled;
00388     split->date_reconciled = s->date_reconciled;
00389 
00390     split->value = s->value;
00391     split->amount = s->amount;
00392 
00393     /* no need to futz with the balances;  these get wiped each time ...
00394      * split->balance             = s->balance;
00395      * split->cleared_balance     = s->cleared_balance;
00396      * split->reconciled_balance  = s->reconciled_balance;
00397      */
00398 
00399     return split;
00400 }
00401 
00402 Split *
00403 xaccSplitClone (const Split *s)
00404 {
00405     Split *split = g_object_new (GNC_TYPE_SPLIT, NULL);
00406 
00407     split->parent              = NULL;
00408     split->memo                = CACHE_INSERT(s->memo);
00409     split->action              = CACHE_INSERT(s->action);
00410     split->reconciled          = s->reconciled;
00411     split->date_reconciled     = s->date_reconciled;
00412     split->value               = s->value;
00413     split->amount              = s->amount;
00414     split->balance             = s->balance;
00415     split->cleared_balance     = s->cleared_balance;
00416     split->reconciled_balance  = s->reconciled_balance;
00417 
00418     split->gains = GAINS_STATUS_UNKNOWN;
00419     split->gains_split = NULL;
00420 
00421     qof_instance_init_data(&split->inst, GNC_ID_SPLIT, qof_instance_get_book(s));
00422     kvp_frame_delete(split->inst.kvp_data);
00423     split->inst.kvp_data = kvp_frame_copy(s->inst.kvp_data);
00424 
00425     xaccAccountInsertSplit(s->acc, split);
00426     if (s->lot)
00427     {
00428         /* CHECKME: Is this right? */
00429         gnc_lot_add_split(s->lot, split);
00430     }
00431     return split;
00432 }
00433 
00434 #ifdef DUMP_FUNCTIONS
00435 void
00436 xaccSplitDump (const Split *split, const char *tag)
00437 {
00438     printf("  %s Split %p", tag, split);
00439     printf("    Book:     %p\n", qof_instance_get_book(split));
00440     printf("    Account:  %p (%s)\n", split->acc,
00441            split->acc ? xaccAccountGetName(split->acc) : "");
00442     printf("    Commod:   %s\n",
00443            split->acc ?
00444            gnc_commodity_get_printname(xaccAccountGetCommodity(split->acc))
00445            : "");
00446     printf("    Lot:      %p\n", split->lot);
00447     printf("    Parent:   %p\n", split->parent);
00448     printf("    Gains:    %p\n", split->gains_split);
00449     printf("    Memo:     %s\n", split->memo ? split->memo : "(null)");
00450     printf("    Action:   %s\n", split->action ? split->action : "(null)");
00451     printf("    KVP Data: %p\n", split->inst.kvp_data);
00452     printf("    Recncld:  %c (date %s)\n", split->reconciled,
00453            gnc_print_date(split->date_reconciled));
00454     printf("    Value:    %s\n", gnc_numeric_to_string(split->value));
00455     printf("    Amount:   %s\n", gnc_numeric_to_string(split->amount));
00456     printf("    Balance:  %s\n", gnc_numeric_to_string(split->balance));
00457     printf("    CBalance: %s\n", gnc_numeric_to_string(split->cleared_balance));
00458     printf("    RBalance: %s\n",
00459            gnc_numeric_to_string(split->reconciled_balance));
00460     printf("    idata:    %x\n", qof_instance_get_idata(split));
00461 }
00462 #endif
00463 
00464 /********************************************************************\
00465 \********************************************************************/
00466 
00467 void
00468 xaccFreeSplit (Split *split)
00469 {
00470     if (!split) return;
00471 
00472     /* Debug double-free's */
00473     if (((char *) 1) == split->memo)
00474     {
00475         PERR ("double-free %p", split);
00476         return;
00477     }
00478     CACHE_REMOVE(split->memo);
00479     CACHE_REMOVE(split->action);
00480 
00481     /* Just in case someone looks up freed memory ... */
00482     split->memo        = (char *) 1;
00483     split->action      = NULL;
00484     split->reconciled  = NREC;
00485     split->amount      = gnc_numeric_zero();
00486     split->value       = gnc_numeric_zero();
00487     split->parent      = NULL;
00488     split->lot         = NULL;
00489     split->acc         = NULL;
00490     split->orig_acc    = NULL;
00491 
00492     split->date_reconciled.tv_sec = 0;
00493     split->date_reconciled.tv_nsec = 0;
00494 
00495     // Is this right?
00496     if (split->gains_split) split->gains_split->gains_split = NULL;
00497     /* qof_instance_release(&split->inst); */
00498     g_object_unref(split);
00499 }
00500 
00501 void mark_split (Split *s)
00502 {
00503     if (s->acc)
00504     {
00505         g_object_set(s->acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
00506     }
00507 
00508     /* set dirty flag on lot too. */
00509     if (s->lot) gnc_lot_set_closed_unknown(s->lot);
00510 }
00511 
00512 /*
00513  * Helper routine for xaccSplitEqual.
00514  */
00515 static gboolean
00516 xaccSplitEqualCheckBal (const char *tag, gnc_numeric a, gnc_numeric b)
00517 {
00518     char *str_a, *str_b;
00519 
00520     if (gnc_numeric_equal (a, b))
00521         return TRUE;
00522 
00523     str_a = gnc_numeric_to_string (a);
00524     str_b = gnc_numeric_to_string (b);
00525 
00526     PWARN ("%sbalances differ: %s vs %s", tag, str_a, str_b);
00527 
00528     g_free (str_a);
00529     g_free (str_b);
00530 
00531     return FALSE;
00532 }
00533 
00534 /********************************************************************
00535  * xaccSplitEqual
00536  ********************************************************************/
00537 gboolean
00538 xaccSplitEqual(const Split *sa, const Split *sb,
00539                gboolean check_guids,
00540                gboolean check_balances,
00541                gboolean check_txn_splits)
00542 {
00543     gboolean same_book;
00544 
00545     if (!sa && !sb) return TRUE; /* Arguable. FALSE is better, methinks */
00546 
00547     if (!sa || !sb)
00548     {
00549         PWARN ("one is NULL");
00550         return FALSE;
00551     }
00552 
00553     if (sa == sb) return TRUE;
00554 
00555     same_book = qof_instance_get_book(QOF_INSTANCE(sa)) == qof_instance_get_book(QOF_INSTANCE(sb));
00556 
00557     if (check_guids)
00558     {
00559         if (qof_instance_guid_compare(sa, sb) != 0)
00560         {
00561             PWARN ("GUIDs differ");
00562             return FALSE;
00563         }
00564     }
00565 
00566     /* If the same book, since these strings are cached we can just use pointer equality */
00567     if ((same_book && sa->memo != sb->memo) || (!same_book && safe_strcmp(sa->memo, sb->memo) != 0))
00568     {
00569         PWARN ("memos differ: (%p)%s vs (%p)%s",
00570                sa->memo, sa->memo, sb->memo, sb->memo);
00571         return FALSE;
00572     }
00573 
00574     if ((same_book && sa->action != sb->action) || (!same_book && safe_strcmp(sa->action, sb->action) != 0))
00575     {
00576         PWARN ("actions differ: %s vs %s", sa->action, sb->action);
00577         return FALSE;
00578     }
00579 
00580     if (kvp_frame_compare(sa->inst.kvp_data, sb->inst.kvp_data) != 0)
00581     {
00582         char *frame_a;
00583         char *frame_b;
00584 
00585         frame_a = kvp_frame_to_string (sa->inst.kvp_data);
00586         frame_b = kvp_frame_to_string (sb->inst.kvp_data);
00587 
00588         PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
00589 
00590         g_free (frame_a);
00591         g_free (frame_b);
00592 
00593         return FALSE;
00594     }
00595 
00596     if (sa->reconciled != sb->reconciled)
00597     {
00598         PWARN ("reconcile flags differ: %c vs %c", sa->reconciled, sb->reconciled);
00599         return FALSE;
00600     }
00601 
00602     if (timespec_cmp(&(sa->date_reconciled), &(sb->date_reconciled)))
00603     {
00604         PWARN ("reconciled date differs");
00605         return FALSE;
00606     }
00607 
00608     if (!gnc_numeric_eq(xaccSplitGetAmount (sa), xaccSplitGetAmount (sb)))
00609     {
00610         char *str_a;
00611         char *str_b;
00612 
00613         str_a = gnc_numeric_to_string (xaccSplitGetAmount (sa));
00614         str_b = gnc_numeric_to_string (xaccSplitGetAmount (sb));
00615 
00616         PWARN ("amounts differ: %s vs %s", str_a, str_b);
00617 
00618         g_free (str_a);
00619         g_free (str_b);
00620 
00621         return FALSE;
00622     }
00623 
00624     if (!gnc_numeric_eq(xaccSplitGetValue (sa), xaccSplitGetValue (sb)))
00625     {
00626         char *str_a;
00627         char *str_b;
00628 
00629         str_a = gnc_numeric_to_string (xaccSplitGetValue (sa));
00630         str_b = gnc_numeric_to_string (xaccSplitGetValue (sb));
00631 
00632         PWARN ("values differ: %s vs %s", str_a, str_b);
00633 
00634         g_free (str_a);
00635         g_free (str_b);
00636 
00637         return FALSE;
00638     }
00639 
00640     if (check_balances)
00641     {
00642         if (!xaccSplitEqualCheckBal ("", sa->balance, sb->balance))
00643             return FALSE;
00644         if (!xaccSplitEqualCheckBal ("cleared ", sa->cleared_balance,
00645                                      sb->cleared_balance))
00646             return FALSE;
00647         if (!xaccSplitEqualCheckBal ("reconciled ", sa->reconciled_balance,
00648                                      sb->reconciled_balance))
00649             return FALSE;
00650     }
00651 
00652     if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits,
00653                         check_balances, FALSE))
00654     {
00655         PWARN ("transactions differ");
00656         return FALSE;
00657     }
00658 
00659     return TRUE;
00660 }
00661 
00662 /********************************************************************
00663  * Account funcs
00664  ********************************************************************/
00665 
00666 Account *
00667 xaccSplitGetAccount (const Split *s)
00668 {
00669     return s ? s->acc : NULL;
00670 }
00671 
00672 void
00673 xaccSplitSetAccount (Split *s, Account *acc)
00674 {
00675     Transaction *trans;
00676 
00677     g_return_if_fail(s && acc);
00678     g_return_if_fail(qof_instance_books_equal(acc, s));
00679 
00680     trans = s->parent;
00681     if (trans)
00682         xaccTransBeginEdit(trans);
00683 
00684     s->acc = acc;
00685     qof_instance_set_dirty(QOF_INSTANCE(s));
00686 
00687     if (trans)
00688         xaccTransCommitEdit(trans);
00689 }
00690 
00691 static void commit_err (QofInstance *inst, QofBackendError errcode)
00692 {
00693     PERR("commit error: %d", errcode);
00694     gnc_engine_signal_commit_error( errcode );
00695 }
00696 
00697 /* An engine-private helper for completing xaccTransCommitEdit(). */
00698 void
00699 xaccSplitCommitEdit(Split *s)
00700 {
00701     Account *acc = NULL;
00702     Account *orig_acc = NULL;
00703 
00704     g_return_if_fail(s);
00705     if (!qof_instance_is_dirty(QOF_INSTANCE(s)))
00706         return;
00707 
00708     orig_acc = s->orig_acc;
00709 
00710     if (GNC_IS_ACCOUNT(s->acc))
00711         acc = s->acc;
00712 
00713     /* Remove from lot (but only if it hasn't been moved to
00714        new lot already) */
00715     if (s->lot && (gnc_lot_get_account(s->lot) != acc || qof_instance_get_destroying(s)))
00716         gnc_lot_remove_split (s->lot, s);
00717 
00718     /* Possibly remove the split from the original account... */
00719     if (orig_acc && (orig_acc != acc || qof_instance_get_destroying(s)))
00720     {
00721         if (!gnc_account_remove_split(orig_acc, s))
00722         {
00723             PERR("Account lost track of moved or deleted split.");
00724         }
00725     }
00726 
00727     /* ... and insert it into the new account if needed */
00728     if (acc && (orig_acc != acc) && !qof_instance_get_destroying(s))
00729     {
00730         if (gnc_account_insert_split(acc, s))
00731         {
00732             /* If the split's lot belonged to some other account, we
00733                leave it so. */
00734             if (s->lot && (NULL == gnc_lot_get_account(s->lot)))
00735                 xaccAccountInsertLot (acc, s->lot);
00736         }
00737         else
00738         {
00739             PERR("Account grabbed split prematurely.");
00740         }
00741         xaccSplitSetAmount(s, xaccSplitGetAmount(s));
00742     }
00743 
00744     if (s->parent != s->orig_parent)
00745     {
00746         //FIXME: find better event
00747         if (s->orig_parent)
00748             qof_event_gen(&s->orig_parent->inst, QOF_EVENT_MODIFY,
00749                           NULL);
00750     }
00751     if (s->lot)
00752     {
00753         /* A change of value/amnt affects gains display, etc. */
00754         qof_event_gen (QOF_INSTANCE(s->lot), QOF_EVENT_MODIFY, NULL);
00755     }
00756 
00757     /* Important: we save off the original parent transaction and account
00758        so that when we commit, we can generate signals for both the
00759        original and new transactions, for the _next_ begin/commit cycle. */
00760     s->orig_acc = s->acc;
00761     s->orig_parent = s->parent;
00762     if (!qof_commit_edit_part2(QOF_INSTANCE(s), commit_err, NULL,
00763                                (void (*) (QofInstance *)) xaccFreeSplit))
00764         return;
00765 
00766     if (acc)
00767     {
00768         g_object_set(acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
00769         xaccAccountRecomputeBalance(acc);
00770     }
00771 }
00772 
00773 /* An engine-private helper for completing xaccTransRollbackEdit(). */
00774 void
00775 xaccSplitRollbackEdit(Split *s)
00776 {
00777 
00778     /* Don't use setters because we want to allow NULL.  This is legit
00779        only because we don't emit events for changing accounts until
00780        the final commit. */
00781     if (s->acc != s->orig_acc)
00782         s->acc = s->orig_acc;
00783 
00784     /* Undestroy if needed */
00785     if (qof_instance_get_destroying(s) && s->parent)
00786     {
00787         GncEventData ed;
00788         qof_instance_set_destroying(s, FALSE);
00789         ed.node = s;
00790         ed.idx = -1; /* unused */
00791         qof_event_gen(&s->parent->inst, GNC_EVENT_ITEM_ADDED, &ed);
00792     }
00793 
00794     /* But for the parent trans, we want the intermediate events, so
00795        we use the setter. */
00796     xaccSplitSetParent(s, s->orig_parent);
00797 }
00798 
00799 /********************************************************************\
00800 \********************************************************************/
00801 
00802 Split *
00803 xaccSplitLookup (const GncGUID *guid, QofBook *book)
00804 {
00805     QofCollection *col;
00806     if (!guid || !book) return NULL;
00807     col = qof_book_get_collection (book, GNC_ID_SPLIT);
00808     return (Split *) qof_collection_lookup_entity (col, guid);
00809 }
00810 
00811 /********************************************************************\
00812 \********************************************************************/
00813 /* Routines for marking splits dirty, and for sending out change
00814  * events.  Note that we can't just mark-n-generate-event in one
00815  * step, since sometimes we need to mark things up before its suitable
00816  * to send out a change event.
00817  */
00818 
00819 /* CHECKME: This function modifies the Split without dirtying or
00820    checking its parent.  Is that correct? */
00821 void
00822 xaccSplitDetermineGainStatus (Split *split)
00823 {
00824     Split *other;
00825     KvpValue *val;
00826 
00827     if (GAINS_STATUS_UNKNOWN != split->gains) return;
00828 
00829     other = xaccSplitGetCapGainsSplit (split);
00830     if (other)
00831     {
00832         split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
00833         split->gains_split = other;
00834         return;
00835     }
00836 
00837     val = kvp_frame_get_slot (split->inst.kvp_data, "gains-source");
00838     if (!val)
00839     {
00840         // CHECKME: We leave split->gains_split alone.  Is that correct?
00841         split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY;
00842     }
00843     else
00844     {
00845         QofCollection *col;
00846         col = qof_book_get_collection (qof_instance_get_book(split), GNC_ID_SPLIT);
00847         split->gains = GAINS_STATUS_GAINS;
00848         other = (Split *) qof_collection_lookup_entity (col,
00849                 kvp_value_get_guid (val));
00850         split->gains_split = other;
00851     }
00852 }
00853 
00854 /********************************************************************\
00855 \********************************************************************/
00856 
00857 static inline int
00858 get_currency_denom(const Split * s)
00859 {
00860     if (!s)
00861     {
00862         return 0;
00863     }
00864     else if (!s->parent || !s->parent->common_currency)
00865     {
00866         return 100000;
00867     }
00868     else
00869     {
00870         return gnc_commodity_get_fraction (s->parent->common_currency);
00871     }
00872 }
00873 
00874 static inline int
00875 get_commodity_denom(const Split * s)
00876 {
00877     if (!s)
00878     {
00879         return 0;
00880     }
00881     else if (!s->acc)
00882     {
00883         return 100000;
00884     }
00885     else
00886     {
00887         return xaccAccountGetCommoditySCU(s->acc);
00888     }
00889 }
00890 
00891 /********************************************************************
00892  * xaccSplitGetSlots
00893  ********************************************************************/
00894 
00895 KvpFrame *
00896 xaccSplitGetSlots (const Split * s)
00897 {
00898     return qof_instance_get_slots(QOF_INSTANCE(s));
00899 }
00900 /* Used for testing only: _get_random_split in test-engine-stuff.c */
00901 void
00902 xaccSplitSetSlots_nc(Split *s, KvpFrame *frm)
00903 {
00904     if (!s || !frm) return;
00905     xaccTransBeginEdit(s->parent);
00906     qof_instance_set_slots(QOF_INSTANCE(s), frm);
00907     xaccTransCommitEdit(s->parent);
00908 
00909 }
00910 
00911 /********************************************************************\
00912 \********************************************************************/
00913 
00914 void
00915 xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)
00916 {
00917     if (!s) return;
00918     ENTER (" ");
00919     xaccTransBeginEdit (s->parent);
00920 
00921     s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
00922                                     GNC_HOW_RND_ROUND_HALF_UP);
00923     s->value  = gnc_numeric_mul(s->amount, price,
00924                                 get_currency_denom(s), GNC_HOW_RND_ROUND_HALF_UP);
00925 
00926     SET_GAINS_A_VDIRTY(s);
00927     mark_split (s);
00928     qof_instance_set_dirty(QOF_INSTANCE(s));
00929     xaccTransCommitEdit(s->parent);
00930     LEAVE ("");
00931 }
00932 
00933 static void
00934 qofSplitSetSharePrice (Split *split, gnc_numeric price)
00935 {
00936     g_return_if_fail(split);
00937     split->value = gnc_numeric_mul(xaccSplitGetAmount(split),
00938                                    price, get_currency_denom(split),
00939                                    GNC_HOW_RND_ROUND_HALF_UP);
00940 }
00941 
00942 void
00943 xaccSplitSetSharePrice (Split *s, gnc_numeric price)
00944 {
00945     if (!s) return;
00946     ENTER (" ");
00947     xaccTransBeginEdit (s->parent);
00948 
00949     s->value = gnc_numeric_mul(xaccSplitGetAmount(s),
00950                                price, get_currency_denom(s),
00951                                GNC_HOW_RND_ROUND_HALF_UP);
00952 
00953     SET_GAINS_VDIRTY(s);
00954     mark_split (s);
00955     qof_instance_set_dirty(QOF_INSTANCE(s));
00956     xaccTransCommitEdit(s->parent);
00957     LEAVE ("");
00958 }
00959 
00960 static void
00961 qofSplitSetAmount (Split *split, gnc_numeric amt)
00962 {
00963     g_return_if_fail(split);
00964     if (split->acc)
00965     {
00966         split->amount = gnc_numeric_convert(amt,
00967                                             get_commodity_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
00968     }
00969     else
00970     {
00971         split->amount = amt;
00972     }
00973 }
00974 
00975 /* The amount of the split in the _account's_ commodity. */
00976 void
00977 xaccSplitSetAmount (Split *s, gnc_numeric amt)
00978 {
00979     if (!s) return;
00980     g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
00981     ENTER ("(split=%p) old amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
00982            " new amt=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
00983            s->amount.num, s->amount.denom, amt.num, amt.denom);
00984 
00985     xaccTransBeginEdit (s->parent);
00986     if (s->acc)
00987         s->amount = gnc_numeric_convert(amt, get_commodity_denom(s),
00988                                         GNC_HOW_RND_ROUND_HALF_UP);
00989     else
00990         s->amount = amt;
00991 
00992     SET_GAINS_ADIRTY(s);
00993     mark_split (s);
00994     qof_instance_set_dirty(QOF_INSTANCE(s));
00995     xaccTransCommitEdit(s->parent);
00996     LEAVE("");
00997 }
00998 
00999 static void
01000 qofSplitSetValue (Split *split, gnc_numeric amt)
01001 {
01002     g_return_if_fail(split);
01003     split->value = gnc_numeric_convert(amt,
01004                                        get_currency_denom(split), GNC_HOW_RND_ROUND_HALF_UP);
01005 }
01006 
01007 /* The value of the split in the _transaction's_ currency. */
01008 void
01009 xaccSplitSetValue (Split *s, gnc_numeric amt)
01010 {
01011     gnc_numeric new_val;
01012     if (!s) return;
01013 
01014     g_return_if_fail(gnc_numeric_check(amt) == GNC_ERROR_OK);
01015     ENTER ("(split=%p) old val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT
01016            " new val=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, s,
01017            s->value.num, s->value.denom, amt.num, amt.denom);
01018 
01019     xaccTransBeginEdit (s->parent);
01020     new_val = gnc_numeric_convert(amt, get_currency_denom(s),
01021                                   GNC_HOW_RND_ROUND_HALF_UP);
01022     if (gnc_numeric_check(new_val) == GNC_ERROR_OK)
01023         s->value = new_val;
01024     else PERR("numeric error in converting the split value's denominator");
01025 
01026     SET_GAINS_VDIRTY(s);
01027     mark_split (s);
01028     qof_instance_set_dirty(QOF_INSTANCE(s));
01029     xaccTransCommitEdit(s->parent);
01030     LEAVE ("");
01031 }
01032 
01033 /********************************************************************\
01034 \********************************************************************/
01035 
01036 gnc_numeric
01037 xaccSplitGetBalance (const Split *s)
01038 {
01039     return s ? s->balance : gnc_numeric_zero();
01040 }
01041 
01042 gnc_numeric
01043 xaccSplitGetClearedBalance (const Split *s)
01044 {
01045     return s ? s->cleared_balance : gnc_numeric_zero();
01046 }
01047 
01048 gnc_numeric
01049 xaccSplitGetReconciledBalance (const Split *s)
01050 {
01051     return s ? s->reconciled_balance : gnc_numeric_zero();
01052 }
01053 
01054 void
01055 xaccSplitSetBaseValue (Split *s, gnc_numeric value,
01056                        const gnc_commodity * base_currency)
01057 {
01058     const gnc_commodity *currency;
01059     const gnc_commodity *commodity;
01060 
01061     if (!s) return;
01062     xaccTransBeginEdit (s->parent);
01063 
01064     if (!s->acc)
01065     {
01066         PERR ("split must have a parent account");
01067         return;
01068     }
01069 
01070     currency = xaccTransGetCurrency (s->parent);
01071     commodity = xaccAccountGetCommodity (s->acc);
01072 
01073     /* If the base_currency is the transaction's commodity ('currency'),
01074      * set the value.  If it's the account commodity, set the
01075      * amount. If both, set both. */
01076     if (gnc_commodity_equiv(currency, base_currency))
01077     {
01078         if (gnc_commodity_equiv(commodity, base_currency))
01079         {
01080             s->amount = gnc_numeric_convert(value,
01081                                             get_commodity_denom(s),
01082                                             GNC_HOW_RND_ROUND_HALF_UP);
01083         }
01084         s->value = gnc_numeric_convert(value,
01085                                        get_currency_denom(s),
01086                                        GNC_HOW_RND_ROUND_HALF_UP);
01087     }
01088     else if (gnc_commodity_equiv(commodity, base_currency))
01089     {
01090         s->amount = gnc_numeric_convert(value, get_commodity_denom(s),
01091                                         GNC_HOW_RND_ROUND_HALF_UP);
01092     }
01093     else
01094     {
01095         PERR ("inappropriate base currency %s "
01096               "given split currency=%s and commodity=%s\n",
01097               gnc_commodity_get_printname(base_currency),
01098               gnc_commodity_get_printname(currency),
01099               gnc_commodity_get_printname(commodity));
01100         return;
01101     }
01102 
01103     SET_GAINS_A_VDIRTY(s);
01104     mark_split (s);
01105     qof_instance_set_dirty(QOF_INSTANCE(s));
01106     xaccTransCommitEdit(s->parent);
01107 }
01108 
01109 gnc_numeric
01110 xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)
01111 {
01112     if (!s || !s->acc || !s->parent) return gnc_numeric_zero();
01113 
01114     /* be more precise -- the value depends on the currency we want it
01115      * expressed in.  */
01116     if (gnc_commodity_equiv(xaccTransGetCurrency(s->parent), base_currency))
01117         return xaccSplitGetValue(s);
01118     if (gnc_commodity_equiv(xaccAccountGetCommodity(s->acc), base_currency))
01119         return xaccSplitGetAmount(s);
01120 
01121     PERR ("inappropriate base currency %s "
01122           "given split currency=%s and commodity=%s\n",
01123           gnc_commodity_get_printname(base_currency),
01124           gnc_commodity_get_printname(xaccTransGetCurrency (s->parent)),
01125           gnc_commodity_get_printname(xaccAccountGetCommodity(s->acc)));
01126     return gnc_numeric_zero();
01127 }
01128 
01129 /********************************************************************\
01130 \********************************************************************/
01131 
01132 gnc_numeric
01133 xaccSplitConvertAmount (const Split *split, const Account * account)
01134 {
01135     gnc_commodity *acc_com, *to_commodity;
01136     Transaction *txn;
01137     gnc_numeric amount, value, convrate;
01138     Account * split_acc;
01139 
01140     amount = xaccSplitGetAmount (split);
01141 
01142     /* If this split is attached to this account, OR */
01143     split_acc = xaccSplitGetAccount (split);
01144     if (split_acc == account)
01145         return amount;
01146 
01147     /* If split->account->commodity == to_commodity, return the amount */
01148     acc_com = xaccAccountGetCommodity (split_acc);
01149     to_commodity = xaccAccountGetCommodity (account);
01150     if (acc_com && gnc_commodity_equal (acc_com, to_commodity))
01151         return amount;
01152 
01153     /* Ok, this split is not for the viewed account, and the commodity
01154      * does not match.  So we need to do some conversion.
01155      *
01156      * First, we can cheat.  If this transaction is balanced and has
01157      * exactly two splits, then we can implicitly determine the exchange
01158      * rate and just return the 'other' split amount.
01159      */
01160     txn = xaccSplitGetParent (split);
01161     if (txn && xaccTransIsBalanced (txn))
01162     {
01163         const Split *osplit = xaccSplitGetOtherSplit (split);
01164 
01165         if (osplit)
01166         {
01167             gnc_commodity* split_comm =
01168                 xaccAccountGetCommodity(xaccSplitGetAccount(osplit));
01169             if (!gnc_commodity_equal(to_commodity, split_comm))
01170             {
01171                 PERR("The split's (%s) amount can't be converted from %s into %s.",
01172                      guid_to_string(xaccSplitGetGUID(osplit)),
01173                      gnc_commodity_get_mnemonic(split_comm),
01174                      gnc_commodity_get_mnemonic(to_commodity)
01175                     );
01176                 return gnc_numeric_zero();
01177             }
01178             return gnc_numeric_neg (xaccSplitGetAmount (osplit));
01179         }
01180     }
01181 
01182     /* ... otherwise, we need to compute the amount from the conversion
01183      * rate into _this account_.  So, find the split into this account,
01184      * compute the conversion rate (based on amount/value), and then multiply
01185      * this times the split value.
01186      */
01187     value = xaccSplitGetValue (split);
01188 
01189     if (gnc_numeric_zero_p (value))
01190     {
01191         return value;
01192     }
01193 
01194     convrate = xaccTransGetAccountConvRate(txn, account);
01195     return gnc_numeric_mul (value, convrate,
01196                             gnc_commodity_get_fraction (to_commodity),
01197                             GNC_HOW_RND_ROUND_HALF_UP);
01198 }
01199 
01200 /********************************************************************\
01201 \********************************************************************/
01202 
01203 gboolean
01204 xaccSplitDestroy (Split *split)
01205 {
01206     Account *acc;
01207     Transaction *trans;
01208     GncEventData ed;
01209 
01210     if (!split) return TRUE;
01211 
01212     acc = split->acc;
01213     trans = split->parent;
01214     if (acc && !qof_instance_get_destroying(acc)
01215             && xaccTransGetReadOnly(trans))
01216         return FALSE;
01217 
01218     xaccTransBeginEdit(trans);
01219     ed.node = split;
01220     ed.idx = xaccTransGetSplitIndex(trans, split);
01221     qof_instance_set_dirty(QOF_INSTANCE(split));
01222     qof_instance_set_destroying(split, TRUE);
01223     qof_event_gen(&trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
01224     xaccTransCommitEdit(trans);
01225 
01226     return TRUE;
01227 }
01228 
01229 /********************************************************************\
01230 \********************************************************************/
01231 
01232 gint
01233 xaccSplitOrder (const Split *sa, const Split *sb)
01234 {
01235     int retval;
01236     int comp;
01237     char *da, *db;
01238 
01239     if (sa == sb) return 0;
01240     /* nothing is always less than something */
01241     if (!sa) return -1;
01242     if (!sb) return +1;
01243 
01244     retval = xaccTransOrder (sa->parent, sb->parent);
01245     if (retval) return retval;
01246 
01247     /* otherwise, sort on memo strings */
01248     da = sa->memo ? sa->memo : "";
01249     db = sb->memo ? sb->memo : "";
01250     retval = g_utf8_collate (da, db);
01251     if (retval)
01252         return retval;
01253 
01254     /* otherwise, sort on action strings */
01255     da = sa->action ? sa->action : "";
01256     db = sb->action ? sb->action : "";
01257     retval = g_utf8_collate (da, db);
01258     if (retval != 0)
01259         return retval;
01260 
01261     /* the reconciled flag ... */
01262     if (sa->reconciled < sb->reconciled) return -1;
01263     if (sa->reconciled > sb->reconciled) return +1;
01264 
01265     /* compare amounts */
01266     comp = gnc_numeric_compare(xaccSplitGetAmount(sa), xaccSplitGetAmount (sb));
01267     if (comp < 0) return -1;
01268     if (comp > 0) return +1;
01269 
01270     comp = gnc_numeric_compare(xaccSplitGetValue(sa), xaccSplitGetValue (sb));
01271     if (comp < 0) return -1;
01272     if (comp > 0) return +1;
01273 
01274     /* if dates differ, return */
01275     DATE_CMP(sa, sb, date_reconciled);
01276 
01277     /* else, sort on guid - keeps sort stable. */
01278     retval = qof_instance_guid_compare(sa, sb);
01279     if (retval) return retval;
01280 
01281     return 0;
01282 }
01283 
01284 gint
01285 xaccSplitOrderDateOnly (const Split *sa, const Split *sb)
01286 {
01287     Transaction *ta, *tb;
01288 
01289     if (sa == sb) return 0;
01290     /* nothing is always less than something */
01291     if (!sa) return -1;
01292     if (!sb) return +1;
01293 
01294     ta = sa->parent;
01295     tb = sb->parent;
01296     if ( !ta && !tb ) return 0;
01297     if ( !tb ) return -1;
01298     if ( !ta ) return +1;
01299 
01300     /* if dates differ, return */
01301     DATE_CMP(ta, tb, date_posted);
01302 
01303     /* If the dates are the same, do not change the order */
01304     return -1;
01305 }
01306 
01307 static gboolean
01308 get_corr_account_split(const Split *sa, const Split **retval)
01309 {
01310 
01311     const Split *current_split;
01312     GList *node;
01313     gnc_numeric sa_value, current_value;
01314     gboolean sa_value_positive, current_value_positive, seen_one = FALSE;
01315 
01316     *retval = NULL;
01317     g_return_val_if_fail(sa, FALSE);
01318 
01319     sa_value = xaccSplitGetValue (sa);
01320     sa_value_positive = gnc_numeric_positive_p(sa_value);
01321 
01322     for (node = sa->parent->splits; node; node = node->next)
01323     {
01324         current_split = node->data;
01325         if (current_split == sa) continue;
01326 
01327         if (!xaccTransStillHasSplit(sa->parent, current_split)) continue;
01328         current_value = xaccSplitGetValue (current_split);
01329         current_value_positive = gnc_numeric_positive_p(current_value);
01330         if ((sa_value_positive && !current_value_positive) ||
01331                 (!sa_value_positive && current_value_positive))
01332         {
01333             if (seen_one)
01334             {
01335                 *retval = NULL;
01336                 return FALSE;
01337             }
01338             else
01339             {
01340                 *retval = current_split;
01341                 seen_one = TRUE;
01342             }
01343         }
01344     }
01345     return seen_one;
01346 }
01347 
01348 /* TODO: these static consts can be shared. */
01349 const char *
01350 xaccSplitGetCorrAccountName(const Split *sa)
01351 {
01352     static const char *split_const = NULL;
01353     const Split *other_split;
01354 
01355     if (!get_corr_account_split(sa, &other_split))
01356     {
01357         if (!split_const)
01358             split_const = _("-- Split Transaction --");
01359 
01360         return split_const;
01361     }
01362 
01363     return xaccAccountGetName(other_split->acc);
01364 }
01365 
01366 char *
01367 xaccSplitGetCorrAccountFullName(const Split *sa)
01368 {
01369     static const char *split_const = NULL;
01370     const Split *other_split;
01371 
01372     if (!get_corr_account_split(sa, &other_split))
01373     {
01374         if (!split_const)
01375             split_const = _("-- Split Transaction --");
01376 
01377         return g_strdup(split_const);
01378     }
01379     return gnc_account_get_full_name(other_split->acc);
01380 }
01381 
01382 const char *
01383 xaccSplitGetCorrAccountCode(const Split *sa)
01384 {
01385     static const char *split_const = NULL;
01386     const Split *other_split;
01387 
01388     if (!get_corr_account_split(sa, &other_split))
01389     {
01390         if (!split_const)
01391             /* Translators: This string has a disambiguation prefix */
01392             split_const = Q_("Displayed account code of the other account in a multi-split transaction|Split");
01393 
01394         return split_const;
01395     }
01396     return xaccAccountGetCode(other_split->acc);
01397 }
01398 
01399 /* TODO: It's not too hard to make this function avoid the malloc/free. */
01400 int
01401 xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)
01402 {
01403     Account *aa, *ab;
01404     char *full_a, *full_b;
01405     int retval;
01406     if (!sa && !sb) return 0;
01407     if (!sa) return -1;
01408     if (!sb) return 1;
01409 
01410     aa = sa->acc;
01411     ab = sb->acc;
01412     full_a = gnc_account_get_full_name(aa);
01413     full_b = gnc_account_get_full_name(ab);
01414     retval = g_utf8_collate(full_a, full_b);
01415     g_free(full_a);
01416     g_free(full_b);
01417     return retval;
01418 }
01419 
01420 
01421 int
01422 xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)
01423 {
01424     Account *aa, *ab;
01425     if (!sa && !sb) return 0;
01426     if (!sa) return -1;
01427     if (!sb) return 1;
01428 
01429     aa = sa->acc;
01430     ab = sb->acc;
01431 
01432     return safe_strcmp(xaccAccountGetCode(aa), xaccAccountGetCode(ab));
01433 }
01434 
01435 int
01436 xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)
01437 {
01438     char *ca, *cb;
01439     int retval;
01440     if (!sa && !sb) return 0;
01441     if (!sa) return -1;
01442     if (!sb) return 1;
01443 
01444     /* doesn't matter what separator we use
01445      * as long as they are the same
01446      */
01447 
01448     ca = xaccSplitGetCorrAccountFullName(sa);
01449     cb = xaccSplitGetCorrAccountFullName(sb);
01450     retval = safe_strcmp(ca, cb);
01451     g_free(ca);
01452     g_free(cb);
01453     return retval;
01454 }
01455 
01456 int
01457 xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)
01458 {
01459     const char *ca, *cb;
01460     if (!sa && !sb) return 0;
01461     if (!sa) return -1;
01462     if (!sb) return 1;
01463 
01464     ca = xaccSplitGetCorrAccountCode(sa);
01465     cb = xaccSplitGetCorrAccountCode(sb);
01466     return safe_strcmp(ca, cb);
01467 }
01468 
01469 static void
01470 qofSplitSetMemo (Split *split, const char* memo)
01471 {
01472     g_return_if_fail(split);
01473     CACHE_REPLACE(split->memo, memo);
01474 }
01475 
01476 void
01477 xaccSplitSetMemo (Split *split, const char *memo)
01478 {
01479     if (!split || !memo) return;
01480     xaccTransBeginEdit (split->parent);
01481 
01482     CACHE_REPLACE(split->memo, memo);
01483     qof_instance_set_dirty(QOF_INSTANCE(split));
01484     xaccTransCommitEdit(split->parent);
01485 
01486 }
01487 
01488 static void
01489 qofSplitSetAction (Split *split, const char *actn)
01490 {
01491     g_return_if_fail(split);
01492     CACHE_REPLACE(split->action, actn);
01493 }
01494 
01495 void
01496 xaccSplitSetAction (Split *split, const char *actn)
01497 {
01498     if (!split || !actn) return;
01499     xaccTransBeginEdit (split->parent);
01500 
01501     CACHE_REPLACE(split->action, actn);
01502     qof_instance_set_dirty(QOF_INSTANCE(split));
01503     xaccTransCommitEdit(split->parent);
01504 
01505 }
01506 
01507 static void
01508 qofSplitSetReconcile (Split *split, char recn)
01509 {
01510     g_return_if_fail(split);
01511     switch (recn)
01512     {
01513     case NREC:
01514     case CREC:
01515     case YREC:
01516     case FREC:
01517     case VREC:
01518         split->reconciled = recn;
01519         mark_split (split);
01520         xaccAccountRecomputeBalance (split->acc);
01521         break;
01522     default:
01523         PERR("Bad reconciled flag");
01524         break;
01525     }
01526 }
01527 
01528 void
01529 xaccSplitSetReconcile (Split *split, char recn)
01530 {
01531     if (!split || split->reconciled == recn) return;
01532     xaccTransBeginEdit (split->parent);
01533 
01534     switch (recn)
01535     {
01536     case NREC:
01537     case CREC:
01538     case YREC:
01539     case FREC:
01540     case VREC:
01541         split->reconciled = recn;
01542         mark_split (split);
01543         qof_instance_set_dirty(QOF_INSTANCE(split));
01544         xaccAccountRecomputeBalance (split->acc);
01545         break;
01546     default:
01547         PERR("Bad reconciled flag");
01548         break;
01549     }
01550     xaccTransCommitEdit(split->parent);
01551 
01552 }
01553 
01554 void
01555 xaccSplitSetDateReconciledSecs (Split *split, time_t secs)
01556 {
01557     if (!split) return;
01558     xaccTransBeginEdit (split->parent);
01559 
01560     split->date_reconciled.tv_sec = secs;
01561     split->date_reconciled.tv_nsec = 0;
01562     qof_instance_set_dirty(QOF_INSTANCE(split));
01563     xaccTransCommitEdit(split->parent);
01564 
01565 }
01566 
01567 void
01568 xaccSplitSetDateReconciledTS (Split *split, Timespec *ts)
01569 {
01570     if (!split || !ts) return;
01571     xaccTransBeginEdit (split->parent);
01572 
01573     split->date_reconciled = *ts;
01574     qof_instance_set_dirty(QOF_INSTANCE(split));
01575     xaccTransCommitEdit(split->parent);
01576 
01577 }
01578 
01579 void
01580 xaccSplitGetDateReconciledTS (const Split * split, Timespec *ts)
01581 {
01582     if (!split || !ts) return;
01583     *ts = (split->date_reconciled);
01584 }
01585 
01586 Timespec
01587 xaccSplitRetDateReconciledTS (const Split * split)
01588 {
01589     Timespec ts = {0, 0};
01590     return split ? split->date_reconciled : ts;
01591 }
01592 
01593 /********************************************************************\
01594 \********************************************************************/
01595 
01596 /* return the parent transaction of the split */
01597 Transaction *
01598 xaccSplitGetParent (const Split *split)
01599 {
01600     return split ? split->parent : NULL;
01601 }
01602 
01603 void
01604 xaccSplitSetParent(Split *s, Transaction *t)
01605 {
01606     Transaction *old_trans;
01607     GncEventData ed;
01608 
01609     g_return_if_fail(s);
01610     if (s->parent == t) return;
01611 
01612     if (s->parent != s->orig_parent && s->orig_parent != t)
01613         PERR("You may not add the split to more than one transaction"
01614              " during the BeginEdit/CommitEdit block.");
01615     xaccTransBeginEdit(t);
01616     old_trans = s->parent;
01617 
01618     xaccTransBeginEdit(old_trans);
01619 
01620     ed.node = s;
01621     if (old_trans)
01622     {
01623         ed.idx = xaccTransGetSplitIndex(old_trans, s);
01624         qof_event_gen(&old_trans->inst, GNC_EVENT_ITEM_REMOVED, &ed);
01625     }
01626     s->parent = t;
01627 
01628     xaccTransCommitEdit(old_trans);
01629     qof_instance_set_dirty(QOF_INSTANCE(s));
01630 
01631     if (t)
01632     {
01633         /* Convert split to new transaction's commodity denominator */
01634         xaccSplitSetValue(s, xaccSplitGetValue(s));
01635 
01636         /* add ourselves to the new transaction's list of pending splits. */
01637         if (NULL == g_list_find(t->splits, s))
01638             t->splits = g_list_append(t->splits, s);
01639 
01640         ed.idx = -1; /* unused */
01641         qof_event_gen(&t->inst, GNC_EVENT_ITEM_ADDED, &ed);
01642     }
01643     xaccTransCommitEdit(t);
01644 }
01645 
01646 
01647 GNCLot *
01648 xaccSplitGetLot (const Split *split)
01649 {
01650     return split ? split->lot : NULL;
01651 }
01652 
01653 void
01654 xaccSplitSetLot(Split* split, GNCLot* lot)
01655 {
01656     xaccTransBeginEdit (split->parent);
01657     split->lot = lot;
01658     qof_instance_set_dirty(QOF_INSTANCE(split));
01659     xaccTransCommitEdit(split->parent);
01660 }
01661 
01662 const char *
01663 xaccSplitGetMemo (const Split *split)
01664 {
01665     return split ? split->memo : NULL;
01666 }
01667 
01668 const char *
01669 xaccSplitGetAction (const Split *split)
01670 {
01671     return split ? split->action : NULL;
01672 }
01673 
01674 char
01675 xaccSplitGetReconcile (const Split *split)
01676 {
01677     return split ? split->reconciled : ' ';
01678 }
01679 
01680 
01681 gnc_numeric
01682 xaccSplitGetAmount (const Split * split)
01683 {
01684     return split ? split->amount : gnc_numeric_zero();
01685 }
01686 
01687 gnc_numeric
01688 xaccSplitGetValue (const Split * split)
01689 {
01690     return split ? split->value : gnc_numeric_zero();
01691 }
01692 
01693 gnc_numeric
01694 xaccSplitGetSharePrice (const Split * split)
01695 {
01696     gnc_numeric amt, val, price;
01697     if (!split) return gnc_numeric_create(1, 1);
01698 
01699 
01700     /* if amount == 0 and value == 0, then return 1.
01701      * if amount == 0 and value != 0 then return 0.
01702      * otherwise return value/amount
01703      */
01704 
01705     amt = xaccSplitGetAmount(split);
01706     val = xaccSplitGetValue(split);
01707     if (gnc_numeric_zero_p(amt))
01708     {
01709         if (gnc_numeric_zero_p(val))
01710             return gnc_numeric_create(1, 1);
01711         return gnc_numeric_create(0, 1);
01712     }
01713     price = gnc_numeric_div(val, amt,
01714                             GNC_DENOM_AUTO,
01715                             GNC_HOW_DENOM_SIGFIGS(PRICE_SIGFIGS) |
01716                             GNC_HOW_RND_ROUND_HALF_UP);
01717 
01718     /* During random checks we can get some very weird prices.  Let's
01719      * handle some overflow and other error conditions by returning
01720      * zero.  But still print an error to let us know it happened.
01721      */
01722     if (gnc_numeric_check(price))
01723     {
01724         PERR("Computing share price failed (%d): [ %" G_GINT64_FORMAT " / %"
01725              G_GINT64_FORMAT " ] / [ %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " ]",
01726              gnc_numeric_check(price), val.num, val.denom, amt.num, amt.denom);
01727         return gnc_numeric_create(0, 1);
01728     }
01729 
01730     return price;
01731 }
01732 
01733 /********************************************************************\
01734 \********************************************************************/
01735 
01736 QofBook *
01737 xaccSplitGetBook (const Split *split)
01738 {
01739     return qof_instance_get_book(QOF_INSTANCE(split));
01740 }
01741 
01742 const char *
01743 xaccSplitGetType(const Split *s)
01744 {
01745     const char *split_type;
01746 
01747     if (!s) return NULL;
01748     split_type = kvp_frame_get_string(s->inst.kvp_data, "split-type");
01749     return split_type ? split_type : "normal";
01750 }
01751 
01752 /* reconfigure a split to be a stock split - after this, you shouldn't
01753    mess with the value, just the amount. */
01754 void
01755 xaccSplitMakeStockSplit(Split *s)
01756 {
01757     xaccTransBeginEdit (s->parent);
01758 
01759     s->value = gnc_numeric_zero();
01760     kvp_frame_set_str(s->inst.kvp_data, "split-type", "stock-split");
01761     SET_GAINS_VDIRTY(s);
01762     mark_split(s);
01763     qof_instance_set_dirty(QOF_INSTANCE(s));
01764     xaccTransCommitEdit(s->parent);
01765 }
01766 
01767 
01768 /********************************************************************\
01769 \********************************************************************/
01770 /* In the old world, the 'other split' was the other split of a
01771  * transaction that contained only two splits.  In the new world,
01772  * a split may have been cut up between multiple lots, although
01773  * in a conceptual sense, if lots hadn't been used, there would be
01774  * only a pair.  So we handle this conceptual case: we can still
01775  * identify, unambiguously, the 'other' split when 'this' split
01776  * as been cut up across lots.  We do this by looking for the
01777  * 'lot-split' keyword, which occurs only in cut-up splits.
01778  */
01779 
01780 Split *
01781 xaccSplitGetOtherSplit (const Split *split)
01782 {
01783     int i;
01784     Transaction *trans;
01785     int count, num_splits;
01786     Split *other = NULL;
01787     KvpValue *sva;
01788     gboolean trading_accts;
01789 
01790     if (!split) return NULL;
01791     trans = split->parent;
01792     if (!trans) return NULL;
01793 
01794 #ifdef OLD_ALGO_HAS_ONLY_TWO_SPLITS
01795     Split *s1, *s2;
01796     if (g_list_length (trans->splits) != 2) return NULL;
01797 
01798     s1 = g_list_nth_data (trans->splits, 0);
01799     s2 = g_list_nth_data (trans->splits, 1);
01800 
01801     if (s1 == split) return s2;
01802     return s1;
01803 #endif
01804 
01805     trading_accts = xaccTransUseTradingAccounts (trans);
01806     num_splits = xaccTransCountSplits(trans);
01807     count = num_splits;
01808     sva = kvp_frame_get_slot (split->inst.kvp_data, "lot-split");
01809     if (!sva && !trading_accts && (2 != count)) return NULL;
01810 
01811     for (i = 0; i < num_splits; i++)
01812     {
01813         Split *s = xaccTransGetSplit(trans, i);
01814         if (s == split)
01815         {
01816             --count;
01817             continue;
01818         }
01819         if (kvp_frame_get_slot (s->inst.kvp_data, "lot-split"))
01820         {
01821             --count;
01822             continue;
01823         }
01824         if (trading_accts &&
01825                 xaccAccountGetType(xaccSplitGetAccount(s)) == ACCT_TYPE_TRADING)
01826         {
01827             --count;
01828             continue;
01829         }
01830         other = s;
01831     }
01832     return (1 == count) ? other : NULL;
01833 }
01834 
01835 /********************************************************************\
01836 \********************************************************************/
01837 
01838 gnc_numeric
01839 xaccSplitVoidFormerAmount(const Split *split)
01840 {
01841     g_return_val_if_fail(split, gnc_numeric_zero());
01842     return kvp_frame_get_numeric(split->inst.kvp_data, void_former_amt_str);
01843 }
01844 
01845 gnc_numeric
01846 xaccSplitVoidFormerValue(const Split *split)
01847 {
01848     g_return_val_if_fail(split, gnc_numeric_zero());
01849     return kvp_frame_get_numeric(split->inst.kvp_data, void_former_val_str);
01850 }
01851 
01852 void
01853 xaccSplitVoid(Split *split)
01854 {
01855     gnc_numeric zero = gnc_numeric_zero();
01856     KvpFrame *frame = split->inst.kvp_data;
01857 
01858     kvp_frame_set_gnc_numeric(frame, void_former_amt_str,
01859                               xaccSplitGetAmount(split));
01860     kvp_frame_set_gnc_numeric(frame, void_former_val_str,
01861                               xaccSplitGetValue(split));
01862 
01863     xaccSplitSetAmount (split, zero);
01864     xaccSplitSetValue (split, zero);
01865     xaccSplitSetReconcile(split, VREC);
01866 
01867 }
01868 
01869 void
01870 xaccSplitUnvoid(Split *split)
01871 {
01872     KvpFrame *frame = split->inst.kvp_data;
01873 
01874     xaccSplitSetAmount (split, xaccSplitVoidFormerAmount(split));
01875     xaccSplitSetValue (split, xaccSplitVoidFormerValue(split));
01876     xaccSplitSetReconcile(split, NREC);
01877     kvp_frame_set_slot(frame, void_former_amt_str, NULL);
01878     kvp_frame_set_slot(frame, void_former_val_str, NULL);
01879 }
01880 
01881 /********************************************************************\
01882 \********************************************************************/
01883 /* QofObject function implementation */
01884 
01885 /* Hook into the QofObject registry */
01886 
01887 #ifdef _MSC_VER
01888 /* MSVC compiler doesn't have C99 "designated initializers"
01889  * so we wrap them in a macro that is empty on MSVC. */
01890 # define DI(x) /* */
01891 #else
01892 # define DI(x) x
01893 #endif
01894 static QofObject split_object_def =
01895 {
01896     DI(.interface_version = ) QOF_OBJECT_VERSION,
01897     DI(.e_type            = ) GNC_ID_SPLIT,
01898     DI(.type_label        = ) "Split",
01899     DI(.create            = ) (gpointer)xaccMallocSplit,
01900     DI(.book_begin        = ) NULL,
01901     DI(.book_end          = ) NULL,
01902     DI(.is_dirty          = ) qof_collection_is_dirty,
01903     DI(.mark_clean        = ) qof_collection_mark_clean,
01904     DI(.foreach           = ) qof_collection_foreach,
01905     DI(.printable         = ) (const char * (*)(gpointer)) xaccSplitGetMemo,
01906     DI(.version_cmp       = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
01907 };
01908 
01909 static gpointer
01910 split_account_guid_getter (gpointer obj, const QofParam *p)
01911 {
01912     Split *s = obj;
01913     Account *acc;
01914 
01915     if (!s) return NULL;
01916     acc = xaccSplitGetAccount (s);
01917     if (!acc) return NULL;
01918     return ((gpointer)xaccAccountGetGUID (acc));
01919 }
01920 
01921 static double    /* internal use only */
01922 DxaccSplitGetShareAmount (const Split * split)
01923 {
01924     return split ? gnc_numeric_to_double(xaccSplitGetAmount(split)) : 0.0;
01925 }
01926 
01927 static gpointer
01928 no_op (gpointer obj, const QofParam *p)
01929 {
01930     return obj;
01931 }
01932 
01933 static void
01934 qofSplitSetParentTrans(Split *s, QofInstance *ent)
01935 {
01936     Transaction *trans = (Transaction*)ent;
01937 
01938     g_return_if_fail(trans);
01939     xaccSplitSetParent(s, trans);
01940 }
01941 
01942 static void
01943 qofSplitSetAccount(Split *s, QofInstance *ent)
01944 {
01945     Account *acc = (Account*)ent;
01946 
01947     g_return_if_fail(acc);
01948     xaccSplitSetAccount(s, acc);
01949 }
01950 
01951 gboolean xaccSplitRegister (void)
01952 {
01953     static const QofParam params[] =
01954     {
01955         {
01956             SPLIT_DATE_RECONCILED, QOF_TYPE_DATE,
01957             (QofAccessFunc)xaccSplitRetDateReconciledTS,
01958             (QofSetterFunc)xaccSplitSetDateReconciledTS
01959         },
01960 
01961         /* d-* are deprecated query params, should not be used in new
01962          * queries, should be removed from old queries. */
01963         {
01964             "d-share-amount", QOF_TYPE_DOUBLE,
01965             (QofAccessFunc)DxaccSplitGetShareAmount, NULL
01966         },
01967         {
01968             "d-share-int64", QOF_TYPE_INT64,
01969             (QofAccessFunc)qof_entity_get_guid, NULL
01970         },
01971         {
01972             SPLIT_BALANCE, QOF_TYPE_NUMERIC,
01973             (QofAccessFunc)xaccSplitGetBalance, NULL
01974         },
01975         {
01976             SPLIT_CLEARED_BALANCE, QOF_TYPE_NUMERIC,
01977             (QofAccessFunc)xaccSplitGetClearedBalance, NULL
01978         },
01979         {
01980             SPLIT_RECONCILED_BALANCE, QOF_TYPE_NUMERIC,
01981             (QofAccessFunc)xaccSplitGetReconciledBalance, NULL
01982         },
01983         {
01984             SPLIT_MEMO, QOF_TYPE_STRING,
01985             (QofAccessFunc)xaccSplitGetMemo, (QofSetterFunc)qofSplitSetMemo
01986         },
01987         {
01988             SPLIT_ACTION, QOF_TYPE_STRING,
01989             (QofAccessFunc)xaccSplitGetAction, (QofSetterFunc)qofSplitSetAction
01990         },
01991         {
01992             SPLIT_RECONCILE, QOF_TYPE_CHAR,
01993             (QofAccessFunc)xaccSplitGetReconcile,
01994             (QofSetterFunc)qofSplitSetReconcile
01995         },
01996         {
01997             SPLIT_AMOUNT, QOF_TYPE_NUMERIC,
01998             (QofAccessFunc)xaccSplitGetAmount, (QofSetterFunc)qofSplitSetAmount
01999         },
02000         {
02001             SPLIT_SHARE_PRICE, QOF_TYPE_NUMERIC,
02002             (QofAccessFunc)xaccSplitGetSharePrice,
02003             (QofSetterFunc)qofSplitSetSharePrice
02004         },
02005         {
02006             SPLIT_VALUE, QOF_TYPE_DEBCRED,
02007             (QofAccessFunc)xaccSplitGetValue, (QofSetterFunc)qofSplitSetValue
02008         },
02009         { SPLIT_TYPE, QOF_TYPE_STRING, (QofAccessFunc)xaccSplitGetType, NULL },
02010         {
02011             SPLIT_VOIDED_AMOUNT, QOF_TYPE_NUMERIC,
02012             (QofAccessFunc)xaccSplitVoidFormerAmount, NULL
02013         },
02014         {
02015             SPLIT_VOIDED_VALUE, QOF_TYPE_NUMERIC,
02016             (QofAccessFunc)xaccSplitVoidFormerValue, NULL
02017         },
02018         { SPLIT_LOT, GNC_ID_LOT, (QofAccessFunc)xaccSplitGetLot, NULL },
02019         {
02020             SPLIT_TRANS, GNC_ID_TRANS,
02021             (QofAccessFunc)xaccSplitGetParent,
02022             (QofSetterFunc)qofSplitSetParentTrans
02023         },
02024         {
02025             SPLIT_ACCOUNT, GNC_ID_ACCOUNT,
02026             (QofAccessFunc)xaccSplitGetAccount, (QofSetterFunc)qofSplitSetAccount
02027         },
02028         { SPLIT_ACCOUNT_GUID, QOF_TYPE_GUID, split_account_guid_getter, NULL },
02029         /*  these are no-ops to register the parameter names (for sorting) but
02030             they return an allocated object which getters cannot do.  */
02031         { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, NULL },
02032         { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, NULL },
02033         { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, NULL },
02034         { SPLIT_KVP, QOF_TYPE_KVP, (QofAccessFunc)xaccSplitGetSlots, NULL },
02035         { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, NULL },
02036         {
02037             QOF_PARAM_GUID, QOF_TYPE_GUID,
02038             (QofAccessFunc)qof_entity_get_guid, NULL
02039         },
02040         { NULL },
02041     };
02042 
02043     qof_class_register (GNC_ID_SPLIT, (QofSortFunc)xaccSplitOrder, params);
02044     qof_class_register (SPLIT_ACCT_FULLNAME,
02045                         (QofSortFunc)xaccSplitCompareAccountFullNames, NULL);
02046     qof_class_register (SPLIT_CORR_ACCT_NAME,
02047                         (QofSortFunc)xaccSplitCompareOtherAccountFullNames,
02048                         NULL);
02049     qof_class_register (SPLIT_CORR_ACCT_CODE,
02050                         (QofSortFunc)xaccSplitCompareOtherAccountCodes, NULL);
02051 
02052     return qof_object_register (&split_object_def);
02053 }
02054 
02055 SplitTestFunctions*
02056 _utest_split_fill_functions (void)
02057 {
02058     SplitTestFunctions *func = g_new (SplitTestFunctions, 1);
02059 
02060     func->xaccSplitEqualCheckBal = xaccSplitEqualCheckBal;
02061     func->get_currency_denom = get_currency_denom;
02062     func->get_commodity_denom = get_commodity_denom;
02063     func->get_corr_account_split = get_corr_account_split;
02064     return func;
02065 }
02066 
02067 /************************ END OF ************************************\
02068 \************************* FILE *************************************/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines