27 #define _GL_UNISTD_H //Deflect poisonous define in Guile's GnuLib 31 #include <glib/gstdio.h> 42 #include <gnc-guile-utils.h> 44 #include "gnc-report.h" 47 extern "C" SCM scm_init_sw_report_module(
void);
49 static QofLogModule log_module = GNC_MOD_GUI;
52 static GHashTable *reports = NULL;
53 static gint report_next_serial_id = 0;
56 try_load_config_array(
const gchar *fns[])
61 for (i = 0; fns[i]; i++)
64 if (gfec_try_load(filename))
75 update_message(
const gchar *msg)
82 load_custom_reports_stylesheets(
void)
86 static const gchar *saved_report_files[] =
88 SAVED_REPORTS_FILE, SAVED_REPORTS_FILE_OLD_REV, NULL
90 static const gchar *stylesheet_files[] = {
"stylesheets-2.0", NULL};
91 static int is_user_config_loaded = FALSE;
93 if (is_user_config_loaded)
95 else is_user_config_loaded = TRUE;
97 update_message(
"loading saved reports");
98 try_load_config_array(saved_report_files);
99 update_message(
"loading stylesheets");
100 try_load_config_array(stylesheet_files);
104 gnc_report_init (
void)
106 scm_init_sw_report_module();
107 scm_c_use_module (
"gnucash report");
108 scm_c_use_module (
"gnucash reports");
109 scm_c_eval_string(
"(report-module-loader (list '(gnucash report stylesheets)))");
111 load_custom_reports_stylesheets();
116 gnc_report_init_table(
void)
120 reports = g_hash_table_new_full(
121 g_int_hash, g_int_equal,
122 g_free, (GDestroyNotify) scm_gc_unprotect_object);
127 gnc_report_remove_by_id(gint
id)
130 g_hash_table_remove(reports, &
id);
133 SCM gnc_report_find(gint
id)
135 SCM report =
nullptr;
139 report =
static_cast<SCM
>(g_hash_table_lookup(reports, &
id));
148 gint gnc_report_add(SCM report)
150 SCM get_id = scm_c_eval_string(
"gnc:report-id");
154 gnc_report_init_table();
156 value = scm_call_1(get_id, report);
157 if (scm_is_number(value))
159 id = scm_to_int(value);
160 if (!g_hash_table_lookup(reports, &
id))
162 key = g_new(gint, 1);
164 g_hash_table_insert(reports, key, (gpointer)report);
165 scm_gc_protect_object(report);
168 g_warning(
"Report specified id of %d is already is use. " 169 "Using generated id.",
id);
172 id = report_next_serial_id++;
173 while (
id < G_MAXINT)
175 if (!g_hash_table_lookup(reports, &
id))
177 key = g_new(gint, 1);
179 g_hash_table_insert(reports, key, (gpointer)report);
180 scm_gc_protect_object(report);
183 id = report_next_serial_id++;
186 g_warning(
"Unable to add report to table. %d reports in use.", G_MAXINT);
187 report_next_serial_id = G_MAXINT;
192 yes_remove(gpointer key, gpointer val, gpointer data)
198 gnc_reports_flush_global(
void)
201 g_hash_table_foreach_remove(reports, yes_remove, NULL);
205 gnc_reports_foreach (GHFunc func, gpointer user_data)
207 gnc_report_init_table();
209 g_hash_table_foreach (reports, func, user_data);
213 gnc_run_report_with_error_handling (gint report_id, gchar ** data, gchar **errmsg)
215 SCM report, res, html, captured_error;
217 report = gnc_report_find (report_id);
218 g_return_val_if_fail (data, FALSE);
219 g_return_val_if_fail (errmsg, FALSE);
220 g_return_val_if_fail (!scm_is_false (report), FALSE);
222 res = scm_call_1 (scm_c_eval_string (
"gnc:render-report"), report);
223 html = scm_car (res);
224 captured_error = scm_cadr (res);
226 if (!scm_is_false (html))
228 *data = gnc_scm_to_utf8_string (html);
234 constexpr
const char* with_err =
"Report %s failed to generate html: %s";
235 constexpr
const char* without_err =
"Report %s Failed to generate html but didn't raise a Scheme exception.";
236 auto scm_err = scm_is_string (captured_error) ? gnc_scm_to_utf8_string (captured_error) :
239 if (scm_err && *scm_err)
240 *errmsg = g_strdup_printf (with_err, gnc_report_name (report), scm_err);
242 *errmsg = g_strdup_printf (without_err, gnc_report_name (report));
251 gnc_report_name( SCM report )
253 SCM get_name = scm_c_eval_string(
"gnc:report-name");
255 if (report == SCM_BOOL_F)
258 return gnc_scm_call_1_to_string(get_name, report);
262 gnc_report_id_string_to_report_id (
const char *id_string)
264 g_return_val_if_fail (id_string, -1);
266 const char *end_ptr = id_string + std::strlen (id_string);
268 auto res = std::from_chars (id_string, end_ptr, rpt_id);
269 if (res.ec != std::errc() || rpt_id < 0)
return -1;
270 if (res.ptr == end_ptr)
return rpt_id;
271 if (*res.ptr !=
'|')
return -1;
274 res = std::from_chars (res.ptr + 1, end_ptr, anchor_id);
275 if (res.ec != std::errc() || *res.ptr !=
'\0' || anchor_id < 0)
return -1;
277 const SCM get_linked = scm_c_eval_string (
"gnc:report-get-linked-report");
279 auto id = scm_call_2 (get_linked, scm_from_int (rpt_id), scm_from_int (anchor_id));
280 return scm_is_number (
id) ? scm_to_int (
id) : -1;
284 gnc_run_report_id_string_with_error_handling (
const char * id_string,
char **data,
287 g_return_val_if_fail (id_string, FALSE);
288 g_return_val_if_fail (data, FALSE);
291 if (strncmp (
"id=", id_string, 3) != 0)
294 gint report_id = gnc_report_id_string_to_report_id (id_string + 3);
298 return gnc_run_report_with_error_handling (report_id, data, errmsg);
302 gnc_get_default_report_font_family(
void)
305 GtkWidget *top_widget;
306 PangoFontDescription *font_desc;
307 GtkStyleContext *top_widget_style_c;
308 gchar *default_font_family;
310 top_list = gtk_window_list_toplevels();
311 if (top_list == NULL)
312 return g_strdup (
"Arial");
313 top_widget = GTK_WIDGET(top_list->data);
314 g_list_free(top_list);
315 top_widget_style_c = gtk_widget_get_style_context (top_widget);
316 gtk_style_context_get (top_widget_style_c, gtk_widget_get_state_flags (GTK_WIDGET(top_widget)),
317 "font", &font_desc, NULL);
319 default_font_family = g_strdup(pango_font_description_get_family (font_desc));
321 pango_font_description_free (font_desc);
323 if (!default_font_family)
324 return g_strdup (
"Arial");
325 else if (g_str_has_prefix (default_font_family,
".AppleSystemUIFont"))
327 g_free (default_font_family);
328 return g_strdup (
"Arial");
331 return default_font_family;
335 gnc_saved_reports_write_internal (
const gchar *file,
const gchar *contents, gboolean overwrite)
337 gboolean success = TRUE;
341 gint flags = O_WRONLY | O_CREAT | (overwrite ? O_TRUNC : O_APPEND);
347 if (strstr(file,
"backup"))
350 fd = g_open (file, flags, 0666);
353 PWARN(
"Cannot open file %s: %s\n", file, strerror(errno));
357 length = strlen (contents);
358 written = write(fd, contents, length);
362 PWARN(
"Cannot write to file %s: %s\n", file, strerror(errno));
365 else if (written != length)
368 PWARN(
"File %s truncated (provided %d, written %d)",
369 file, length, (
int)written);
373 else if (close(fd) == -1)
374 PWARN(
"Close failed for file %s: %s", file, strerror(errno));
380 gboolean gnc_saved_reports_backup (
void)
382 gboolean success = FALSE;
385 gchar *contents = NULL;
386 GError *save_error = NULL;
388 if (g_file_test (saved_rpts_path, G_FILE_TEST_EXISTS))
390 if (!g_file_get_contents (saved_rpts_path, &contents, NULL, &save_error))
392 PWARN (
"Couldn't read contents of %s.\nReason: %s", saved_rpts_path, save_error->message);
393 g_error_free (save_error);
399 DEBUG (
"creating backup of file %s", saved_rpts_bkp_path);
400 success = gnc_saved_reports_write_internal (saved_rpts_bkp_path, contents, TRUE);
403 g_free (saved_rpts_path);
404 g_free (saved_rpts_bkp_path);
411 gnc_saved_reports_write_to_file (
const gchar* report_def, gboolean overwrite)
413 gboolean success = FALSE;
418 DEBUG (
"writing to %s", saved_rpts_path);
419 success = gnc_saved_reports_write_internal (saved_rpts_path, report_def, overwrite);
422 g_free (saved_rpts_path);
428 gnc_get_optiondb_from_dispatcher(SCM dispatcher)
430 SCM get_options = scm_c_eval_string(
"gnc:optiondb");
431 if (dispatcher == SCM_BOOL_F)
433 auto scm_ptr{scm_call_1(get_options, dispatcher)};
434 auto smob{!scm_is_null(scm_ptr) && SCM_INSTANCEP(scm_ptr) &&
435 scm_is_true(scm_slot_exists_p(scm_ptr, SCM_EOL)) ?
436 scm_slot_ref(scm_ptr, SCM_EOL) : (scm_ptr)};
438 void *c_ptr{
nullptr};
439 if (!SCM_NULLP(smob))
441 if (SCM_POINTER_P(smob))
442 c_ptr = SCM_POINTER_VALUE(smob);
444 c_ptr =
reinterpret_cast<void*
>(SCM_CELL_WORD_1(smob));
449 auto u_ptr{
static_cast<std::unique_ptr<GncOptionDB>*
>(c_ptr)};
Holds all of the options for a book, report, or stylesheet, organized by GncOptionSections.
gchar * gnc_build_userdata_path(const gchar *filename)
Make a path to filename in the user's gnucash data directory.
#define PINFO(format, args...)
Print an informational note.
#define DEBUG(format, args...)
Print a debugging message.
#define PWARN(format, args...)
Log a warning.
All type declarations for the whole Gnucash engine.
The primary C++ interface to options for books, reports, and stylesheets.
File path resolution utility functions.