Skip to content

Commit

Permalink
[gnc-features.cpp] convert to cpp
Browse files Browse the repository at this point in the history
- don't need to create/destroy GHashTable for each feature query
- plugs leak: g_hash_table_unref (features_used) not always called properly
- to check 1 feature, don't need to traverse whole GHashTable
  • Loading branch information
christopherlam committed Oct 28, 2022
1 parent 6f6d2fe commit 8192def
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 108 deletions.
3 changes: 2 additions & 1 deletion libgnucash/engine/CMakeLists.txt
Expand Up @@ -93,6 +93,7 @@ set (engine_HEADERS
qof-backend.hpp
qofbackend.h
qofbook.h
qofbook.hpp
qofbookslots.h
qofchoice.h
qofclass.h
Expand Down Expand Up @@ -145,7 +146,7 @@ set (engine_SOURCES
gnc-datetime.cpp
gnc-engine.c
gnc-event.c
gnc-features.c
gnc-features.cpp
gnc-hooks.c
gnc-int128.cpp
gnc-lot.c
Expand Down
129 changes: 23 additions & 106 deletions libgnucash/engine/gnc-features.c → libgnucash/engine/gnc-features.cpp
Expand Up @@ -19,28 +19,22 @@
* *
\********************************************************************/

#include <unordered_map>
#include <string>
#include <numeric>

#include <config.h>

#include <glib.h>
#include <glib/gi18n.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "qof.h"
#include "gnc-features.h"
#include "gnc-glib-utils.h"
#include "qofbook.hpp"

typedef struct
extern "C"
{
const gchar *key;
const gchar *desc;
} gncFeature;
#include "gnc-features.h"
}

static GHashTable *features_table = NULL;
static gncFeature known_features[] =
static const FeaturesTable features_table
{
{ GNC_FEATURE_CREDIT_NOTES, "Customer and vendor credit notes (requires at least GnuCash 2.5.0)" },
{ GNC_FEATURE_NUM_FIELD_SOURCE, "User specifies source of 'num' field'; either transaction number or split action (requires at least GnuCash 2.5.0)" },
Expand All @@ -53,7 +47,6 @@ static gncFeature known_features[] =
{ GNC_FEATURE_BUDGET_UNREVERSED, "Store budget amounts unreversed (i.e. natural) signs (requires at least Gnucash 3.8)"},
{ GNC_FEATURE_BUDGET_SHOW_EXTRA_ACCOUNT_COLS, "Show extra account columns in the Budget View (requires at least Gnucash 3.8)"},
{ GNC_FEATURE_EQUITY_TYPE_OPENING_BALANCE, GNC_FEATURE_EQUITY_TYPE_OPENING_BALANCE " (requires at least Gnucash 4.3)" },
{ NULL },
};

/* This static indicates the debugging module that this .o belongs to. */
Expand All @@ -62,40 +55,11 @@ static QofLogModule log_module = G_LOG_DOMAIN;
/********************************************************************\
\********************************************************************/

static void gnc_features_init ()
{
gint i;

if (features_table)
return;

features_table = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; known_features[i].key; i++)
g_hash_table_insert (features_table,
g_strdup (known_features[i].key),
g_strdup (known_features[i].desc));
}

static void gnc_features_test_one(gpointer pkey, gpointer value,
gpointer data)
{
const gchar *key = (const gchar*)pkey;
const gchar *feature_desc = (const gchar*)value;
GList **unknown_features;

g_assert(data);
unknown_features = (GList**) data;

/* Check if this feature is in the known features list. */
if (g_hash_table_lookup_extended (features_table, key, NULL, NULL))
return;

/* It is unknown, so add the description to the unknown features list: */
g_assert(feature_desc);

*unknown_features = g_list_prepend(*unknown_features,
(gpointer)feature_desc);
}
static const char*
header = N_("This Dataset contains features not supported "
"by this version of GnuCash. You must use a "
"newer version of GnuCash in order to support "
"the following features:");

/* Check if the session requires features unknown to this version of GnuCash.
*
Expand All @@ -104,78 +68,31 @@ static void gnc_features_test_one(gpointer pkey, gpointer value,
*/
gchar *gnc_features_test_unknown (QofBook *book)
{

GList* features_list = NULL;
GHashTable *features_used = qof_book_get_features (book);

/* Setup the known_features hash table */
gnc_features_init();

/* Iterate over the members of this frame for unknown features */
g_hash_table_foreach (features_used, &gnc_features_test_one,
&features_list);
if (features_list)
{
const char* sep = "\n* ";
const char* header = _("This Dataset contains features not supported "
"by this version of GnuCash. You must use a "
"newer version of GnuCash in order to support "
"the following features:");

char *features_str = gnc_g_list_stringjoin (features_list, sep);
char *msg = g_strconcat (header, sep, features_str, NULL);
g_free (features_str);
g_list_free(features_list);
return msg;
}
g_hash_table_unref (features_used);
return NULL;
auto unknowns {qof_book_get_unknown_features (book, features_table)};
auto accum = [](const auto& a, const auto& b){ return a + "\n* " + b; };
return unknowns.empty() ? nullptr :
g_strdup (std::accumulate (unknowns.begin(), unknowns.end(),
std::string (_(header)), accum).c_str());
}

