From f147b5439347e14bb8affc08ec9adbc3d25998fb Mon Sep 17 00:00:00 2001
From: Přemysl Eric Janouch
Date: Fri, 15 Oct 2021 13:37:29 +0200
Subject: sdgui: load dictionaries from sdtui configuration
---
src/sdgui.c | 67 +++++++++++++++++++++++++++------
src/sdtui.c | 122 +++++-------------------------------------------------------
src/utils.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/utils.h | 9 ++++-
4 files changed, 190 insertions(+), 126 deletions(-)
(limited to 'src')
diff --git a/src/sdgui.c b/src/sdgui.c
index c547760..cc2a042 100644
--- a/src/sdgui.c
+++ b/src/sdgui.c
@@ -53,9 +53,8 @@ g;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static gboolean
-dictionary_load (Dictionary *self, gchar *filename, GError **e)
+dictionary_load (Dictionary *self, GError **e)
{
- self->filename = filename;
if (!(self->dict = stardict_dict_new (self->filename, e)))
return FALSE;
@@ -69,22 +68,62 @@ dictionary_load (Dictionary *self, gchar *filename, GError **e)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-static gboolean
-init (gchar **filenames, GError **e)
+static void
+init (gchar **filenames)
{
while (filenames[g.dictionaries_len])
g.dictionaries_len++;
g.dictionaries = g_malloc0_n (sizeof *g.dictionaries, g.dictionaries_len);
+ for (gsize i = 0; i < g.dictionaries_len; i++)
+ g.dictionaries[i].filename = filenames[i];
+}
+
+// TODO: try to deduplicate, similar to app_load_config_values()
+static gboolean
+init_from_key_file (GKeyFile *kf, GError **error)
+{
+ const gchar *dictionaries = "Dictionaries";
+ gchar **names =
+ g_key_file_get_keys (kf, dictionaries, &g.dictionaries_len, NULL);
+ if (!names)
+ return TRUE;
+
+ g.dictionaries = g_malloc0_n (sizeof *g.dictionaries, g.dictionaries_len);
+ for (gsize i = 0; i < g.dictionaries_len; i++)
+ g.dictionaries[i].name = names[i];
+ g_free (names);
+
for (gsize i = 0; i < g.dictionaries_len; i++)
{
Dictionary *dict = &g.dictionaries[i];
- if (!dictionary_load (dict, filenames[i], e))
+ gchar *path =
+ g_key_file_get_string (kf, dictionaries, dict->name, error);
+ if (!path)
return FALSE;
+
+ // Try to resolve relative paths and expand tildes
+ if (!(dict->filename =
+ resolve_filename (path, resolve_relative_config_filename)))
+ dict->filename = path;
+ else
+ g_free (path);
}
return TRUE;
}
+static gboolean
+init_from_config (GError **error)
+{
+ GKeyFile *key_file = load_project_config_file (error);
+ if (!key_file)
+ return FALSE;
+
+ gboolean result = init_from_key_file (key_file, error);
+ g_key_file_free (key_file);
+ return result;
+}
+
static void
search (Dictionary *dict)
{
@@ -203,7 +242,7 @@ main (int argc, char *argv[])
GOptionEntry option_entries[] =
{
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames,
- NULL, N_("FILE...")},
+ NULL, N_("[FILE]...")},
{},
};
@@ -217,14 +256,18 @@ main (int argc, char *argv[])
return 1;
}
- if (!filenames)
- {
- // TODO: eventually just load all dictionaries from configuration
- die_with_dialog ("No arguments have been passed.");
- }
- if (!init (filenames, &error))
+ if (filenames)
+ init (filenames);
+ else if (!init_from_config (&error) && error)
die_with_dialog (error->message);
+ for (gsize i = 0; i < g.dictionaries_len; i++)
+ if (!dictionary_load (&g.dictionaries[i], &error))
+ die_with_dialog (error->message);
+ if (!g.dictionaries_len)
+ die_with_dialog (_("No dictionaries found either in "
+ "the configuration or on the command line"));
+
// Some Adwaita stupidity
const char *style = "notebook header tab { padding: 2px 8px; margin: 0; }";
diff --git a/src/sdtui.c b/src/sdtui.c
index 1158d05..caf08e6 100644
--- a/src/sdtui.c
+++ b/src/sdtui.c
@@ -28,13 +28,11 @@
#include
#include
#include
-#include
#include
#include
#include
#include
-#include
#include // input
#include // output
@@ -96,94 +94,6 @@ add_read_watch (int fd, GIOFunc func, gpointer user_data)
return res;
}
-// At times, GLib even with its sheer size is surprisingly useless,
-// and I need to port some code over from "liberty".
-
-static gchar **
-get_xdg_config_dirs (void)
-{
- GPtrArray *paths = g_ptr_array_new ();
- g_ptr_array_add (paths, (gpointer) g_get_user_config_dir ());
- for (const gchar *const *system = g_get_system_config_dirs ();
- *system; system++)
- g_ptr_array_add (paths, (gpointer) *system);
- g_ptr_array_add (paths, NULL);
- return (gchar **) g_ptr_array_free (paths, FALSE);
-}
-
-static gchar *
-resolve_relative_filename_generic
- (gchar **paths, const gchar *tail, const gchar *filename)
-{
- for (; *paths; paths++)
- {
- // As per XDG spec, relative paths are ignored
- if (**paths != '/')
- continue;
-
- gchar *file = g_build_filename (*paths, tail, filename, NULL);
- GStatBuf st;
- if (!g_stat (file, &st))
- return file;
- g_free (file);
- }
- return NULL;
-}
-
-static gchar *
-resolve_relative_config_filename (const gchar *filename)
-{
- gchar **paths = get_xdg_config_dirs ();
- gchar *result = resolve_relative_filename_generic
- (paths, PROJECT_NAME, filename);
- g_strfreev (paths);
- return result;
-}
-
-static gchar *
-try_expand_tilde (const gchar *filename)
-{
- size_t until_slash = strcspn (filename, "/");
- if (!until_slash)
- return g_build_filename (g_get_home_dir () ?: "", filename, NULL);
-
- long buf_len = sysconf (_SC_GETPW_R_SIZE_MAX);
- if (buf_len < 0)
- buf_len = 1024;
- struct passwd pwd, *success = NULL;
-
- gchar *user = g_strndup (filename, until_slash);
- gchar *buf = g_malloc (buf_len);
- while (getpwnam_r (user, &pwd, buf, buf_len, &success) == ERANGE)
- buf = g_realloc (buf, buf_len <<= 1);
- g_free (user);
-
- gchar *result = NULL;
- if (success)
- result = g_strdup_printf ("%s%s", pwd.pw_dir, filename + until_slash);
- g_free (buf);
- return result;
-}
-
-static gchar *
-resolve_filename (const gchar *filename, gchar *(*relative_cb) (const char *))
-{
- // Absolute path is absolute
- if (*filename == '/')
- return g_strdup (filename);
-
- // We don't want to use wordexp() for this as it may execute /bin/sh
- if (*filename == '~')
- {
- // Paths to home directories ought to be absolute
- char *expanded = try_expand_tilde (filename + 1);
- if (expanded)
- return expanded;
- g_debug ("failed to expand the home directory in `%s'", filename);
- }
- return relative_cb (filename);
-}
-
// --- Application -------------------------------------------------------------
#define ATTRIBUTE_TABLE(XX) \
@@ -574,8 +484,8 @@ app_load_config_values (Application *self, GKeyFile *kf)
continue;
// Try to resolve relative paths and expand tildes
- gchar *resolved = resolve_filename
- (path, resolve_relative_config_filename);
+ gchar *resolved =
+ resolve_filename (path, resolve_relative_config_filename);
if (resolved)
g_free (path);
else
@@ -588,30 +498,16 @@ app_load_config_values (Application *self, GKeyFile *kf)
}
static void
-app_load_config (Application *self, GError **e)
+app_load_config (Application *self, GError **error)
{
- GKeyFile *kf = g_key_file_new ();
- gchar **paths = get_xdg_config_dirs ();
-
- // XXX: if there are dashes in the final path component,
- // the function tries to replace them with directory separators,
- // which is completely undocumented
- GError *error = NULL;
- g_key_file_load_from_dirs (kf,
- PROJECT_NAME G_DIR_SEPARATOR_S PROJECT_NAME ".conf",
- (const gchar **) paths, NULL, 0, &error);
- g_strfreev (paths);
-
// TODO: proper error handling showing all relevant information;
// we can afford that here since the terminal hasn't been initialized yet
- if (!error)
- app_load_config_values (self, kf);
- else if (error->code == G_KEY_FILE_ERROR_NOT_FOUND)
- g_error_free (error);
- else
- g_propagate_error (e, error);
-
- g_key_file_free (kf);
+ GKeyFile *key_file = load_project_config_file (error);
+ if (key_file)
+ {
+ app_load_config_values (self, key_file);
+ g_key_file_free (key_file);
+ }
}
static void
diff --git a/src/utils.c b/src/utils.c
index 3bba022..612eaaa 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -19,10 +19,14 @@
#include
#include
#include
+#include
+
#include
#include
#include
+#include
+
#include "config.h"
#include "utils.h"
@@ -105,3 +109,117 @@ fatal (const gchar *format, ...)
exit (EXIT_FAILURE);
va_end (ap);
}
+
+// At times, GLib even with its sheer size is surprisingly useless,
+// and I need to port some code over from "liberty".
+
+static gchar **
+get_xdg_config_dirs (void)
+{
+ GPtrArray *paths = g_ptr_array_new ();
+ g_ptr_array_add (paths, (gpointer) g_get_user_config_dir ());
+ for (const gchar *const *system = g_get_system_config_dirs ();
+ *system; system++)
+ g_ptr_array_add (paths, (gpointer) *system);
+ g_ptr_array_add (paths, NULL);
+ return (gchar **) g_ptr_array_free (paths, FALSE);
+}
+
+gchar *
+resolve_relative_filename_generic
+ (gchar **paths, const gchar *tail, const gchar *filename)
+{
+ for (; *paths; paths++)
+ {
+ // As per XDG spec, relative paths are ignored
+ if (**paths != '/')
+ continue;
+
+ gchar *file = g_build_filename (*paths, tail, filename, NULL);
+ GStatBuf st;
+ if (!g_stat (file, &st))
+ return file;
+ g_free (file);
+ }
+ return NULL;
+}
+
+gchar *
+resolve_relative_config_filename (const gchar *filename)
+{
+ gchar **paths = get_xdg_config_dirs ();
+ gchar *result = resolve_relative_filename_generic
+ (paths, PROJECT_NAME, filename);
+ g_strfreev (paths);
+ return result;
+}
+
+static gchar *
+try_expand_tilde (const gchar *filename)
+{
+ size_t until_slash = strcspn (filename, "/");
+ if (!until_slash)
+ return g_build_filename (g_get_home_dir () ?: "", filename, NULL);
+
+ long buf_len = sysconf (_SC_GETPW_R_SIZE_MAX);
+ if (buf_len < 0)
+ buf_len = 1024;
+ struct passwd pwd, *success = NULL;
+
+ gchar *user = g_strndup (filename, until_slash);
+ gchar *buf = g_malloc (buf_len);
+ while (getpwnam_r (user, &pwd, buf, buf_len, &success) == ERANGE)
+ buf = g_realloc (buf, buf_len <<= 1);
+ g_free (user);
+
+ gchar *result = NULL;
+ if (success)
+ result = g_strdup_printf ("%s%s", pwd.pw_dir, filename + until_slash);
+ g_free (buf);
+ return result;
+}
+
+gchar *
+resolve_filename (const gchar *filename, gchar *(*relative_cb) (const char *))
+{
+ // Absolute path is absolute
+ if (*filename == '/')
+ return g_strdup (filename);
+
+ // We don't want to use wordexp() for this as it may execute /bin/sh
+ if (*filename == '~')
+ {
+ // Paths to home directories ought to be absolute
+ char *expanded = try_expand_tilde (filename + 1);
+ if (expanded)
+ return expanded;
+ g_debug ("failed to expand the home directory in `%s'", filename);
+ }
+ return relative_cb (filename);
+}
+
+GKeyFile *
+load_project_config_file (GError **error)
+{
+ GKeyFile *key_file = g_key_file_new ();
+ gchar **paths = get_xdg_config_dirs ();
+ GError *e = NULL;
+
+ // XXX: if there are dashes in the final path component,
+ // the function tries to replace them with directory separators,
+ // which is completely undocumented
+ g_key_file_load_from_dirs (key_file,
+ PROJECT_NAME G_DIR_SEPARATOR_S PROJECT_NAME ".conf",
+ (const gchar **) paths, NULL, 0, &e);
+ g_strfreev (paths);
+ if (!e)
+ return key_file;
+
+ if (e->code == G_KEY_FILE_ERROR_NOT_FOUND)
+ g_error_free (e);
+ else
+ g_propagate_error (error, e);
+
+ g_key_file_free (key_file);
+ return NULL;
+}
diff --git a/src/utils.h b/src/utils.h
index b47daa9..1394f08 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,7 +1,7 @@
/*
* utils.h: miscellaneous utilities
*
- * Copyright (c) 2013 - 2020, Přemysl Eric Janouch
+ * Copyright (c) 2013 - 2021, Přemysl Eric Janouch
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
@@ -43,4 +43,11 @@ gchar *stream_read_string (GDataInputStream *dis, GError **error);
gboolean xstrtoul (unsigned long *out, const char *s, int base);
void fatal (const gchar *format, ...) G_GNUC_PRINTF (1, 2) G_GNUC_NORETURN;
+gchar *resolve_relative_filename_generic
+ (gchar **paths, const gchar *tail, const gchar *filename);
+gchar *resolve_relative_config_filename (const gchar *filename);
+gchar *resolve_filename
+ (const gchar *filename, gchar *(*relative_cb) (const char *));
+GKeyFile *load_project_config_file (GError **error);
+
#endif // ! UTILS_H
--
cgit v1.2.3-70-g09d2