LCOV - code coverage report
Current view: top level - libgnucash/engine - TransLog.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 78.3 % 83 65
Test Date: 2025-02-07 16:25:45 Functions: 75.0 % 8 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************\
       2                 :             :  * TransLog.c -- the transaction logger                             *
       3                 :             :  * Copyright (C) 1998 Linas Vepstas                                 *
       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                 :             : 
      24                 :             : #include <config.h>
      25                 :             : #ifdef __MINGW32__
      26                 :             : #define __USE_MINGW_ANSI_STDIO 1
      27                 :             : #endif
      28                 :             : #include <errno.h>
      29                 :             : #include <glib.h>
      30                 :             : #include <glib/gstdio.h>
      31                 :             : #include <string.h>
      32                 :             : 
      33                 :             : #include "Account.h"
      34                 :             : #include "Transaction.h"
      35                 :             : #include "TransactionP.hpp"
      36                 :             : #include "TransLog.h"
      37                 :             : #include "qof.h"
      38                 :             : #ifdef _MSC_VER
      39                 :             : # define g_fopen fopen
      40                 :             : #endif
      41                 :             : 
      42                 :             : static QofLogModule log_module = "gnc.translog";
      43                 :             : 
      44                 :             : /*
      45                 :             :  * Some design philosophy that I think would be good to keep in mind:
      46                 :             :  * (0) Simplicity and foolproofness are the over-riding design points.
      47                 :             :  *     This is supposed to be a fail-safe safety net.   We don't want
      48                 :             :  *     our safety net to fail because of some whiz-bang shenanigans.
      49                 :             :  *
      50                 :             :  * (1) Try to keep the code simple.  Want to make it simple and obvious
      51                 :             :  *     that we are recording everything that we need to record.
      52                 :             :  *
      53                 :             :  * (2) Keep the printed format human readable, for the same reasons.
      54                 :             :  * (2.a) Keep the format, simple, flat, more or less unstructured,
      55                 :             :  *       record oriented.  This will help parsing by perl scripts.
      56                 :             :  *       No, using a perl script to analyze a file that's supposed to
      57                 :             :  *       be human readable is not a contradication in terms -- that's
      58                 :             :  *       exactly the point.
      59                 :             :  * (2.b) Use tabs as a human friendly field separator; its also a
      60                 :             :  *       character that does not (should not) appear naturally anywhere
      61                 :             :  *       in the data, as it serves no formatting purpose in the current
      62                 :             :  *       GUI design.  (hack alert -- this is not currently tested for
      63                 :             :  *       or enforced, so this is a very unsafe assumption. Maybe
      64                 :             :  *       urlencoding should be used.)
      65                 :             :  * (2.c) Don't print redundant information in a single record. This
      66                 :             :  *       would just confuse any potential user of this file.
      67                 :             :  * (2.d) Saving space, being compact is not a priority, I don't think.
      68                 :             :  *
      69                 :             :  * (3) There are no compatibility requirements from release to release.
      70                 :             :  *     Sounds OK to me to change the format of the output when needed.
      71                 :             :  *
      72                 :             :  * (-) print transaction start and end delimiters
      73                 :             :  * (-) print a unique transaction id as a handy label for anyone
      74                 :             :  *     who actually examines these logs.
      75                 :             :  *     The C address pointer to the transaction struct should be fine,
      76                 :             :  *     as it is simple and unique until the transaction is deleted ...
      77                 :             :  *     and we log deletions, so that's OK.  Just note that the id
      78                 :             :  *     for a deleted transaction might be recycled.
      79                 :             :  * (-) print the current timestamp, so that if it is known that a bug
      80                 :             :  *     occurred at a certain time, it can be located.
      81                 :             :  * (-) hack alert -- something better than just the account name
      82                 :             :  *     is needed for identifying the account.
      83                 :             :  */
      84                 :             : /* ------------------------------------------------------------------ */
      85                 :             : 
      86                 :             : 
      87                 :             : static int gen_logs = 1;
      88                 :             : static FILE * trans_log = nullptr; /**< current log file handle */
      89                 :             : static char * trans_log_name = nullptr; /**< current log file name */
      90                 :             : static char * log_base_name = nullptr;
      91                 :             : 
      92                 :             : /********************************************************************\
      93                 :             : \********************************************************************/
      94                 :             : 
      95                 :         142 : void xaccLogDisable (void)
      96                 :             : {
      97                 :         142 :     gen_logs = 0;
      98                 :         142 : }
      99                 :         129 : void xaccLogEnable  (void)
     100                 :             : {
     101                 :         129 :     gen_logs = 1;
     102                 :         129 : }
     103                 :             : 
     104                 :             : /********************************************************************\
     105                 :             : \********************************************************************/
     106                 :             : 
     107                 :             : void
     108                 :           0 : xaccReopenLog (void)
     109                 :             : {
     110                 :           0 :     if (trans_log)
     111                 :             :     {
     112                 :           0 :         xaccCloseLog();
     113                 :           0 :         xaccOpenLog();
     114                 :             :     }
     115                 :           0 : }
     116                 :             : 
     117                 :             : 
     118                 :             : void
     119                 :          46 : xaccLogSetBaseName (const char *basepath)
     120                 :             : {
     121                 :          46 :     if (!basepath) return;
     122                 :             : 
     123                 :          37 :     g_free (log_base_name);
     124                 :          37 :     log_base_name = g_strdup (basepath);
     125                 :             : 
     126                 :          37 :     if (trans_log)
     127                 :             :     {
     128                 :          10 :         xaccCloseLog();
     129                 :          10 :         xaccOpenLog();
     130                 :             :     }
     131                 :             : }
     132                 :             : 
     133                 :             : 
     134                 :             : /*
     135                 :             :  * See if the provided file name is that of the current log file.
     136                 :             :  * Since the filename is generated with a time-stamp we can ignore the
     137                 :             :  * directory path and avoid problems with worrying about any ".."
     138                 :             :  * components in the path.
     139                 :             :  */
     140                 :             : gboolean
     141                 :           0 : xaccFileIsCurrentLog (const gchar *name)
     142                 :             : {
     143                 :             :     gchar *base;
     144                 :             :     gint result;
     145                 :             : 
     146                 :           0 :     if (!name || !trans_log_name)
     147                 :           0 :         return FALSE;
     148                 :             : 
     149                 :           0 :     base = g_path_get_basename(name);
     150                 :           0 :     result = (strcmp(base, trans_log_name) == 0);
     151                 :           0 :     g_free(base);
     152                 :           0 :     return result;
     153                 :             : }
     154                 :             : 
     155                 :             : /********************************************************************\
     156                 :             : \********************************************************************/
     157                 :             : 
     158                 :             : void
     159                 :        4750 : xaccOpenLog (void)
     160                 :             : {
     161                 :             :     char * filename;
     162                 :             :     char * timestamp;
     163                 :             : 
     164                 :        4750 :     if (!gen_logs)
     165                 :             :     {
     166                 :        2435 :          PINFO ("Attempt to open disabled transaction log");
     167                 :        2435 :          return;
     168                 :             :     }
     169                 :        2315 :     if (trans_log) return;
     170                 :             : 
     171                 :          75 :     if (!log_base_name) log_base_name = g_strdup ("translog");
     172                 :             : 
     173                 :             :     /* tag each filename with a timestamp */
     174                 :          43 :     timestamp = gnc_date_timestamp ();
     175                 :             : 
     176                 :          43 :     filename = g_strconcat (log_base_name, ".", timestamp, ".log", nullptr);
     177                 :             : 
     178                 :          43 :     trans_log = g_fopen (filename, "a");
     179                 :          43 :     if (!trans_log)
     180                 :             :     {
     181                 :           0 :         int norr = errno;
     182                 :           0 :         printf ("Error: xaccOpenLog(): cannot open journal\n"
     183                 :           0 :                 "\t %d %s\n", norr, g_strerror (norr) ? g_strerror (norr) : "");
     184                 :             : 
     185                 :           0 :         g_free (filename);
     186                 :           0 :         g_free (timestamp);
     187                 :           0 :         return;
     188                 :             :     }
     189                 :             : 
     190                 :             :     /* Save the log file name */
     191                 :          43 :     if (trans_log_name)
     192                 :          10 :         g_free (trans_log_name);
     193                 :          43 :     trans_log_name = g_path_get_basename(filename);
     194                 :             : 
     195                 :          43 :     g_free (filename);
     196                 :          43 :     g_free (timestamp);
     197                 :             : 
     198                 :             :     /*  Note: this must match src/import-export/log-replay/gnc-log-replay.c */
     199                 :          43 :     fprintf (trans_log, "mod\ttrans_guid\tsplit_guid\ttime_now\t"
     200                 :             :              "date_entered\tdate_posted\t"
     201                 :             :              "acc_guid\tacc_name\tnum\tdescription\t"
     202                 :             :              "notes\tmemo\taction\treconciled\t"
     203                 :             :              "amount\tvalue\tdate_reconciled\n");
     204                 :          43 :     fprintf (trans_log, "-----------------\n");
     205                 :             : }
     206                 :             : 
     207                 :             : /********************************************************************\
     208                 :             : \********************************************************************/
     209                 :             : 
     210                 :             : void
     211                 :          10 : xaccCloseLog (void)
     212                 :             : {
     213                 :          10 :     if (!trans_log) return;
     214                 :          10 :     fflush (trans_log);
     215                 :          10 :     fclose (trans_log);
     216                 :          10 :     trans_log = nullptr;
     217                 :             : }
     218                 :             : 
     219                 :             : /********************************************************************\
     220                 :             : \********************************************************************/
     221                 :             : 
     222                 :             : void
     223                 :        9376 : xaccTransWriteLog (Transaction *trans, char flag)
     224                 :             : {
     225                 :             :     GList *node;
     226                 :             :     char trans_guid_str[GUID_ENCODING_LENGTH + 1];
     227                 :             :     char split_guid_str[GUID_ENCODING_LENGTH + 1];
     228                 :             :     const char *trans_notes;
     229                 :             :     char dnow[100], dent[100], dpost[100], drecn[100];
     230                 :             : 
     231                 :        9376 :     if (!gen_logs)
     232                 :             :     {
     233                 :        4766 :          PINFO ("Attempt to write disabled transaction log");
     234                 :        4766 :          return;
     235                 :             :     }
     236                 :        4610 :     if (!trans_log) return;
     237                 :             : 
     238                 :        4610 :     gnc_time64_to_iso8601_buff (gnc_time(nullptr), dnow);
     239                 :        4610 :     gnc_time64_to_iso8601_buff (trans->date_entered, dent);
     240                 :        4610 :     gnc_time64_to_iso8601_buff (trans->date_posted, dpost);
     241                 :        4610 :     guid_to_string_buff (xaccTransGetGUID(trans), trans_guid_str);
     242                 :        4610 :     trans_notes = xaccTransGetNotes(trans);
     243                 :        4610 :     fprintf (trans_log, "===== START\n");
     244                 :             : 
     245                 :        9700 :     for (node = trans->splits; node; node = node->next)
     246                 :             :     {
     247                 :        5090 :         Split *split = GNC_SPLIT(node->data);
     248                 :        5090 :         const char * accname = "";
     249                 :             :         char acc_guid_str[GUID_ENCODING_LENGTH + 1];
     250                 :             :         gnc_numeric amt, val;
     251                 :             : 
     252                 :        5090 :         if (xaccSplitGetAccount(split))
     253                 :             :         {
     254                 :        5059 :             accname = xaccAccountGetName (xaccSplitGetAccount(split));
     255                 :        5059 :             guid_to_string_buff(xaccAccountGetGUID(xaccSplitGetAccount(split)),
     256                 :             :                                 acc_guid_str);
     257                 :             :         }
     258                 :             :         else
     259                 :             :         {
     260                 :          31 :             acc_guid_str[0] = '\0';
     261                 :             :         }
     262                 :             : 
     263                 :        5090 :         gnc_time64_to_iso8601_buff (split->date_reconciled, drecn);
     264                 :             : 
     265                 :        5090 :         guid_to_string_buff (xaccSplitGetGUID(split), split_guid_str);
     266                 :        5090 :         amt = xaccSplitGetAmount (split);
     267                 :        5090 :         val = xaccSplitGetValue (split);
     268                 :             : 
     269                 :             :         /* use tab-separated fields */
     270                 :       25450 :         fprintf (trans_log,
     271                 :             :                  "%c\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t"
     272                 :             :                  "%s\t%s\t%s\t%s\t%c\t%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT "\t%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT "\t%s\n",
     273                 :             :                  flag,
     274                 :             :                  trans_guid_str, split_guid_str,  /* trans+split make up unique id */
     275                 :             :                  /* Note that the next three strings always exist,
     276                 :             :                                 * so we don't need to test them. */
     277                 :             :                  dnow,
     278                 :             :                  dent,
     279                 :             :                  dpost,
     280                 :             :                  acc_guid_str,
     281                 :             :                  accname ? accname : "",
     282                 :        5090 :                  trans->num ? trans->num : "",
     283                 :        5090 :                  trans->description ? trans->description : "",
     284                 :             :                  trans_notes ? trans_notes : "",
     285                 :        5090 :                  split->memo ? split->memo : "",
     286                 :        5090 :                  split->action ? split->action : "",
     287                 :        5090 :                  split->reconciled,
     288                 :             :                  gnc_numeric_num(amt),
     289                 :             :                  gnc_numeric_denom(amt),
     290                 :             :                  gnc_numeric_num(val),
     291                 :             :                  gnc_numeric_denom(val),
     292                 :             :                  /* The next string always exists. No need to test it. */
     293                 :             :                  drecn);
     294                 :             :     }
     295                 :             : 
     296                 :        4610 :     fprintf (trans_log, "===== END\n");
     297                 :             : 
     298                 :             :     /* get data out to the disk */
     299                 :        4610 :     fflush (trans_log);
     300                 :             : }
     301                 :             : 
     302                 :             : /************************ END OF ************************************\
     303                 :             : \************************* FILE *************************************/
        

Generated by: LCOV version 2.0-1