void gnc_features_set_used (QofBook *book, const gchar *feature)
{
const gchar *description;

g_return_if_fail (book);
g_return_if_fail (feature);

gnc_features_init();

/* Can't set an unknown feature */
description = g_hash_table_lookup (features_table, feature);
if (!description)
auto iter = features_table.find (feature);
if (iter == features_table.end ())
{
PWARN("Tried to set unknown feature as used.");
return;
}

qof_book_set_feature (book, feature, description);
}

struct CheckFeature
{
gchar const * checked_feature;
gboolean found;
};

static void gnc_features_check_feature_cb (gpointer pkey, gpointer value,
gpointer data)
{
const gchar *key = (const gchar*)pkey;
struct CheckFeature * check_data = data;
g_assert(data);
if (!g_strcmp0 (key, check_data->checked_feature))
check_data->found = TRUE;
qof_book_set_feature (book, feature, iter->second.c_str());
}

gboolean gnc_features_check_used (QofBook *book, const gchar * feature)
{
GHashTable *features_used = qof_book_get_features (book);
struct CheckFeature check_data = {feature, FALSE};
/* Setup the known_features hash table */
gnc_features_init();
g_hash_table_foreach (features_used, &gnc_features_check_feature_cb, &check_data);
g_hash_table_unref (features_used);
return check_data.found;
return qof_book_test_feature (book, feature);
}

28 changes: 28 additions & 0 deletions libgnucash/engine/qofbook.cpp
Expand Up @@ -61,6 +61,8 @@ extern "C"
// For GNC_ID_ROOT_ACCOUNT:
#include "AccountP.h"

#include "qofbook.hpp"

static QofLogModule log_module = QOF_MOD_ENGINE;
#define AB_KEY "hbci"
#define AB_TEMPLATES "template-list"
Expand Down Expand Up @@ -1255,6 +1257,32 @@ qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
}
}

std::vector<std::string>
qof_book_get_unknown_features (QofBook *book, const FeaturesTable& features)
{
std::vector<std::string> rv;
auto test_feature = [&](const KvpFrameImpl::map_type::value_type& feature)
{
if (features.find (feature.first) == features.end ())
rv.push_back (feature.second->get<const char*>());
};
auto frame = qof_instance_get_slots (QOF_INSTANCE (book));
auto slot = frame->get_slot({GNC_FEATURES});
if (slot != nullptr)
{
frame = slot->get<KvpFrame*>();
std::for_each (frame->begin (), frame->end (), test_feature);
}
return rv;
}

bool
qof_book_test_feature (QofBook *book, const char *feature)
{
auto frame = qof_instance_get_slots (QOF_INSTANCE (book));
return (frame->get_slot({GNC_FEATURES, feature}) != nullptr);
}

void
qof_book_load_options (QofBook *book, GNCOptionLoad load_cb, GNCOptionDB *odb)
{
Expand Down
36 changes: 36 additions & 0 deletions libgnucash/engine/qofbook.hpp
@@ -0,0 +1,36 @@
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
\********************************************************************/

#ifndef __QOF_BOOK__HPP__
#define __QOF_BOOK__HPP__

#include <vector>
#include <unordered_map>
#include <string>

#include "qof.h"

using FeaturesTable = std::unordered_map<std::string,std::string>;

std::vector<std::string>
qof_book_get_unknown_features (QofBook *book, const FeaturesTable& features);
bool qof_book_test_feature (QofBook*, const char*);

#endif /* QOF_BOOK_HPP */
2 changes: 1 addition & 1 deletion po/POTFILES.in
Expand Up @@ -641,7 +641,7 @@ libgnucash/engine/gncEmployee.c
libgnucash/engine/gnc-engine.c
libgnucash/engine/gncEntry.c
libgnucash/engine/gnc-event.c
libgnucash/engine/gnc-features.c
libgnucash/engine/gnc-features.cpp
libgnucash/engine/gnc-hooks.c
libgnucash/engine/gncIDSearch.c
libgnucash/engine/gnc-int128.cpp
Expand Down

0 comments on commit 8192def

Please sign in to comment.