diff options
Diffstat (limited to 'hardinfo2/util')
| -rw-r--r-- | hardinfo2/util/binreloc.c | 672 | ||||
| -rw-r--r-- | hardinfo2/util/expr.c | 250 | ||||
| -rw-r--r-- | hardinfo2/util/socket.c | 127 | ||||
| -rw-r--r-- | hardinfo2/util/util.c | 1292 | ||||
| -rw-r--r-- | hardinfo2/util/vendor.c | 195 | 
5 files changed, 2536 insertions, 0 deletions
| diff --git a/hardinfo2/util/binreloc.c b/hardinfo2/util/binreloc.c new file mode 100644 index 00000000..1d1acfe6 --- /dev/null +++ b/hardinfo2/util/binreloc.c @@ -0,0 +1,672 @@ +/* + * BinReloc - a library for creating relocatable executables + * Written by: Hongli Lai <h.lai@chello.nl> + * http://autopackage.org/ + * + * This source code is public domain. You can relicense this code + * under whatever license you want. + * + * See http://autopackage.org/docs/binreloc/ for + * more information and how to use this. + */ + +#ifndef __BINRELOC_C__ +#define __BINRELOC_C__ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include "binreloc.h" +#include "config.h" + +G_BEGIN_DECLS +/** @internal + * Find the canonical filename of the executable. Returns the filename + * (which must be freed) or NULL on error. If the parameter 'error' is + * not NULL, the error code will be stored there, if an error occured. + */ +static char *_br_find_exe(GbrInitError * error) +{ +    char *path, *path2, *line, *result; +    size_t buf_size; +    ssize_t size; +    struct stat stat_buf; +    FILE *f; + +    /* Read from /proc/self/exe (symlink) */ +    if (sizeof(path) > SSIZE_MAX) +	buf_size = SSIZE_MAX - 1; +    else +	buf_size = PATH_MAX - 1; +    path = (char *) g_try_malloc(buf_size); +    if (path == NULL) { +	/* Cannot allocate memory. */ +	if (error) +	    *error = GBR_INIT_ERROR_NOMEM; +	return NULL; +    } +    path2 = (char *) g_try_malloc(buf_size); +    if (path2 == NULL) { +	/* Cannot allocate memory. */ +	if (error) +	    *error = GBR_INIT_ERROR_NOMEM; +	g_free(path); +	return NULL; +    } + +    strncpy(path2, "/proc/self/exe", buf_size - 1); + +    while (1) { +	int i; + +	size = readlink(path2, path, buf_size - 1); +	if (size == -1) { +	    /* Error. */ +	    g_free(path2); +	    break; +	} + +	/* readlink() success. */ +	path[size] = '\0'; + +	/* Check whether the symlink's target is also a symlink. +	 * We want to get the final target. */ +	i = stat(path, &stat_buf); +	if (i == -1) { +	    /* Error. */ +	    g_free(path2); +	    break; +	} + +	/* stat() success. */ +	if (!S_ISLNK(stat_buf.st_mode)) { +	    /* path is not a symlink. Done. */ +	    g_free(path2); +	    return path; +	} + +	/* path is a symlink. Continue loop and resolve this. */ +	strncpy(path, path2, buf_size - 1); +    } + + +    /* readlink() or stat() failed; this can happen when the program is +     * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */ + +    buf_size = PATH_MAX + 128; +    line = (char *) g_try_realloc(path, buf_size); +    if (line == NULL) { +	/* Cannot allocate memory. */ +	g_free(path); +	if (error) +	    *error = GBR_INIT_ERROR_NOMEM; +	return NULL; +    } + +    f = fopen("/proc/self/maps", "r"); +    if (f == NULL) { +	g_free(line); +	if (error) +	    *error = GBR_INIT_ERROR_OPEN_MAPS; +	return NULL; +    } + +    /* The first entry should be the executable name. */ +    result = fgets(line, (int) buf_size, f); +    if (result == NULL) { +	fclose(f); +	g_free(line); +	if (error) +	    *error = GBR_INIT_ERROR_READ_MAPS; +	return NULL; +    } + +    /* Get rid of newline character. */ +    buf_size = strlen(line); +    if (buf_size <= 0) { +	/* Huh? An empty string? */ +	fclose(f); +	g_free(line); +	if (error) +	    *error = GBR_INIT_ERROR_INVALID_MAPS; +	return NULL; +    } +    if (line[buf_size - 1] == 10) +	line[buf_size - 1] = 0; + +    /* Extract the filename; it is always an absolute path. */ +    path = strchr(line, '/'); + +    /* Sanity check. */ +    if (strstr(line, " r-xp ") == NULL || path == NULL) { +	fclose(f); +	g_free(line); +	if (error) +	    *error = GBR_INIT_ERROR_INVALID_MAPS; +	return NULL; +    } + +    path = g_strdup(path); +    g_free(line); +    fclose(f); +    return path; +} + + +/** @internal + * Find the canonical filename of the executable which owns symbol. + * Returns a filename which must be freed, or NULL on error. + */ +static char *_br_find_exe_for_symbol(const void *symbol, +				     GbrInitError * error) +{ +#define SIZE PATH_MAX + 100 +    FILE *f; +    size_t address_string_len; +    char *address_string, line[SIZE], *found; + +    if (symbol == NULL) +	return (char *) NULL; + +    f = fopen("/proc/self/maps", "r"); +    if (f == NULL) +	return (char *) NULL; + +    address_string_len = 4; +    address_string = (char *) g_try_malloc(address_string_len); +    found = (char *) NULL; + +    while (!feof(f)) { +	char *start_addr, *end_addr, *end_addr_end, *file; +	void *start_addr_p, *end_addr_p; +	size_t len; + +	if (fgets(line, SIZE, f) == NULL) +	    break; + +	/* Sanity check. */ +	if (strstr(line, " r-xp ") == NULL || strchr(line, '/') == NULL) +	    continue; + +	/* Parse line. */ +	start_addr = line; +	end_addr = strchr(line, '-'); +	file = strchr(line, '/'); + +	/* More sanity check. */ +	if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-')) +	    continue; + +	end_addr[0] = '\0'; +	end_addr++; +	end_addr_end = strchr(end_addr, ' '); +	if (end_addr_end == NULL) +	    continue; + +	end_addr_end[0] = '\0'; +	len = strlen(file); +	if (len == 0) +	    continue; +	if (file[len - 1] == '\n') +	    file[len - 1] = '\0'; + +	/* Get rid of "(deleted)" from the filename. */ +	len = strlen(file); +	if (len > 10 && strcmp(file + len - 10, " (deleted)") == 0) +	    file[len - 10] = '\0'; + +	/* I don't know whether this can happen but better safe than sorry. */ +	len = strlen(start_addr); +	if (len != strlen(end_addr)) +	    continue; + + +	/* Transform the addresses into a string in the form of 0xdeadbeef, +	 * then transform that into a pointer. */ +	if (address_string_len < len + 3) { +	    address_string_len = len + 3; +	    address_string = +		(char *) g_try_realloc(address_string, address_string_len); +	} + +	memcpy(address_string, "0x", 2); +	memcpy(address_string + 2, start_addr, len); +	address_string[2 + len] = '\0'; +	sscanf(address_string, "%p", &start_addr_p); + +	memcpy(address_string, "0x", 2); +	memcpy(address_string + 2, end_addr, len); +	address_string[2 + len] = '\0'; +	sscanf(address_string, "%p", &end_addr_p); + + +	if (symbol >= start_addr_p && symbol < end_addr_p) { +	    found = file; +	    break; +	} +    } + +    g_free(address_string); +    fclose(f); + +    if (found == NULL) +	return (char *) NULL; +    else +	return g_strdup(found); +} + + +static gchar *exe = NULL; + +static void set_gerror(GError ** error, GbrInitError errcode); + + +/** Initialize the BinReloc library (for applications). + * + * This function must be called before using any other BinReloc functions. + * It attempts to locate the application's canonical filename. + * + * @note If you want to use BinReloc for a library, then you should call + *       gbr_init_lib() instead. + * + * @param error  If BinReloc failed to initialize, then the error report will + *               be stored in this variable. Set to NULL if you don't want an + *               error report. See the #GbrInitError for a list of error + *               codes. + * + * @returns TRUE on success, FALSE if BinReloc failed to initialize. + */ +gboolean gbr_init(GError ** error) +{ +    GbrInitError errcode = 0; + +    /* Locate the application's filename. */ +    exe = _br_find_exe(&errcode); +    if (exe != NULL) +	/* Success! */ +	return TRUE; +    else { +	/* Failed :-( */ +	set_gerror(error, errcode); +	return FALSE; +    } +} + + +/** Initialize the BinReloc library (for libraries). + * + * This function must be called before using any other BinReloc functions. + * It attempts to locate the calling library's canonical filename. + * + * @note The BinReloc source code MUST be included in your library, or this + *       function won't work correctly. + * + * @returns TRUE on success, FALSE if a filename cannot be found. + */ +gboolean gbr_init_lib(GError ** error) +{ +    GbrInitError errcode = 0; + +    exe = _br_find_exe_for_symbol((const void *) "", &errcode); +    if (exe != NULL) +	/* Success! */ +	return TRUE; +    else { +	/* Failed :-( */ +	set_gerror(error, errcode); +	return exe != NULL; +    } +} + + +static void set_gerror(GError ** error, GbrInitError errcode) +{ +    gchar *error_message; + +    if (error == NULL) +	return; + +    switch (errcode) { +    case GBR_INIT_ERROR_NOMEM: +	error_message = "Cannot allocate memory."; +	break; +    case GBR_INIT_ERROR_OPEN_MAPS: +	error_message = "Unable to open /proc/self/maps for reading."; +	break; +    case GBR_INIT_ERROR_READ_MAPS: +	error_message = "Unable to read from /proc/self/maps."; +	break; +    case GBR_INIT_ERROR_INVALID_MAPS: +	error_message = "The file format of /proc/self/maps is invalid."; +	break; +    case GBR_INIT_ERROR_DISABLED: +	error_message = "Binary relocation support is disabled."; +	break; +    default: +	error_message = "Unknown error."; +	break; +    }; +    g_set_error(error, g_quark_from_static_string("GBinReloc"), +		errcode, "%s", error_message); +} + + +/** Find the canonical filename of the current application. + * + * @param default_exe  A default filename which will be used as fallback. + * @returns A string containing the application's canonical filename, + *          which must be freed when no longer necessary. If BinReloc is + *          not initialized, or if the initialization function failed, + *          then a copy of default_exe will be returned. If default_exe + *          is NULL, then NULL will be returned. + */ +gchar *gbr_find_exe(const gchar * default_exe) +{ +    if (exe == NULL) { +	/* BinReloc is not initialized. */ +	if (default_exe != NULL) +	    return g_strdup(default_exe); +	else +	    return NULL; +    } +    return g_strdup(exe); +} + + +/** Locate the directory in which the current application is installed. + * + * The prefix is generated by the following pseudo-code evaluation: + * \code + * dirname(exename) + * \endcode + * + * @param default_dir  A default directory which will used as fallback. + * @return A string containing the directory, which must be freed when no + *         longer necessary. If BinReloc is not initialized, or if the + *         initialization function failed, then a copy of default_dir + *         will be returned. If default_dir is NULL, then NULL will be + *         returned. + */ +gchar *gbr_find_exe_dir(const gchar * default_dir) +{ +    if (exe == NULL) { +	/* BinReloc not initialized. */ +	if (default_dir != NULL) +	    return g_strdup(default_dir); +	else +	    return NULL; +    } + +    return g_path_get_dirname(exe); +} + + +/** Locate the prefix in which the current application is installed. + * + * The prefix is generated by the following pseudo-code evaluation: + * \code + * dirname(dirname(exename)) + * \endcode + * + * @param default_prefix  A default prefix which will used as fallback. + * @return A string containing the prefix, which must be freed when no + *         longer necessary. If BinReloc is not initialized, or if the + *         initialization function failed, then a copy of default_prefix + *         will be returned. If default_prefix is NULL, then NULL will be + *         returned. + */ +gchar *gbr_find_prefix(const gchar * default_prefix) +{ +    gchar *dir1, *dir2; + +    if (exe == NULL) { +	/* BinReloc not initialized. */ +	if (default_prefix != NULL) +	    return g_strdup(default_prefix); +	else +	    return NULL; +    } + +    dir1 = g_path_get_dirname(exe); +    dir2 = g_path_get_dirname(dir1); +    g_free(dir1); +    return dir2; +} + + +/** Locate the application's binary folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/bin" + * \endcode + * + * @param default_bin_dir  A default path which will used as fallback. + * @return A string containing the bin folder's path, which must be freed when + *         no longer necessary. If BinReloc is not initialized, or if the + *         initialization function failed, then a copy of default_bin_dir will + *         be returned. If default_bin_dir is NULL, then NULL will be returned. + */ +gchar *gbr_find_bin_dir(const gchar * default_bin_dir) +{ +    gchar *prefix, *dir; + +    prefix = gbr_find_prefix(NULL); +    if (prefix == NULL) { +	/* BinReloc not initialized. */ +	if (default_bin_dir != NULL) +	    return g_strdup(default_bin_dir); +	else +	    return NULL; +    } + +    dir = g_build_filename(prefix, "bin", NULL); +    g_free(prefix); +    return dir; +} + + +/** Locate the application's superuser binary folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/sbin" + * \endcode + * + * @param default_sbin_dir  A default path which will used as fallback. + * @return A string containing the sbin folder's path, which must be freed when + *         no longer necessary. If BinReloc is not initialized, or if the + *         initialization function failed, then a copy of default_sbin_dir will + *         be returned. If default_bin_dir is NULL, then NULL will be returned. + */ +gchar *gbr_find_sbin_dir(const gchar * default_sbin_dir) +{ +    gchar *prefix, *dir; + +    prefix = gbr_find_prefix(NULL); +    if (prefix == NULL) { +	/* BinReloc not initialized. */ +	if (default_sbin_dir != NULL) +	    return g_strdup(default_sbin_dir); +	else +	    return NULL; +    } + +    dir = g_build_filename(prefix, "sbin", NULL); +    g_free(prefix); +    return dir; +} + + +/** Locate the application's data folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/share" + * \endcode + * + * @param default_data_dir  A default path which will used as fallback. + * @return A string containing the data folder's path, which must be freed when + *         no longer necessary. If BinReloc is not initialized, or if the + *         initialization function failed, then a copy of default_data_dir + *         will be returned. If default_data_dir is NULL, then NULL will be + *         returned. + */ +gchar *gbr_find_data_dir(const gchar * default_data_dir) +{ +    gchar *prefix, *dir; + +    prefix = gbr_find_prefix(NULL); +    if (prefix == NULL) { +	/* BinReloc not initialized. */ +	if (default_data_dir != NULL) +	    return g_strdup(default_data_dir); +	else +	    return NULL; +    } + +    dir = g_build_filename(prefix, "share", NULL); +    g_free(prefix); +    return dir; +} + + +/** Locate the application's localization folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/share/locale" + * \endcode + * + * @param default_locale_dir  A default path which will used as fallback. + * @return A string containing the localization folder's path, which must be freed when + *         no longer necessary. If BinReloc is not initialized, or if the + *         initialization function failed, then a copy of default_locale_dir will be returned. + *         If default_locale_dir is NULL, then NULL will be returned. + */ +gchar *gbr_find_locale_dir(const gchar * default_locale_dir) +{ +    gchar *data_dir, *dir; + +    data_dir = gbr_find_data_dir(NULL); +    if (data_dir == NULL) { +	/* BinReloc not initialized. */ +	if (default_locale_dir != NULL) +	    return g_strdup(default_locale_dir); +	else +	    return NULL; +    } + +    dir = g_build_filename(data_dir, "locale", NULL); +    g_free(data_dir); +    return dir; +} + + +/** Locate the application's library folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/lib" + * \endcode + * + * @param default_lib_dir  A default path which will used as fallback. + * @return A string containing the library folder's path, which must be freed when + *         no longer necessary. If BinReloc is not initialized, or if the + *         initialization function failed, then a copy of default_lib_dir will be returned. + *         If default_lib_dir is NULL, then NULL will be returned. + */ +gchar *gbr_find_lib_dir(const gchar * default_lib_dir) +{ +    gchar *prefix, *dir; + +    prefix = gbr_find_prefix(NULL); +    if (prefix == NULL) { +	/* BinReloc not initialized. */ +	if (default_lib_dir != NULL) +	    return g_strdup(default_lib_dir); +	else +	    return NULL; +    } + +#ifdef ARCH_x86_64 +    dir = g_build_filename(prefix, "lib64", NULL); +#else +    dir = g_build_filename(prefix, "lib", NULL); +#endif + +    g_free(prefix); +    return dir; +} + + +/** Locate the application's libexec folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/libexec" + * \endcode + * + * @param default_libexec_dir  A default path which will used as fallback. + * @return A string containing the libexec folder's path, which must be freed when + *         no longer necessary. If BinReloc is not initialized, or if the initialization + *         function failed, then a copy of default_libexec_dir will be returned. + *         If default_libexec_dir is NULL, then NULL will be returned. + */ +gchar *gbr_find_libexec_dir(const gchar * default_libexec_dir) +{ +    gchar *prefix, *dir; + +    prefix = gbr_find_prefix(NULL); +    if (prefix == NULL) { +	/* BinReloc not initialized. */ +	if (default_libexec_dir != NULL) +	    return g_strdup(default_libexec_dir); +	else +	    return NULL; +    } + +    dir = g_build_filename(prefix, "libexec", NULL); +    g_free(prefix); +    return dir; +} + + +/** Locate the application's configuration files folder. + * + * The path is generated by the following pseudo-code evaluation: + * \code + * prefix + "/etc" + * \endcode + * + * @param default_etc_dir  A default path which will used as fallback. + * @return A string containing the etc folder's path, which must be freed when + *         no longer necessary. If BinReloc is not initialized, or if the initialization + *         function failed, then a copy of default_etc_dir will be returned. + *         If default_etc_dir is NULL, then NULL will be returned. + */ +gchar *gbr_find_etc_dir(const gchar * default_etc_dir) +{ +    gchar *prefix, *dir; + +    prefix = gbr_find_prefix(NULL); +    if (prefix == NULL) { +	/* BinReloc not initialized. */ +	if (default_etc_dir != NULL) +	    return g_strdup(default_etc_dir); +	else +	    return NULL; +    } + +    dir = g_build_filename(prefix, "etc", NULL); +    g_free(prefix); +    return dir; +} + + +G_END_DECLS +#endif				/* __BINRELOC_C__ */ diff --git a/hardinfo2/util/expr.c b/hardinfo2/util/expr.c new file mode 100644 index 00000000..32e303d7 --- /dev/null +++ b/hardinfo2/util/expr.c @@ -0,0 +1,250 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    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 + */ +/* + * This is only used to compute sensor values, hence the only variable supported is '@'. + * The '`' operator (ln(x)) is not available, nor multi-line formulas. + */ + +#include <glib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <math.h> + +#include "expr.h" +#include "config.h" + +static MathToken *new_operator(gchar op) +{ +    MathToken *t = g_new0(MathToken, 1); + +    t->val.op = op; +    t->type = TOKEN_OPERATOR;	/* operator */ + +    return t; +} + +static MathToken *new_variable(gchar var) +{ +    MathToken *t = g_new0(MathToken, 1); + +    t->val.op = '@'; +    t->type = TOKEN_VARIABLE;	/* variable */ + +    return t; +} + +static MathToken *new_value(gfloat value) +{ +    MathToken *t = g_new0(MathToken, 1); + +    t->val.value = value; +    t->type = TOKEN_VALUE;	/* value */ + +    return t; +} + +static inline gint priority(char operation) +{ +    switch (operation) { +    case '^': +	return 3; +    case '*': +    case '/': +	return 2; +    case '+': +    case '-': +	return 1; +    case '(': +	return 0; +    } + +    return 0; +} + +GSList *math_infix_to_postfix(GSList * infix) +{ +    MathToken *stack[500]; +    gint t_sp = 0; + +    GSList *postfix = NULL, *p; +    MathToken *top; + +    for (p = infix; p; p = p->next) { +	MathToken *t = (MathToken *) p->data; + +	if (t->type == TOKEN_OPERATOR && t->val.op == '(') { +	    stack[++t_sp] = t; +	} else if (t->type == TOKEN_OPERATOR && t->val.op == ')') { +	    for (top = stack[t_sp]; t_sp != 0 && top->val.op != '('; +		 top = stack[t_sp]) { +                postfix = g_slist_append(postfix, stack[t_sp--]); +            } +	    t_sp--; +	} else if (t->type != TOKEN_OPERATOR) { +	    postfix = g_slist_append(postfix, t); +	} else if (t_sp == 0) { +	    stack[++t_sp] = t; +	} else { +	    while (t_sp != 0 +		   && priority(t->val.op) <= priority(stack[t_sp]->val.op)) +		postfix = g_slist_append(postfix, stack[t_sp--]); +	    stack[++t_sp] = t; +	} +    } + +    while (t_sp) +	postfix = g_slist_append(postfix, stack[t_sp--]); +	 +    return postfix; +} + +static inline gfloat __result(gfloat op1, gfloat op2, gchar operation) +{ +    switch (operation) { +    case '^': +	return powf(op1, op2); +    case '+': +	return op1 + op2; +    case '-': +	return op1 - op2; +    case '/': +	return op1 / op2; +    case '*': +	return op1 * op2; +    } + +    return 0; +} + +gfloat math_postfix_eval(GSList * postfix, gfloat at_value) +{ +    GSList *p; +    gfloat stack[500]; +    gint sp = 0; + +    memset(stack, 0, sizeof(gfloat) * 500); + +    for (p = postfix; p; p = p->next) { +	MathToken *t = (MathToken *) p->data; + +	if (t->type == TOKEN_VARIABLE) { +	    stack[++sp] = at_value; +	} else if (t->type == TOKEN_VALUE) { +	    stack[++sp] = t->val.value; +	} else { +	    gfloat op1, op2; + +	    op2 = stack[sp--]; +	    op1 = stack[sp]; +	     +	    stack[sp] = __result(op1, op2, t->val.op); +	} +    } +     +    return stack[sp]; +} + +GSList *math_string_to_infix(gchar * string) +{ +    GSList *infix = NULL; +    gchar *expr = string; +     +    for (; *expr; expr++) { +	if (strchr("+-/*^()", *expr)) { +	    infix = g_slist_append(infix, new_operator(*expr)); +	} else if (strchr("@", *expr)) { +	    infix = g_slist_append(infix, new_variable(*expr)); +	} else if (strchr("-.1234567890", *expr)) { +	    gchar value[32], *v = value; +	    gfloat floatval; +	     +	    do { +	      *v++ = *expr++; +	    } while (*expr && strchr("-.1234567890", *expr)); +	    expr--; +	    *v = '\0'; +	     +	    sscanf(value, "%f", &floatval); + +	    infix = g_slist_append(infix, new_value(floatval)); +	} else if (!isspace(*expr)) { +	    g_print("Invalid token: [%c][%d]\n", *expr, *expr); +	    math_infix_free(infix, TRUE); +	    return NULL; +	} +    } + +    return infix; +} + +void math_infix_free(GSList * infix, gboolean free_tokens) +{ +    GSList *p; + +    if (!free_tokens) +	for (p = infix; p; p = g_slist_delete_link(p, p)); +    else +	for (p = infix; p; p = g_slist_delete_link(p, p)) { +	    MathToken *t = (MathToken *) p->data; +	    g_free(t); +	} +} + +GSList *math_string_to_postfix(gchar * string) +{ +    GSList *infix; +    GSList *postfix; + +    infix = math_string_to_infix(string); +    if (!infix) +	return NULL; + +    postfix = math_infix_to_postfix(infix); +    math_infix_free(infix, FALSE); + +    return postfix; +} + +gfloat math_string_eval(gchar * string, gfloat at_value) +{ +    GSList *postfix; +    gfloat val; + +    postfix = math_string_to_postfix(string); +    val = math_postfix_eval(postfix, at_value); +    math_postfix_free(postfix, TRUE); + +    return val; +} + +#ifdef MATH_TEST +int main(void) +{ +    GSList *postfix; + +    gchar *expr = "0.9*(@+(5.2*0.923+3*(2.0)))"; + +    postfix = math_string_to_postfix(expr); +    g_print("%s = %f (must be 18.71964)\n", expr, +	    math_postfix_eval(postfix, 10)); +    math_postfix_free(postfix, TRUE); + +    return 0; +} +#endif diff --git a/hardinfo2/util/socket.c b/hardinfo2/util/socket.c new file mode 100644 index 00000000..339df30e --- /dev/null +++ b/hardinfo2/util/socket.c @@ -0,0 +1,127 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    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 + */ + +#include <stdio.h> +#include <string.h> +#include <arpa/inet.h> +#include <errno.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include <glib.h> + +#include "socket.h" + +Socket *sock_connect(gchar * host, gint port) +{ +    struct sockaddr_in server; +    Socket *s; +    int sock; + +    sock = socket(AF_INET, SOCK_STREAM, 0); +    if (sock > 0) { +	memset(&server, 0, sizeof(server)); +	server.sin_family = AF_INET; +	server.sin_addr.s_addr = inet_addr(host); +	server.sin_port = htons(port); + +	if (connect(sock, (struct sockaddr *) (void *) &server, sizeof(server)) < 0) { +	     goto cleanup; +	} + +	s = g_new0(Socket, 1); +	s->sock = sock; + +	return s; +    } + +cleanup:     +    close(sock); + +    return NULL; +} + +/* From: http://www.erlenstar.demon.co.uk/unix/faq_3.html#SEC26 */ +static inline int __sock_is_ready(Socket * s, int mode) +{ +    int rc, fd = s->sock; +    fd_set fds; +    struct timeval tv; + +    FD_ZERO(&fds); +    FD_SET(fd, &fds); +    tv.tv_sec = tv.tv_usec = 0; + +    if (mode == 0) { +	/* read */ +	rc = select(fd + 1, &fds, NULL, NULL, &tv); +    } else { +	/* write */ +	rc = select(fd + 1, NULL, &fds, NULL, &tv); +    } + +    if (rc < 0) +	return -1; + +    return FD_ISSET(fd, &fds) ? 1 : 0; +} + +int sock_ready_to_read(Socket * s) +{ +    return __sock_is_ready(s, 0); +} + +int sock_ready_to_write(Socket * s) +{ +    return __sock_is_ready(s, 1); +} + +int sock_read(Socket * s, gchar * buffer, gint size) +{ +    if (sock_ready_to_read(s)) { +	gint n; + +	n = read(s->sock, buffer, size); +	if (n > 0) { +            buffer[n] = '\0'; +        } else { +            return 0; +        } + +	return n; +    } + +    return 0; +} + +int sock_write(Socket * s, gchar * str) +{ +    while (!sock_ready_to_write(s)); + +    return write(s->sock, str, strlen(str)); +} + +void sock_close(Socket * s) +{ +    shutdown(s->sock, 2); +    close(s->sock); +    g_free(s); +} diff --git a/hardinfo2/util/util.c b/hardinfo2/util/util.c new file mode 100644 index 00000000..fb995406 --- /dev/null +++ b/hardinfo2/util/util.c @@ -0,0 +1,1292 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    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 + +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[] = { "/bin", "/sbin", +		           "/usr/bin", "/usr/sbin", +		           "/usr/local/bin", "/usr/local/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; + +    minutes = seconds / 60; +    hours = minutes / 60; +    minutes %= 60; +    days = hours / 24; +    hours %= 24; + +#define plural(x) ((x > 1) ? "s" : "") + +    if (days < 1) { +	if (hours < 1) { +	    return g_strdup_printf("%d minute%s", minutes, +				   plural(minutes)); +	} else { +	    return g_strdup_printf("%d hour%s, %d minute%s", +				   hours, +				   plural(hours), minutes, +				   plural(minutes)); +	} +    } + +    return g_strdup_printf("%d day%s, %d hour%s and %d minute%s", +			   days, plural(days), hours, +			   plural(hours), minutes, plural(minutes)); +} + +inline 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); + +    return g_strdup_printf("%.1f GiB", size / GiB); +} + +inline char *strend(gchar * str, gchar chr) +{ +    if (!str) +	return NULL; + +    char *p; +    if ((p = strchr(str, chr))) +	*p = 0; + +    return str; +} + +inline void remove_quotes(gchar * str) +{ +    if (!str) +	return; + +    while (*str == '"') +	*(str++) = ' '; + +    strend(str, '"'); +} + +inline void remove_linefeed(gchar * str) +{ +    strend(str, '\n'); +} + +void widget_set_cursor(GtkWidget * widget, GdkCursorType cursor_type) +{ +    GdkCursor *cursor; + +    if ((cursor = gdk_cursor_new(cursor_type))) { +        gdk_window_set_cursor(GDK_WINDOW(widget->window), cursor); +        gdk_display_flush(gtk_widget_get_display(widget)); +        gdk_cursor_unref(cursor); +    } + +    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, "hardinfo", NULL); +	g_free(tmp); + +	tmp = gbr_find_lib_dir(PREFIX); +	params.path_lib = g_build_filename(tmp, "hardinfo", 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 uidefs.xml 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 show_version = FALSE; +    static gboolean list_modules = FALSE; +    static gboolean autoload_deps = FALSE; +    static gboolean run_xmlrpc_server = FALSE; +    static gchar *report_format = NULL; +    static gchar *run_benchmark = NULL; +    static gchar **use_modules = NULL; + +    static GOptionEntry options[] = { +	{ +	 .long_name = "generate-report", +	 .short_name = 'r', +	 .arg = G_OPTION_ARG_NONE, +	 .arg_data = &create_report, +	 .description = "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 = "chooses a report format (text, html)"}, +	{ +	 .long_name = "run-benchmark", +	 .short_name = 'b', +	 .arg = G_OPTION_ARG_STRING, +	 .arg_data = &run_benchmark, +	 .description = "run benchmark; requires benchmark.so to be loaded"}, +	{ +	 .long_name = "list-modules", +	 .short_name = 'l', +	 .arg = G_OPTION_ARG_NONE, +	 .arg_data = &list_modules, +	 .description = "lists modules"}, +	{ +	 .long_name = "load-module", +	 .short_name = 'm', +	 .arg = G_OPTION_ARG_STRING_ARRAY, +	 .arg_data = &use_modules, +	 .description = "specify module to load"}, +	{ +	 .long_name = "autoload-deps", +	 .short_name = 'a', +	 .arg = G_OPTION_ARG_NONE, +	 .arg_data = &autoload_deps, +	 .description = "automatically load module dependencies"}, +#ifdef HAS_LIBSOUP +	{ +	 .long_name = "xmlrpc-server", +	 .short_name = 'x', +	 .arg = G_OPTION_ARG_NONE, +	 .arg_data = &run_xmlrpc_server, +	 .description = "run in XML-RPC server mode"}, +#endif	/* HAS_LIBSOUP */ +	{ +	 .long_name = "version", +	 .short_name = 'v', +	 .arg = G_OPTION_ARG_NONE, +	 .arg_data = &show_version, +	 .description = "shows program version and quit"}, +	{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->autoload_deps = autoload_deps; +    param->run_xmlrpc_server = run_xmlrpc_server; +    param->argv0 = *(argv)[0]; + +    if (report_format && g_str_equal(report_format, "html")) +	param->report_format = REPORT_FORMAT_HTML; + +    gchar *confdir = g_build_filename(g_get_home_dir(), ".hardinfo", 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("HardInfo"); +    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); +} + +void open_url(gchar * url) +{ +    const gchar *browsers[] = { +	"xdg-open", "gnome-open", "kfmclient openURL", +	"sensible-browser", "firefox", "epiphany", +	"iceweasel", "seamonkey", "galeon", "mozilla", +	"opera", "konqueror", "netscape", "links -g", +	NULL +    }; +    gint i = 0; +    gchar *browser = (gchar *)g_getenv("BROWSER"); +     +    if (!browser || *browser == '\0') { +    	browser = (gchar *)browsers[i++]; +    } +     +    do { +	gchar *cmdline = g_strdup_printf("%s '%s'", browser, url); + +	if (g_spawn_command_line_async(cmdline, NULL)) { +	    g_free(cmdline); +	    return; +	} + +	g_free(cmdline); +    	 +    	browser = (gchar *)browsers[i++]; +    } while (browser); + +    g_warning("Couldn't find a Web browser to open URL %s.", url); +} + +/* 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) +{ +    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)) { +	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); +    gdk_pixbuf_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", tmp, module->dll); +    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) { +	    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; +	    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 + +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), +					       GTK_STOCK_NO, +					       GTK_RESPONSE_REJECT, +					       GTK_STOCK_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("HardInfo 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) { +	while ((filename = (gchar *) g_dir_read_name(dir))) { +	    if (g_strrstr(filename, "." G_MODULE_SUFFIX) && +		module_in_module_list(filename, module_list) && +		((module = module_load(filename)))) { +		modules = g_slist_prepend(modules, module); +	    } +	} + +	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 hardinfo -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 tree_view_save_image(gchar * filename) +{ +    /* this is ridiculously complicated :/ why in the hell gtk+ makes this kind of +       thing so difficult?  */ + +    /* FIXME: this does not work if the window (or part of it) isn't visible. does +       anyone know how to fix this? :/ */ +    Shell *shell = shell_get_main_shell(); +    GtkWidget *widget = shell->info->view; + +    PangoLayout *layout; +    PangoContext *context; +    PangoRectangle rect; + +    GdkPixmap *pm; +    GdkPixbuf *pb; +    GdkGC *gc; +    GdkColor black = { 0, 0, 0, 0 }; +    GdkColor white = { 0, 65535, 65535, 65535 }; + +    gint w, h, visible_height; +    gchar *tmp; + +    gboolean tv_enabled; + +    /* present the window */ +    gtk_window_present(GTK_WINDOW(shell->window)); + +    /* if the treeview is disabled, we need to enable it so we get the +       correct colors when saving. we make it insensitive later on if it +       was this way before entering this function */ +    tv_enabled = GTK_WIDGET_IS_SENSITIVE(widget); +    gtk_widget_set_sensitive(widget, TRUE); + +    gtk_widget_queue_draw(widget); + +    /* unselect things in the information treeview */ +    gtk_range_set_value(GTK_RANGE +			(GTK_SCROLLED_WINDOW(shell->info->scroll)-> +			 vscrollbar), 0.0); +    gtk_tree_selection_unselect_all(gtk_tree_view_get_selection +				    (GTK_TREE_VIEW(widget))); +    while (gtk_events_pending()) +	gtk_main_iteration(); + +    /* initialize stuff */ +    gc = gdk_gc_new(widget->window); +    gdk_gc_set_background(gc, &black); +    gdk_gc_set_foreground(gc, &white); + +    context = gtk_widget_get_pango_context(widget); +    layout = pango_layout_new(context); + +    visible_height = tree_view_get_visible_height(GTK_TREE_VIEW(widget)); + +    /* draw the title */ +    tmp = g_strdup_printf("<b><big>%s</big></b>\n<small>%s</small>", +			  shell->selected->name, +			  shell->selected->notefunc(shell->selected-> +						    number)); +    pango_layout_set_markup(layout, tmp, -1); +    pango_layout_set_width(layout, widget->allocation.width * PANGO_SCALE); +    pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); +    pango_layout_get_pixel_extents(layout, NULL, &rect); + +    w = widget->allocation.width; +    h = visible_height + rect.height; + +    pm = gdk_pixmap_new(widget->window, w, rect.height, -1); +    gdk_draw_rectangle(GDK_DRAWABLE(pm), gc, TRUE, 0, 0, w, rect.height); +    gdk_draw_layout_with_colors(GDK_DRAWABLE(pm), gc, 0, 0, layout, +				&white, &black); + +    /* copy the pixmap from the treeview and from the title */ +    pb = gdk_pixbuf_get_from_drawable(NULL, +				      widget->window, +				      NULL, 0, 0, 0, 0, w, h); +    pb = gdk_pixbuf_get_from_drawable(pb, +				      pm, +				      NULL, +				      0, 0, +				      0, visible_height, w, rect.height); + +    /* save the pixbuf to a png file */ +    gdk_pixbuf_save(pb, filename, "png", NULL, +		    "compression", "9", +		    "tEXt::hardinfo::version", VERSION, +		    "tEXt::hardinfo::arch", ARCH, NULL); + +    /* unref */ +    g_object_unref(pb); +    g_object_unref(layout); +    g_object_unref(pm); +    g_object_unref(gc); +    g_free(tmp); + +    gtk_widget_set_sensitive(widget, tv_enabled); +} + +static gboolean __idle_free_do(gpointer ptr) +{ +    if (ptr) { +	g_free(ptr); +    } + +    return FALSE; +} + +#if RELEASE == 1 +gpointer idle_free(gpointer ptr) +#else +gpointer __idle_free(gpointer ptr, gchar * f, gint l) +#endif +{ +    DEBUG("file: %s, line: %d, ptr %p", f, l, ptr); + +    if (ptr) { +	g_timeout_add(10000, __idle_free_do, ptr); +    } + +    return ptr; +} + +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(gchar *endpoint, 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(gchar *endpoint, 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; +} + +gchar * +h_sysfs_read_string(gchar *endpoint, 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; +} + diff --git a/hardinfo2/util/vendor.c b/hardinfo2/util/vendor.c new file mode 100644 index 00000000..86dba97a --- /dev/null +++ b/hardinfo2/util/vendor.c @@ -0,0 +1,195 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    List of vendors based on GtkSysInfo (c) Pissens Sebastien. + * + *    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 + */ + +#include <string.h> +#include <gtk/gtk.h> + +#include "vendor.h" +#include "syncmanager.h" +#include "config.h" +#include "hardinfo.h" + +static const Vendor vendors[] = { +    {"ATI", "ATI Technologies", "www.ati.com"}, +    {"nVidia", "NVIDIA", "www.nvidia.com"}, +    {"3Com", "3Com", "www.3com.com"}, +    {"Intel", "Intel", "www.intel.com"}, +    {"Cirrus Logic", "Cirrus Logic", "www.cirrus.com"}, +    {"VIA Technologies", "VIA Technologies", "www.via.com.tw"}, +    {"VIA", "VIA Technologies", "www.via.com.tw"}, +    {"hp", "Hewlett-Packard", "www.hp.com"}, +    {"NEC Corporation", "NEC Coporation", "www.nec.com"}, +    {"MAXTOR", "MAXTOR", "www.maxtor.com"}, +    {"SAMSUNG", "SAMSUNG", "www.samsung.com"}, +    {"PIONEER", "PIONEER", "www.pioneer-eur.com"}, +    {"PLEXTOR", "PLEXTOR", "www.plextor.be"}, +    {"Realtek Semiconductor", "Realtek", "www.realtek.com.tw"}, +    {"TOSHIBA", "TOSHIBA", "www.toshiba.com"}, +    {"LITE-ON", "LITE-ON", "www.liteonit.com"}, +    {"WDC", "Western Digital", "www.wdc.com"}, +    {"HL-DT-ST", "LG Electronics", "www.lge.com"}, +    {"ST", "SEAGATE", "www.seagate.com"}, +    {"Lexmark", "Lexmark", "www.lexmark.com"}, +    {"_NEC", "NEC Corporation", "www.nec.com"}, +    {"Creative Labs", "Creative Labs", "www.creative.com"}, +    {"Brooktree", "Conexant", "www.brooktree.com"}, +    {"Atheros", "Atheros Communications", "www.atheros.com"}, +    {"MATSHITA", "Panasonic", "www.panasonic.com"}, +    {"Silicon Image", "Silicon Image", "www.siliconimage.com"}, +    {"Silicon Integrated Image", "Silicon Image", "www.siliconimage.com"}, +    {"KYE", "KYE Systems", "www.genius-kye.com"}, +    {"Broadcom", "Broadcom", "www.broadcom.com"}, +    {"Apple", "Apple", "www.apple.com"}, +    {"IBM", "IBM", "www.ibm.com"}, +    {"Dell", "Dell Computer", "www.dell.com"}, +    {"Logitech", "Logitech International", "www.logitech.com"}, +    {"FUJITSU", "Fujitsu", "www.fujitsu.com"}, +    {"CDU", "Sony", "www.sony.com"}, +    {"SanDisk", "SanDisk", "www.sandisk.com"}, +    {"ExcelStor", "ExcelStor Technology", "www.excelstor.com"}, +    {"D-Link", "D-Link", "www.dlink.com.tw"}, +    {"Giga-byte", "Gigabyte Technology", "www.gigabyte.com.tw"}, +    {"Gigabyte", "Gigabyte Technology", "www.gigabyte.com.tw"}, +    {"C-Media", "C-Media Electronics", "www.cmedia.com.tw"}, +    {"Avermedia", "AVerMedia Technologies", "www.aver.com"}, +    {"Philips", "Philips", "www.philips.com"}, +    {"RaLink", "Ralink Technology", "www.ralinktech.com"}, +    {"Siemens", "Siemens AG", "www.siemens.com"}, +    {"HP", "Hewlett-Packard", "www.hp.com"}, +    {"Hewlett-Packard", "Hewlett-Packard", "www.hp.com"}, +    {"TEAC", "TEAC America", "www.teac.com"}, +    {"Microsoft", "Microsoft", "www.microsoft.com"}, +    {"Memorex", "Memorex Products", "www.memorex.com"}, +    {"eMPIA", "eMPIA Technology", "www.empiatech.com.tw"}, +    {"Canon", "Canon", "www.canon.com"}, +    {"A4Tech", "A4tech", "www.a4tech.com"}, +    {"ALCOR", "Alcor", "www.alcor.org"}, +    {"Vimicro", "Vimicro", "www.vimicro.com"}, +    {"OTi", "Ours Technology", "www.oti.com.tw"}, +    {"BENQ", "BenQ", "www.benq.com"}, +    {"Acer", "Acer", "www.acer.com"}, +    {"QUANTUM", "Quantum", "www.quantum.com"}, +    {"Kingston", "Kingston", "www.kingston.com"}, +    {"Chicony", "Chicony", "www.chicony.com.tw"}, +    {"Genius", "Genius", "www.genius.ru"}, +    /* BIOS manufacturers */ +    {"American Megatrends", "American Megatrends", "www.ami.com"}, +    {"Award", "Award Software International", "www.award-bios.com"}, +    {"Phoenix", "Phoenix Technologies", "www.phoenix.com"}, +}; + +static GSList *vendor_list = NULL; + +void vendor_init(void) +{ +    gint i; +    gchar *path; +    static SyncEntry se = { +       .fancy_name = "Update vendor list", +       .name = "RecvVendorList", +       .save_to = "vendor.conf", +       .get_data = NULL +    }; + +    DEBUG("initializing vendor list"); +    sync_manager_add_entry(&se); +     +    path = g_build_filename(g_get_home_dir(), ".hardinfo", "vendor.conf", NULL); +    if (!g_file_test(path, G_FILE_TEST_EXISTS)) { +      DEBUG("local vendor.conf not found, trying system-wise"); +      g_free(path); +      path = g_build_filename(params.path_data, "vendor.conf", NULL); +    } +     +    if (g_file_test(path, G_FILE_TEST_EXISTS)) { +      GKeyFile *vendors; +      gchar *tmp; +      gint num_vendors; +       +      DEBUG("loading %s", path); +       +      vendors = g_key_file_new(); +      if (g_key_file_load_from_file(vendors, path, 0, NULL)) { +        num_vendors = g_key_file_get_integer(vendors, "vendors", "number", NULL); +         +        for (i = num_vendors - 1; i >= 0; i--) { +          Vendor *v = g_new0(Vendor, 1); +           +          tmp = g_strdup_printf("vendor%d", i); +           +          v->id   = g_key_file_get_string(vendors, tmp, "id", NULL); +          v->name = g_key_file_get_string(vendors, tmp, "name", NULL); +          v->url  = g_key_file_get_string(vendors, tmp, "url", NULL); +           +          vendor_list = g_slist_prepend(vendor_list, v); +           +          g_free(tmp); +        } +      } +       +      g_key_file_free(vendors); +    } else { +      DEBUG("system-wise vendor.conf not found, using internal database"); +       +      for (i = G_N_ELEMENTS(vendors) - 1; i >= 0; i--) { +        vendor_list = g_slist_prepend(vendor_list, (gpointer) &vendors[i]); +      } +    }  + +    g_free(path); +} + +const gchar *vendor_get_name(const gchar * id) +{ +    GSList *vendor; +     +    if (!id) { +      return NULL; +    } +     +    for (vendor = vendor_list; vendor; vendor = vendor->next) { +      Vendor *v = (Vendor *)vendor->data; +       +      if (v && v->id && strstr(id, v->id)) { +        return g_strdup(v->name); +      } +    } + +    return id; +} + +const gchar *vendor_get_url(const gchar * id) +{ +    GSList *vendor; + +    if (!id) { +      return NULL; +    } +     +    for (vendor = vendor_list; vendor; vendor = vendor->next) { +      Vendor *v = (Vendor *)vendor->data; +       +      if (v && v->id && strstr(id, v->id)) { +        return g_strdup(v->url); +      } +    } + +    return NULL; +} | 
