diff options
author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:53 -0300 |
---|---|---|
committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:53 -0300 |
commit | 5f01c706267c595de92406a32e7f31ef5056c2d0 (patch) | |
tree | d1e74ef54efc41ada622900fe3e2a50dee44a237 /hardinfo2/util.c | |
parent | 09fcc751ef158898c315ebc9299a0fa3a722d914 (diff) |
New upstream version 2.0.3preupstream/2.0.3pre
Diffstat (limited to 'hardinfo2/util.c')
-rw-r--r-- | hardinfo2/util.c | 1452 |
1 files changed, 1452 insertions, 0 deletions
diff --git a/hardinfo2/util.c b/hardinfo2/util.c new file mode 100644 index 00000000..e12963c0 --- /dev/null +++ b/hardinfo2/util.c @@ -0,0 +1,1452 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> + * + * 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, version 2. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Functions h_strdup_cprintf and h_strconcat are based on GLib version 2.4.6 + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + */ + +#include <config.h> + +#include <report.h> +#include <string.h> +#include <shell.h> +#include <iconcache.h> +#include <hardinfo.h> +#include <gtk/gtk.h> + +#include <binreloc.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#define KiB 1024 +#define MiB 1048576 +#define GiB 1073741824 +#define TiB 1099511627776 +#define PiB 1125899906842624 + +static GSList *modules_list = NULL; + +void sync_manager_clear_entries(void); + +gchar *find_program(gchar *program_name) +{ + int i; + char *temp; + static GHashTable *cache = NULL; + const char *path[] = { "/usr/local/bin", "/usr/local/sbin", + "/usr/bin", "/usr/sbin", + "/bin", "/sbin", + NULL }; + + /* we don't need to call stat() every time: cache the results */ + if (!cache) { + cache = g_hash_table_new(g_str_hash, g_str_equal); + } else if ((temp = g_hash_table_lookup(cache, program_name))) { + return g_strdup(temp); + } + + for (i = 0; path[i]; i++) { + temp = g_build_filename(path[i], program_name, NULL); + + if (g_file_test(temp, G_FILE_TEST_IS_EXECUTABLE)) { + g_hash_table_insert(cache, program_name, g_strdup(temp)); + return temp; + } + + g_free(temp); + } + + /* our search has failed; use GLib's search (which uses $PATH env var) */ + if ((temp = g_find_program_in_path(program_name))) { + g_hash_table_insert(cache, program_name, g_strdup(temp)); + return temp; + } + + return NULL; +} + +gchar *seconds_to_string(unsigned int seconds) +{ + unsigned int hours, minutes, days; + const gchar *days_fmt, *hours_fmt, *minutes_fmt, *seconds_fmt; + gchar *full_fmt, *ret = g_strdup(""); + + minutes = seconds / 60; + seconds %= 60; + hours = minutes / 60; + minutes %= 60; + days = hours / 24; + hours %= 24; + + days_fmt = ngettext("%d day", "%d days", days); + hours_fmt = ngettext("%d hour", "%d hours", hours); + minutes_fmt = ngettext("%d minute", "%d minutes", minutes); + seconds_fmt = ngettext("%d second", "%d seconds", seconds); + + if (days) { + full_fmt = g_strdup_printf("%s %s %s %s", days_fmt, hours_fmt, minutes_fmt, seconds_fmt); + ret = g_strdup_printf(full_fmt, days, hours, minutes, seconds); + } else if (hours) { + full_fmt = g_strdup_printf("%s %s %s", hours_fmt, minutes_fmt, seconds_fmt); + ret = g_strdup_printf(full_fmt, hours, minutes, seconds); + } else if (minutes) { + full_fmt = g_strdup_printf("%s %s", minutes_fmt, seconds_fmt); + ret = g_strdup_printf(full_fmt, minutes, seconds); + } else { + ret = g_strdup_printf(seconds_fmt, seconds); + } + g_free(full_fmt); + return ret; +} + +gchar *size_human_readable(gfloat size) +{ + if (size < KiB) + return g_strdup_printf(_("%.1f B"), size); + if (size < MiB) + return g_strdup_printf(_("%.1f KiB"), size / KiB); + if (size < GiB) + return g_strdup_printf(_("%.1f MiB"), size / MiB); + if (size < TiB) + return g_strdup_printf(_("%.1f GiB"), size / GiB); + if (size < PiB) + return g_strdup_printf(_("%.1f TiB"), size / TiB); + + return g_strdup_printf(_("%.1f PiB"), size / PiB); +} + +char *strend(gchar * str, gchar chr) +{ + if (!str) + return NULL; + + char *p; + if ((p = g_utf8_strchr(str, -1, chr))) + *p = 0; + + return str; +} + +void remove_quotes(gchar * str) +{ + if (!str) + return; + + while (*str == '"') + *(str++) = ' '; + + strend(str, '"'); +} + +void remove_linefeed(gchar * str) +{ + strend(str, '\n'); +} + +void widget_set_cursor(GtkWidget * widget, GdkCursorType cursor_type) +{ + GdkCursor *cursor; + GdkDisplay *display; + GdkWindow *gdk_window; + + display = gtk_widget_get_display(widget); + cursor = gdk_cursor_new_for_display(display, cursor_type); + gdk_window = gtk_widget_get_window(widget); + if (cursor) { + gdk_window_set_cursor(gdk_window, cursor); + gdk_display_flush(display); +#if GTK_CHECK_VERSION(3, 0, 0) + g_object_unref(cursor); +#else + gdk_cursor_unref(cursor); +#endif + } + + while (gtk_events_pending()) + gtk_main_iteration(); +} + +static gboolean __nonblock_cb(gpointer data) +{ + gtk_main_quit(); + return FALSE; +} + +void nonblock_sleep(guint msec) +{ + g_timeout_add(msec, (GSourceFunc) __nonblock_cb, NULL); + gtk_main(); +} + +static void __expand_cb(GtkWidget * widget, gpointer data) +{ + if (GTK_IS_EXPANDER(widget)) { + gtk_expander_set_expanded(GTK_EXPANDER(widget), TRUE); + } else if (GTK_IS_CONTAINER(widget)) { + gtk_container_foreach(GTK_CONTAINER(widget), + (GtkCallback) __expand_cb, NULL); + } +} + +void file_chooser_open_expander(GtkWidget * chooser) +{ + gtk_container_foreach(GTK_CONTAINER(chooser), + (GtkCallback) __expand_cb, NULL); +} + +void file_chooser_add_filters(GtkWidget * chooser, FileTypes * filters) +{ + GtkFileFilter *filter; + gint i; + + for (i = 0; filters[i].name; i++) { + filter = gtk_file_filter_new(); + gtk_file_filter_add_mime_type(filter, filters[i].mime_type); + gtk_file_filter_set_name(filter, filters[i].name); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter); + } +} + +gchar *file_chooser_get_extension(GtkWidget * chooser, FileTypes * filters) +{ + GtkFileFilter *filter; + const gchar *filter_name; + gint i; + + filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(chooser)); + filter_name = gtk_file_filter_get_name(filter); + for (i = 0; filters[i].name; i++) { + if (g_str_equal(filter_name, filters[i].name)) { + return filters[i].extension; + } + } + + return NULL; +} + +gpointer file_types_get_data_by_name(FileTypes * filters, gchar * filename) +{ + gint i; + + for (i = 0; filters[i].name; i++) { + if (g_str_has_suffix(filename, filters[i].extension)) { + return filters[i].data; + } + } + + return NULL; +} + +gchar *file_chooser_build_filename(GtkWidget * chooser, gchar * extension) +{ + gchar *filename = + gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)); + gchar *retval; + + if (g_str_has_suffix(filename, extension)) { + return filename; + } + + retval = g_strconcat(filename, extension, NULL); + g_free(filename); + + return retval; +} + +gboolean binreloc_init(gboolean try_hardcoded) +{ + GError *error = NULL; + gchar *tmp; + + DEBUG("initializing binreloc (hardcoded = %d)", try_hardcoded); + + /* If the runtime data directories we previously found, don't even try + to find them again. */ + if (params.path_data && params.path_lib) { + DEBUG("data and lib path already found."); + return TRUE; + } + + if (try_hardcoded || !gbr_init(&error)) { + /* We were asked to try hardcoded paths or BinReloc failed to initialize. */ + params.path_data = g_strdup(PREFIX); + params.path_lib = g_strdup(LIBPREFIX); + + if (error) { + g_error_free(error); + } + + DEBUG("%strying hardcoded paths.", + try_hardcoded ? "" : "binreloc init failed. "); + } else { + /* If we were able to initialize BinReloc, build the default data + and library paths. */ + DEBUG("done, trying to use binreloc paths."); + + tmp = gbr_find_data_dir(PREFIX); + params.path_data = g_build_filename(tmp, "hardinfo2", NULL); + g_free(tmp); + + tmp = gbr_find_lib_dir(PREFIX); + params.path_lib = g_build_filename(tmp, "hardinfo2", NULL); + g_free(tmp); + } + + DEBUG("searching for runtime data on these locations:"); + DEBUG(" lib: %s", params.path_lib); + DEBUG(" data: %s", params.path_data); + + /* Try to see if the benchmark test data file isn't missing. This isn't the + definitive test, but it should do okay for most situations. */ + tmp = g_build_filename(params.path_data, "benchmark.data", NULL); + if (!g_file_test(tmp, G_FILE_TEST_EXISTS)) { + DEBUG("runtime data not found"); + + g_free(params.path_data); + g_free(params.path_lib); + g_free(tmp); + + params.path_data = params.path_lib = NULL; + + if (try_hardcoded) { + /* We tried the hardcoded paths, but still was unable to find the + runtime data. Give up. */ + DEBUG("giving up"); + return FALSE; + } else { + /* Even though BinReloc worked OK, the runtime data was not found. + Try the hardcoded paths. */ + DEBUG("trying to find elsewhere"); + return binreloc_init(TRUE); + } + } + g_free(tmp); + + DEBUG("runtime data found!"); + /* We found the runtime data; hope everything is fine */ + return TRUE; +} + +static void +log_handler(const gchar * log_domain, + GLogLevelFlags log_level, + const gchar * message, gpointer user_data) +{ + if (!params.gui_running) { + /* No GUI running: spit the message to the terminal */ + g_print("\n\n*** %s: %s\n\n", + (log_level & G_LOG_FLAG_FATAL) ? _("Error") : _("Warning"), + message); + } else { + /* Hooray! We have a GUI running! */ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new_with_markup(NULL, GTK_DIALOG_MODAL, + (log_level & + G_LOG_FLAG_FATAL) ? + GTK_MESSAGE_ERROR : + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CLOSE, + "<big><b>%s</b></big>\n\n%s", + (log_level & + G_LOG_FLAG_FATAL) ? + _("Fatal Error") : + _("Warning"), message); + + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + } +} + +void parameters_init(int *argc, char ***argv, ProgramParameters * param) +{ + static gboolean create_report = FALSE; + static gboolean force_all_details = FALSE; + static gboolean show_version = FALSE; + static gboolean list_modules = FALSE; + static gboolean autoload_deps = FALSE; + static gboolean skip_benchmarks = FALSE; + static gboolean quiet = FALSE; + static gchar *report_format = NULL; + static gchar *run_benchmark = NULL; + static gchar *result_format = NULL; + static gchar *bench_user_note = NULL; + static gchar **use_modules = NULL; + static gint max_bench_results = 50; + + static GOptionEntry options[] = { + { + .long_name = "quiet", + .short_name = 'q', + .arg = G_OPTION_ARG_NONE, + .arg_data = &quiet, + .description = N_("do not print status messages to standard output")}, + { + .long_name = "generate-report", + .short_name = 'r', + .arg = G_OPTION_ARG_NONE, + .arg_data = &create_report, + .description = N_("creates a report and prints to standard output")}, + { + .long_name = "report-format", + .short_name = 'f', + .arg = G_OPTION_ARG_STRING, + .arg_data = &report_format, + .description = N_("chooses a report format ([text], html)")}, + { + .long_name = "run-benchmark", + .short_name = 'b', + .arg = G_OPTION_ARG_STRING, + .arg_data = &run_benchmark, + .description = N_("run benchmark; requires benchmark.so to be loaded")}, + { + .long_name = "user-note", + .short_name = 'u', + .arg = G_OPTION_ARG_STRING, + .arg_data = &bench_user_note, + .description = N_("note attached to benchmark results")}, + { + .long_name = "result-format", + .short_name = 'g', + .arg = G_OPTION_ARG_STRING, + .arg_data = &result_format, + .description = N_("benchmark result format ([short], conf, shell)")}, + { + .long_name = "max-results", + .short_name = 'n', + .arg = G_OPTION_ARG_INT, + .arg_data = &max_bench_results, + .description = N_("maximum number of benchmark results to include (-1 for no limit, default is 50)")}, +//#if NOT_DEFINED + { + .long_name = "list-modules", + .short_name = 'l', + .arg = G_OPTION_ARG_NONE, + .arg_data = &list_modules, + .description = N_("lists modules")}, + { + .long_name = "load-module", + .short_name = 'm', + .arg = G_OPTION_ARG_STRING_ARRAY, + .arg_data = &use_modules, + .description = N_("specify module to load")}, + { + .long_name = "autoload-deps", + .short_name = 'a', + .arg = G_OPTION_ARG_NONE, + .arg_data = &autoload_deps, + .description = N_("automatically load module dependencies")}, +//#endif + { + .long_name = "version", + .short_name = 'v', + .arg = G_OPTION_ARG_NONE, + .arg_data = &show_version, + .description = N_("shows program version and quit")}, + { + .long_name = "skip-benchmarks", + .short_name = 's', + .arg = G_OPTION_ARG_NONE, + .arg_data = &skip_benchmarks, + .description = N_("do not run benchmarks")}, + { + .long_name = "very-verbose", + .short_name = 'w', /* like -vv */ + .arg = G_OPTION_ARG_NONE, + .arg_data = &force_all_details, + .description = N_("show all details")}, + {NULL} + }; + GOptionContext *ctx; + + ctx = g_option_context_new(_("- System Profiler and Benchmark tool")); + g_option_context_set_ignore_unknown_options(ctx, FALSE); + g_option_context_set_help_enabled(ctx, TRUE); + + g_option_context_add_main_entries(ctx, options, *(argv)[0]); + g_option_context_parse(ctx, argc, argv, NULL); + + g_option_context_free(ctx); + + if (*argc >= 2) { + g_print(_("Unrecognized arguments.\n" + "Try ``%s --help'' for more information.\n"), *(argv)[0]); + exit(1); + } + + param->create_report = create_report; + param->report_format = REPORT_FORMAT_TEXT; + param->show_version = show_version; + param->list_modules = list_modules; + param->use_modules = use_modules; + param->run_benchmark = run_benchmark; + param->result_format = result_format; + param->max_bench_results = max_bench_results; + param->autoload_deps = autoload_deps; + param->skip_benchmarks = skip_benchmarks; + param->force_all_details = force_all_details; + param->quiet = quiet; + param->argv0 = *(argv)[0]; + + if (report_format) { + if (g_str_equal(report_format, "html")) + param->report_format = REPORT_FORMAT_HTML; + if (g_str_equal(report_format, "shell")) + param->report_format = REPORT_FORMAT_SHELL; + } + + /* clean user note */ + if (bench_user_note) { + char *p = NULL; + while(p = strchr(bench_user_note, ';')) { *p = ','; } + param->bench_user_note = + gg_key_file_parse_string_as_value(bench_user_note, '|'); + } + + /* html ok? + * gui: yes + * report html: yes + * report text: no + * anything else? */ + param->markup_ok = TRUE; + if (param->create_report && param->report_format != REPORT_FORMAT_HTML) + param->markup_ok = FALSE; + + // TODO: fmt_opts: FMT_OPT_ATERM, FMT_OPT_HTML, FMT_OPT_PANGO... + param->fmt_opts = FMT_OPT_NONE; + + gchar *confdir = g_build_filename(g_get_user_config_dir(), "hardinfo2", NULL); + if (!g_file_test(confdir, G_FILE_TEST_EXISTS)) { + mkdir(confdir, 0744); + } + g_free(confdir); +} + +gboolean ui_init(int *argc, char ***argv) +{ + DEBUG("initializing gtk+ UI"); + + g_set_application_name("HardInfo2"); + g_log_set_handler(NULL, + G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | + G_LOG_LEVEL_ERROR, log_handler, NULL); + + return gtk_init_check(argc, argv); +} + +/* Copyright: Jens Låås, SLU 2002 */ +gchar *strreplacechr(gchar * string, gchar * replace, gchar new_char) +{ + gchar *s; + for (s = string; *s; s++) + if (strchr(replace, *s)) + *s = new_char; + + return string; +} + +gchar *strreplace(gchar *string, gchar *replace, gchar *replacement) +{ + gchar **tmp, *ret; + + tmp = g_strsplit(string, replace, 0); + ret = g_strjoinv(replacement, tmp); + g_strfreev(tmp); + + return ret; +} + +static GHashTable *__module_methods = NULL; + +static void module_register_methods(ShellModule * module) +{ + const ShellModuleMethod *(*get_methods)(void); + gchar *method_name; + + if (__module_methods == NULL) { + __module_methods = g_hash_table_new(g_str_hash, g_str_equal); + } + + if (g_module_symbol + (module->dll, "hi_exported_methods", (gpointer)&get_methods)) { + const ShellModuleMethod *methods; + + for (methods = get_methods(); methods->name; methods++) { + ShellModuleMethod method = *methods; + gchar *name = g_path_get_basename(g_module_name(module->dll)); + gchar *simple_name = strreplace(name, "lib", ""); + + strend(simple_name, '.'); + + method_name = g_strdup_printf("%s::%s", simple_name, method.name); + g_hash_table_insert(__module_methods, method_name, + method.function); + g_free(name); + g_free(simple_name); + } + } + +} + +gchar *module_call_method(gchar * method) +{ + gchar *(*function) (void); + + if (__module_methods == NULL) { + return NULL; + } + + function = g_hash_table_lookup(__module_methods, method); + return function ? g_strdup(function()) : NULL; +} + +/* FIXME: varargs? */ +gchar *module_call_method_param(gchar * method, gchar * parameter) +{ + gchar *(*function) (gchar *param); + + if (__module_methods == NULL) { + return NULL; + } + + function = g_hash_table_lookup(__module_methods, method); + return function ? g_strdup(function(parameter)) : NULL; +} + +static gboolean remove_module_methods(gpointer key, gpointer value, gpointer data) +{ + return g_str_has_prefix(key, data); +} + +static void module_unload(ShellModule * module) +{ + GSList *entry; + + if (module->dll) { + gchar *name; + + if (module->deinit) { + DEBUG("cleaning up module \"%s\"", module->name); + module->deinit(); + } else { + DEBUG("module \"%s\" does not need cleanup", module->name); + } + + name = g_path_get_basename(g_module_name(module->dll)); + g_hash_table_foreach_remove(__module_methods, remove_module_methods, name); + + g_module_close(module->dll); + g_free(name); + } + + g_free(module->name); + g_object_unref(module->icon); + + for (entry = module->entries; entry; entry = entry->next) { + ShellModuleEntry *e = (ShellModuleEntry *)entry->data; + + g_source_remove_by_user_data(e); + g_free(e); + } + + g_slist_free(module->entries); + g_free(module); +} + + +void module_unload_all(void) +{ + Shell *shell; + GSList *module, *merge_id; + + shell = shell_get_main_shell(); + + sync_manager_clear_entries(); + shell_clear_timeouts(shell); + shell_clear_tree_models(shell); + shell_clear_field_updates(); + shell_set_title(shell, NULL); + + for (module = shell->tree->modules; module; module = module->next) { + module_unload((ShellModule *)module->data); + } + + for (merge_id = shell->merge_ids; merge_id; merge_id = merge_id->next) { + gtk_ui_manager_remove_ui(shell->ui_manager, + GPOINTER_TO_INT(merge_id->data)); + } + g_slist_free(shell->tree->modules); + g_slist_free(shell->merge_ids); + + shell->merge_ids = NULL; + shell->tree->modules = NULL; + shell->selected = NULL; +} + +static ShellModule *module_load(gchar * filename) +{ + ShellModule *module; + gchar *tmp; + + module = g_new0(ShellModule, 1); + + if (params.gui_running) { + gchar *tmpicon, *dot, *simple_name; + + tmpicon = g_strdup(filename); + dot = g_strrstr(tmpicon, "." G_MODULE_SUFFIX); + + *dot = '\0'; + + simple_name = strreplace(tmpicon, "lib", ""); + + tmp = g_strdup_printf("%s.png", simple_name); + module->icon = icon_cache_get_pixbuf(tmp); + + g_free(tmp); + g_free(tmpicon); + g_free(simple_name); + } + + tmp = g_build_filename(params.path_lib, "modules", filename, NULL); + module->dll = g_module_open(tmp, G_MODULE_BIND_LAZY); + DEBUG("gmodule resource for ``%s'' is %p (%s)", tmp, module->dll, g_module_error()); + g_free(tmp); + + if (module->dll) { + void (*init) (void); + ModuleEntry *(*get_module_entries) (void); + gint(*weight_func) (void); + gchar *(*name_func) (void); + ModuleEntry *entries; + gint i = 0; + + if (!g_module_symbol(module->dll, "hi_module_get_entries", (gpointer) & get_module_entries) || + !g_module_symbol(module->dll, "hi_module_get_name", (gpointer) & name_func)) { + DEBUG("cannot find needed symbols; is ``%s'' a real module?", filename); + goto failed; + } + + if (g_module_symbol(module->dll, "hi_module_init", (gpointer) & init)) { + DEBUG("initializing module ``%s''", filename); + init(); + } + + g_module_symbol(module->dll, "hi_module_get_weight", + (gpointer) & weight_func); + + module->weight = weight_func ? weight_func() : 0; + module->name = name_func(); + + g_module_symbol(module->dll, "hi_module_get_about", + (gpointer) & (module->aboutfunc)); + g_module_symbol(module->dll, "hi_module_deinit", + (gpointer) & (module->deinit)); + g_module_symbol(module->dll, "hi_module_get_summary", + (gpointer) & (module->summaryfunc)); + + entries = get_module_entries(); + while (entries[i].name) { + if (*entries[i].name == '#') { i++; continue; } /* skip */ + + ShellModuleEntry *entry = g_new0(ShellModuleEntry, 1); + + if (params.gui_running) { + entry->icon = icon_cache_get_pixbuf(entries[i].icon); + } + entry->icon_file = entries[i].icon; + + g_module_symbol(module->dll, "hi_more_info", + (gpointer) & (entry->morefunc)); + g_module_symbol(module->dll, "hi_get_field", + (gpointer) & (entry->fieldfunc)); + g_module_symbol(module->dll, "hi_note_func", + (gpointer) & (entry->notefunc)); + + entry->name = _(entries[i].name); //gettext unname N_() in computer.c line 67 etc... + entry->scan_func = entries[i].scan_callback; + entry->func = entries[i].callback; + entry->number = i; + entry->flags = entries[i].flags; + + module->entries = g_slist_append(module->entries, entry); + + i++; + } + + DEBUG("registering methods for module ``%s''", filename); + module_register_methods(module); + } else { + DEBUG("cannot g_module_open(``%s''). permission problem?", filename); + failed: + DEBUG("loading module %s failed: %s", filename, g_module_error()); + + g_free(module->name); + g_free(module); + module = NULL; + } + + return module; +} + +static gboolean module_in_module_list(gchar * module, gchar ** module_list) +{ + int i = 0; + + if (!module_list) + return TRUE; + + for (; module_list[i]; i++) { + if (g_str_equal(module_list[i], module)) + return TRUE; + } + + return FALSE; +} + +static gint module_cmp(gconstpointer m1, gconstpointer m2) +{ + ShellModule *a = (ShellModule *) m1; + ShellModule *b = (ShellModule *) m2; + + return a->weight - b->weight; +} + +#if 0 +static void module_entry_free(gpointer data, gpointer user_data) +{ + ShellModuleEntry *entry = (ShellModuleEntry *) data; + + if (entry) { + g_free(entry->name); + g_object_unref(entry->icon); + + g_free(entry); + } +} +#endif + +const ModuleAbout *module_get_about(ShellModule * module) +{ + if (module->aboutfunc) { + return module->aboutfunc(); + } + + return NULL; +} + +static GSList *modules_check_deps(GSList * modules) +{ + GSList *mm; + ShellModule *module; + + for (mm = modules; mm; mm = mm->next) { + gchar **(*get_deps) (void); + gchar **deps; + gint i; + + module = (ShellModule *) mm->data; + + if (g_module_symbol(module->dll, "hi_module_get_dependencies", + (gpointer) & get_deps)) { + for (i = 0, deps = get_deps(); deps[i]; i++) { + GSList *l; + ShellModule *m; + gboolean found = FALSE; + + for (l = modules; l && !found; l = l->next) { + m = (ShellModule *) l->data; + gchar *name = g_path_get_basename(g_module_name(m->dll)); + + found = g_str_equal(name, deps[i]); + g_free(name); + } + + if (!found) { + if (params.autoload_deps) { + ShellModule *mod = module_load(deps[i]); + + if (mod) + modules = g_slist_append(modules, mod); + modules = modules_check_deps(modules); /* re-check dependencies */ + + break; + } + + if (params.gui_running) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new(NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Module \"%s\" depends on module \"%s\", load it?"), + module->name, + deps[i]); + gtk_dialog_add_buttons(GTK_DIALOG(dialog), + "_No", + GTK_RESPONSE_REJECT, + "_Open", + GTK_RESPONSE_ACCEPT, NULL); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == + GTK_RESPONSE_ACCEPT) { + ShellModule *mod = module_load(deps[i]); + + if (mod) + modules = g_slist_prepend(modules, mod); + modules = modules_check_deps(modules); /* re-check dependencies */ + } else { + g_error("HardInfo2 cannot run without loading the additional module."); + exit(1); + } + + gtk_widget_destroy(dialog); + } else { + g_error(_("Module \"%s\" depends on module \"%s\"."), + module->name, deps[i]); + } + } + } + } + } + + return modules; +} + + +GSList *modules_get_list() +{ + return modules_list; +} + +static GSList *modules_load(gchar ** module_list) +{ + GDir *dir; + GSList *modules = NULL; + ShellModule *module; + gchar *filename; + + filename = g_build_filename(params.path_lib, "modules", NULL); + dir = g_dir_open(filename, 0, NULL); + g_free(filename); + + if (dir) { + GList *filenames = NULL; + while ((filename = (gchar *)g_dir_read_name(dir))) { + if (g_strrstr(filename, "." G_MODULE_SUFFIX) && + module_in_module_list(filename, module_list)) { + if (g_strrstr(filename, "devices." G_MODULE_SUFFIX)) { + filenames = g_list_prepend(filenames, filename); + } + else { + filenames = g_list_append(filenames, filename); + } + } + } + GList* item = NULL; + while (item = g_list_first(filenames)) { + if (module = module_load((gchar *)item->data)) { + modules = g_slist_prepend(modules, module); + } + filenames = g_list_delete_link(filenames, item); + } +#if GLIB_CHECK_VERSION(2,44,0) + //FIXME change this to not use g_steal_pointer + g_list_free_full (g_steal_pointer (&filenames), g_object_unref); +#endif + g_dir_close(dir); + } + + modules = modules_check_deps(modules); + + if (g_slist_length(modules) == 0) { + if (params.use_modules == NULL) { + g_error + (_("No module could be loaded. Check permissions on \"%s\" and try again."), + params.path_lib); + } else { + g_error + (_("No module could be loaded. Please use hardinfo2 -l to list all avai" + "lable modules and try again with a valid module list.")); + + } + } + + modules_list = g_slist_sort(modules, module_cmp); + return modules_list; +} + +GSList *modules_load_selected(void) +{ + return modules_load(params.use_modules); +} + +GSList *modules_load_all(void) +{ + return modules_load(NULL); +} + +gint tree_view_get_visible_height(GtkTreeView * tv) +{ + GtkTreePath *path; + GdkRectangle rect; + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model(tv); + gint nrows = 1; + + path = gtk_tree_path_new_first(); + gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect); + + /* FIXME: isn't there any easier way to tell the number of rows? */ + gtk_tree_model_get_iter_first(model, &iter); + do { + nrows++; + } while (gtk_tree_model_iter_next(model, &iter)); + + gtk_tree_path_free(path); + + return nrows * rect.height; +} + +void module_entry_scan_all_except(ModuleEntry * entries, gint except_entry) +{ + ModuleEntry entry; + gint i = 0; + void (*scan_callback) (gboolean reload); + gchar *text; + + shell_view_set_enabled(FALSE); + + for (entry = entries[0]; entry.name; entry = entries[++i]) { + if (i == except_entry) + continue; + + text = g_strdup_printf(_("Scanning: %s..."), _(entry.name)); + shell_status_update(text); + g_free(text); + + if ((scan_callback = entry.scan_callback)) { + scan_callback(FALSE); + } + } + + shell_view_set_enabled(TRUE); + shell_status_update(_("Done.")); +} + +void module_entry_scan_all(ModuleEntry * entries) +{ + module_entry_scan_all_except(entries, -1); +} + +void module_entry_reload(ShellModuleEntry * module_entry) +{ + + if (module_entry->scan_func) { + module_entry->scan_func(TRUE); + } +} + +void module_entry_scan(ShellModuleEntry * module_entry) +{ + if (module_entry->scan_func) { + module_entry->scan_func(FALSE); + } +} + +gchar *module_entry_get_field(ShellModuleEntry * module_entry, gchar * field) +{ + if (module_entry->fieldfunc) { + return module_entry->fieldfunc(field); + } + + return NULL; +} + +gchar *module_entry_function(ShellModuleEntry * module_entry) +{ + if (module_entry->func) { + return module_entry->func(); + } + + return NULL; +} + +gchar *module_entry_get_moreinfo(ShellModuleEntry * module_entry, gchar * field) +{ + if (module_entry->morefunc) { + return module_entry->morefunc(field); + } + + return NULL; +} + +const gchar *module_entry_get_note(ShellModuleEntry * module_entry) +{ + if (module_entry->notefunc) { + return module_entry->notefunc(module_entry->number); + } + + return NULL; +} + +gchar *h_strdup_cprintf(const gchar * format, gchar * source, ...) +{ + gchar *buffer, *retn; + va_list args; + + va_start(args, source); + buffer = g_strdup_vprintf(format, args); + va_end(args); + + if (source) { + retn = g_strconcat(source, buffer, NULL); + g_free(buffer); + g_free(source); + } else { + retn = buffer; + } + + return retn; +} + +gchar *h_strconcat(gchar * string1, ...) +{ + gsize l; + va_list args; + gchar *s; + gchar *concat; + gchar *ptr; + + if (!string1) + return NULL; + + l = 1 + strlen(string1); + va_start(args, string1); + s = va_arg(args, gchar *); + while (s) { + l += strlen(s); + s = va_arg(args, gchar *); + } + va_end(args); + + concat = g_new(gchar, l); + ptr = concat; + + ptr = g_stpcpy(ptr, string1); + va_start(args, string1); + s = va_arg(args, gchar *); + while (s) { + ptr = g_stpcpy(ptr, s); + s = va_arg(args, gchar *); + } + va_end(args); + + g_free(string1); + + return concat; +} + +static gboolean h_hash_table_remove_all_true(gpointer key, gpointer data, gpointer user_data) +{ + return TRUE; +} + +void +h_hash_table_remove_all(GHashTable *hash_table) +{ + g_hash_table_foreach_remove(hash_table, + h_hash_table_remove_all_true, + NULL); +} + +gfloat +h_sysfs_read_float(const gchar *endpoint, const gchar *entry) +{ + gchar *tmp, *buffer; + gfloat return_value = 0.0f; + + tmp = g_build_filename(endpoint, entry, NULL); + if (g_file_get_contents(tmp, &buffer, NULL, NULL)) + return_value = atof(buffer); + + g_free(tmp); + g_free(buffer); + + return return_value; +} + +gint +h_sysfs_read_int(const gchar *endpoint, const gchar *entry) +{ + gchar *tmp, *buffer; + gint return_value = 0; + + tmp = g_build_filename(endpoint, entry, NULL); + if (g_file_get_contents(tmp, &buffer, NULL, NULL)) + return_value = atoi(buffer); + + g_free(tmp); + g_free(buffer); + + return return_value; +} + +gint +h_sysfs_read_hex(const gchar *endpoint, const gchar *entry) +{ + gchar *tmp, *buffer; + gint return_value = 0; + + tmp = g_build_filename(endpoint, entry, NULL); + if (g_file_get_contents(tmp, &buffer, NULL, NULL)) + return_value = (gint) strtoll(buffer, NULL, 16); + + g_free(tmp); + g_free(buffer); + + return return_value; +} + +gchar * +h_sysfs_read_string(const gchar *endpoint, const gchar *entry) +{ + gchar *tmp, *return_value; + + tmp = g_build_filename(endpoint, entry, NULL); + if (!g_file_get_contents(tmp, &return_value, NULL, NULL)) { + g_free(return_value); + + return_value = NULL; + } else { + return_value = g_strstrip(return_value); + } + + g_free(tmp); + + return return_value; +} + +static GHashTable *_moreinfo = NULL; + +void +moreinfo_init(void) +{ + if (G_UNLIKELY(_moreinfo)) { + DEBUG("moreinfo already initialized"); + return; + } + DEBUG("initializing moreinfo"); + _moreinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); +} + +void +moreinfo_shutdown(void) +{ + if (G_UNLIKELY(!_moreinfo)) { + DEBUG("moreinfo not initialized"); + return; + } + DEBUG("shutting down moreinfo"); + g_hash_table_destroy(_moreinfo); + _moreinfo = NULL; +} + +void +moreinfo_add_with_prefix(gchar *prefix, gchar *key, gchar *value) +{ + if (G_UNLIKELY(!_moreinfo)) { + DEBUG("moreinfo not initialized"); + return; + } + + if (prefix) { + gchar *hashkey = g_strconcat(prefix, ":", key, NULL); + g_hash_table_insert(_moreinfo, hashkey, value); + return; + } + + g_hash_table_insert(_moreinfo, g_strdup(key), value); +} + +void +moreinfo_add(gchar *key, gchar *value) +{ + moreinfo_add_with_prefix(NULL, key, value); +} + +static gboolean +_moreinfo_del_cb(gpointer key, gpointer value, gpointer data) +{ + return g_str_has_prefix(key, data); +} + +void +moreinfo_del_with_prefix(gchar *prefix) +{ + if (G_UNLIKELY(!_moreinfo)) { + DEBUG("moreinfo not initialized"); + return; + } + + g_hash_table_foreach_remove(_moreinfo, _moreinfo_del_cb, prefix); +} + +void +moreinfo_clear(void) +{ + if (G_UNLIKELY(!_moreinfo)) { + DEBUG("moreinfo not initialized"); + return; + } + h_hash_table_remove_all(_moreinfo); +} + +gchar * +moreinfo_lookup_with_prefix(gchar *prefix, gchar *key) +{ + if (G_UNLIKELY(!_moreinfo)) { + DEBUG("moreinfo not initialized"); + return 0; + } + + if (prefix) { + gchar *lookup_key = g_strconcat(prefix, ":", key, NULL); + gchar *result = g_hash_table_lookup(_moreinfo, lookup_key); + g_free(lookup_key); + return result; + } + + return g_hash_table_lookup(_moreinfo, key); +} + +gchar * +moreinfo_lookup(gchar *key) +{ + return moreinfo_lookup_with_prefix(NULL, key); +} + +#if !GLIB_CHECK_VERSION(2,44,0) +gboolean g_strv_contains(const gchar * const * strv, const gchar *str) { + /* g_strv_contains() requires glib>2.44 + * fallback for older versions */ + gint i = 0; + while(strv[i] != NULL) { + if (g_strcmp0(strv[i], str) == 0) + return 1; + i++; + } + return 0; +} +#endif + +gchar *hardinfo_clean_grpname(const gchar *v, int replacing) { + gchar *clean, *p; + + p = clean = g_strdup(v); + while (*p != 0) { + switch(*p) { + case '[': + *p = '('; break; + case ']': + *p = ')'; break; + default: + break; + } + p++; + } + if (replacing) + g_free((gpointer)v); + return clean; +} + +/* Hardinfo labels that have # are truncated and/or hidden. + * Labels can't have $ because that is the delimiter in + * moreinfo. */ +gchar *hardinfo_clean_label(const gchar *v, int replacing) { + gchar *clean, *p; + + p = clean = g_strdup(v); + while (*p != 0) { + switch(*p) { + case '#': case '$': + *p = '_'; + break; + default: + break; + } + p++; + } + if (replacing) + g_free((gpointer)v); + return clean; +} + +/* hardinfo uses the values as {ht,x}ml, apparently */ +gchar *hardinfo_clean_value(const gchar *v, int replacing) { + gchar *clean, *tmp; + gchar **vl; + if (v == NULL) return NULL; + + vl = g_strsplit(v, "&", -1); + if (g_strv_length(vl) > 1) + clean = g_strjoinv("&", vl); + else + clean = g_strdup(v); + g_strfreev(vl); + + vl = g_strsplit(clean, "<", -1); + if (g_strv_length(vl) > 1) { + tmp = g_strjoinv("<", vl); + g_free(clean); + clean = tmp; + } + g_strfreev(vl); + + vl = g_strsplit(clean, ">", -1); + if (g_strv_length(vl) > 1) { + tmp = g_strjoinv(">", vl); + g_free(clean); + clean = tmp; + } + g_strfreev(vl); + + if (replacing) + g_free((gpointer)v); + return clean; +} + +gboolean hardinfo_spawn_command_line_sync(const gchar *command_line, + gchar **standard_output, + gchar **standard_error, + gint *exit_status, + GError **error) +{ + shell_status_pulse(); + return g_spawn_command_line_sync(command_line, standard_output, + standard_error, exit_status, error); +} |