diff options
| -rw-r--r-- | src/sdgui.c | 67 | ||||
| -rw-r--r-- | src/sdtui.c | 122 | ||||
| -rw-r--r-- | src/utils.c | 118 | ||||
| -rw-r--r-- | src/utils.h | 9 | 
4 files changed, 190 insertions, 126 deletions
| 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 <gio/gio.h>  #include <pango/pango.h>  #include <glib/gi18n.h> -#include <glib/gstdio.h>  #include <unistd.h>  #include <poll.h>  #include <errno.h>  #include <signal.h> -#include <pwd.h>  #include <termo.h>  // input  #include <ncurses.h>  // 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 <glib.h>  #include <glib/gprintf.h>  #include <gio/gio.h> +#include <glib/gstdio.h> +  #include <stdlib.h>  #include <errno.h>  #include <stdarg.h> +#include <pwd.h> +  #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 <p@janouch.name> + * Copyright (c) 2013 - 2021, Přemysl Eric Janouch <p@janouch.name>   *   * 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 | 
