#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pkg.h"
#include "parse.h"
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#else
# ifdef _AIX
# pragma alloca
# endif
#endif
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <ctype.h>
#ifdef G_OS_WIN32
#undef PKGLIBDIR
#define PKGLIBDIR g_strconcat (g_win32_get_package_installation_directory (PACKAGE, NULL), "\\lib\\pkgconfig", NULL)
#endif
static void verify_package (Package *pkg);
static GHashTable *packages = NULL;
static GHashTable *locations = NULL;
static GHashTable *path_positions = NULL;
static GHashTable *globals = NULL;
static GSList *search_dirs = NULL;
static int scanned_dir_count = 0;
gboolean disable_uninstalled = FALSE;
void
add_search_dir (const char *path)
{
search_dirs = g_slist_append (search_dirs, g_strdup (path));
}
#ifdef G_OS_WIN32
# define FOLD(x) tolower(x)
# define FOLDCMP(a, b) g_ascii_strcasecmp (a, b)
#else
# define FOLD(x) (x)
# define FOLDCMP(a, b) strcmp (a, b)
#endif
#define EXT_LEN 3
static gboolean
ends_in_dotpc (const char *str)
{
int len = strlen (str);
if (len > EXT_LEN &&
str[len - 3] == '.' &&
FOLD (str[len - 2]) == 'p' &&
FOLD (str[len - 1]) == 'c')
return TRUE;
else
return FALSE;
}
#define UNINSTALLED_LEN 11
gboolean
name_ends_in_uninstalled (const char *str)
{
int len = strlen (str);
if (len > UNINSTALLED_LEN &&
FOLDCMP ((str + len - UNINSTALLED_LEN), "uninstalled") == 0)
return TRUE;
else
return FALSE;
}
static void
scan_dir (const char *dirname)
{
DIR *dir;
struct dirent *dent;
int dirnamelen = strlen (dirname);
char *dirname_copy = g_strdup (dirname);
if (dirnamelen > 1 && dirname[dirnamelen-1] == G_DIR_SEPARATOR)
{
dirnamelen--;
dirname_copy[dirnamelen] = '\0';
}
dir = opendir (dirname_copy);
free (dirname_copy);
if (!dir)
{
debug_spew ("Cannot open directory '%s' in package search path: %s\n",
dirname, g_strerror (errno));
return;
}
debug_spew ("Scanning directory '%s'\n", dirname);
scanned_dir_count += 1;
while ((dent = readdir (dir)))
{
int len = strlen (dent->d_name);
if (ends_in_dotpc (dent->d_name))
{
char *pkgname = malloc (len - 2);
debug_spew ("File '%s' appears to be a .pc file\n", dent->d_name);
strncpy (pkgname, dent->d_name, len - EXT_LEN);
pkgname[len-EXT_LEN] = '\0';
if (g_hash_table_lookup (locations, pkgname))
{
debug_spew ("File '%s' ignored, we already know about package '%s'\n", dent->d_name, pkgname);
g_free (pkgname);
}
else
{
char *filename = g_malloc (dirnamelen + 1 + len + 1);
strncpy (filename, dirname, dirnamelen);
filename[dirnamelen] = G_DIR_SEPARATOR;
strcpy (filename + dirnamelen + 1, dent->d_name);
g_hash_table_insert (locations, pkgname, filename);
g_hash_table_insert (path_positions, pkgname,
GINT_TO_POINTER (scanned_dir_count));
debug_spew ("Will find package '%s' in file '%s'\n",
pkgname, filename);
}
}
else
{
debug_spew ("Ignoring file '%s' in search directory; not a .pc file\n",
dent->d_name);
}
}
}
void
package_init ()
{
static gboolean initted = FALSE;
const char *pkglibdir;
pkglibdir = g_getenv ("PKG_CONFIG_LIBDIR");
if (pkglibdir == NULL)
pkglibdir = PKGLIBDIR;
if (!initted)
{
initted = TRUE;
packages = g_hash_table_new (g_str_hash, g_str_equal);
locations = g_hash_table_new (g_str_hash, g_str_equal);
path_positions = g_hash_table_new (g_str_hash, g_str_equal);
g_slist_foreach (search_dirs, (GFunc)scan_dir, NULL);
scan_dir (pkglibdir);
}
}
static gboolean
file_readable (const char *path)
{
FILE *f = fopen (path, "r");
if (f != NULL)
{
fclose (f);
return TRUE;
}
else
return FALSE;
}
static Package *
internal_get_package (const char *name, gboolean warn, gboolean check_compat)
{
Package *pkg = NULL;
const char *location;
pkg = g_hash_table_lookup (packages, name);
if (pkg)
return pkg;
debug_spew ("Looking for package '%s'\n", name);
if ( ends_in_dotpc (name) )
{
debug_spew ("Considering '%s' to be a filename rather than a package name\n", name);
location = name;
}
else
{
if (!disable_uninstalled &&
!name_ends_in_uninstalled (name))
{
char *un;
un = g_strconcat (name, "-uninstalled", NULL);
pkg = internal_get_package (un, FALSE, FALSE);
g_free (un);
if (pkg)
{
debug_spew ("Preferring uninstalled version of package '%s'\n", name);
return pkg;
}
}
location = g_hash_table_lookup (locations, name);
}
if (location == NULL && check_compat)
{
pkg = get_compat_package (name);
if (pkg)
{
debug_spew ("Returning values for '%s' from a legacy -config script\n",
name);
return pkg;
}
}
if (location == NULL)
{
if (warn)
verbose_error ("Package %s was not found in the pkg-config search path.\n"
"Perhaps you should add the directory containing `%s.pc'\n"
"to the PKG_CONFIG_PATH environment variable\n",
name, name);
return NULL;
}
debug_spew ("Reading '%s' from file '%s'\n", name, location);
pkg = parse_package_file (location);
if (pkg == NULL)
{
debug_spew ("Failed to parse '%s'\n", location);
return NULL;
}
if (strstr (location, "uninstalled.pc"))
pkg->uninstalled = TRUE;
if (location != name)
pkg->key = g_strdup (name);
else
{
int len = strlen (name);
const char *end = name + (len - EXT_LEN);
const char *start = end;
while (start != name && *start != G_DIR_SEPARATOR)
--start;
g_assert (end >= start);
pkg->key = g_strndup (start, end - start);
}
pkg->path_position =
GPOINTER_TO_INT (g_hash_table_lookup (path_positions, pkg->key));
debug_spew ("Path position of '%s' is %d\n",
pkg->name, pkg->path_position);
verify_package (pkg);
debug_spew ("Adding '%s' to list of known packages, returning as package '%s'\n",
pkg->key, name);
g_hash_table_insert (packages, pkg->key, pkg);
return pkg;
}
Package *
get_package (const char *name)
{
return internal_get_package (name, TRUE, TRUE);
}
static GSList*
string_list_strip_duplicates (GSList *list)
{
GHashTable *table;
GSList *tmp;
GSList *nodups = NULL;
table = g_hash_table_new (g_str_hash, g_str_equal);
tmp = list;
while (tmp != NULL)
{
if (g_hash_table_lookup (table, tmp->data) == NULL)
{
nodups = g_slist_prepend (nodups, tmp->data);
g_hash_table_insert (table, tmp->data, tmp->data);
}
else
{
debug_spew (" removing duplicate \"%s\"\n", tmp->data);
}
tmp = g_slist_next (tmp);
}
nodups = g_slist_reverse (nodups);
g_hash_table_destroy (table);
return nodups;
}
static GSList*
string_list_strip_duplicates_from_back (GSList *list)
{
GHashTable *table;
GSList *tmp;
GSList *nodups = NULL;
GSList *reversed;
table = g_hash_table_new (g_str_hash, g_str_equal);
reversed = g_slist_reverse (g_slist_copy (list));
tmp = reversed;
while (tmp != NULL)
{
if (g_hash_table_lookup (table, tmp->data) == NULL)
{
nodups = g_slist_prepend (nodups, tmp->data);
g_hash_table_insert (table, tmp->data, tmp->data);
}
else
{
debug_spew (" removing duplicate (from back) \"%s\"\n", tmp->data);
}
tmp = g_slist_next (tmp);
}
g_slist_free (reversed);
g_hash_table_destroy (table);
return nodups;
}
static char *
string_list_to_string (GSList *list)
{
GSList *tmp;
GString *str = g_string_new ("");
char *retval;
tmp = list;
while (tmp != NULL)
{
g_string_append (str, tmp->data);
g_string_append_c (str, ' ');
tmp = g_slist_next (tmp);
}
retval = str->str;
g_string_free (str, FALSE);
return retval;
}
typedef GSList *(* GetListFunc) (Package *pkg);
static GSList *
get_l_libs (Package *pkg)
{
return pkg->l_libs;
}
static GSList *
get_L_libs (Package *pkg)
{
return pkg->L_libs;
}
static GSList*
get_other_libs (Package *pkg)
{
return pkg->other_libs;
}
static GSList *
get_I_cflags (Package *pkg)
{
return pkg->I_cflags;
}
static GSList *
get_other_cflags (Package *pkg)
{
return pkg->other_cflags;
}
static GSList *
get_conflicts (Package *pkg)
{
return pkg->conflicts;
}
static GSList *
get_requires (Package *pkg)
{
return pkg->requires;
}
static int
pathposcmp (gconstpointer a, gconstpointer b)
{
const Package *pa = a;
const Package *pb = b;
if (pa->path_position < pb->path_position)
return -1;
else if (pa->path_position > pb->path_position)
return 1;
else
return 0;
}
static void
spew_package_list (const char *name,
GSList *list)
{
GSList *tmp;
debug_spew (" %s: ", name);
tmp = list;
while (tmp != NULL)
{
Package *pkg = tmp->data;
debug_spew (" %s ", pkg->name);
tmp = tmp->next;
}
debug_spew ("\n");
}
static void
spew_string_list (const char *name,
GSList *list)
{
GSList *tmp;
debug_spew (" %s: ", name);
tmp = list;
while (tmp != NULL)
{
debug_spew (" %s ", tmp->data);
tmp = tmp->next;
}
debug_spew ("\n");
}
static GSList*
packages_sort_by_path_position (GSList *list)
{
return g_slist_sort (list, pathposcmp);
}
static void
fill_one_level (Package *pkg, GetListFunc func, GSList **listp)
{
GSList *copy;
copy = g_slist_copy ((*func)(pkg));
*listp = g_slist_concat (*listp, copy);
}
static void
recursive_fill_list (Package *pkg, GetListFunc func, GSList **listp)
{
GSList *tmp;
fill_one_level (pkg, func, listp);
tmp = pkg->requires;
while (tmp != NULL)
{
recursive_fill_list (tmp->data, func, listp);
tmp = g_slist_next (tmp);
}
}
static void
fill_list_single_package (Package *pkg, GetListFunc func,
GSList **listp, gboolean in_path_order)
{
GSList *packages;
GSList *tmp;
packages = NULL;
packages = g_slist_append (packages, pkg);
recursive_fill_list (pkg, get_requires, &packages);
if (in_path_order)
{
spew_package_list ("original", packages);
packages = packages_sort_by_path_position (packages);
spew_package_list ("sorted", packages);
}
tmp = packages;
while (tmp != NULL)
{
fill_one_level (tmp->data, func, listp);
tmp = tmp->next;
}
g_slist_free (packages);
}
static void
fill_list (GSList *packages, GetListFunc func,
GSList **listp, gboolean in_path_order)
{
GSList *tmp;
GSList *expanded;
expanded = NULL;
tmp = packages;
while (tmp != NULL)
{
expanded = g_slist_append (expanded, tmp->data);
recursive_fill_list (tmp->data, get_requires, &expanded);
tmp = tmp->next;
}
if (in_path_order)
{
spew_package_list ("original", expanded);
expanded = packages_sort_by_path_position (expanded);
spew_package_list ("sorted", expanded);
}
tmp = expanded;
while (tmp != NULL)
{
fill_one_level (tmp->data, func, listp);
tmp = tmp->next;
}
g_slist_free (expanded);
}
static gint
compare_req_version_names (gconstpointer a, gconstpointer b)
{
const RequiredVersion *ver_a = a;
const RequiredVersion *ver_b = b;
return strcmp (ver_a->name, ver_b->name);
}
static gint
compare_package_keys (gconstpointer a, gconstpointer b)
{
const Package *pkg_a = a;
const Package *pkg_b = b;
return strcmp (pkg_a->key, pkg_b->key);
}
static GSList *
add_env_variable_to_list (GSList *list, const gchar *env)
{
gchar **values;
gint i;
values = g_strsplit (env, ":", 0);
for (i = 0; values[i] != NULL; i++)
{
list = g_slist_append (list, g_strdup (values[i]));
}
g_strfreev (values);
return list;
}
static void
verify_package (Package *pkg)
{
GSList *requires = NULL;
GSList *conflicts = NULL;
GSList *system_directories = NULL;
GSList *iter;
GSList *requires_iter;
GSList *conflicts_iter;
GSList *system_dir_iter = NULL;
int count;
gchar *c_include_path;
if (pkg->key == NULL)
{
fprintf (stderr,
"Internal pkg-config error, package with no key, please file a bug report\n");
exit (1);
}
if (pkg->name == NULL)
{
verbose_error ("Package '%s' has no Name: field\n",
pkg->key);
exit (1);
}
if (pkg->version == NULL)
{
verbose_error ("Package '%s' has no Version: field\n",
pkg->name);
exit (1);
}
if (pkg->description == NULL)
{
verbose_error ("Package '%s' has no Description: field\n",
pkg->description);
exit (1);
}
iter = pkg->requires;
while (iter != NULL)
{
Package *req = iter->data;
RequiredVersion *ver = NULL;
if (pkg->required_versions)
ver = g_hash_table_lookup (pkg->required_versions,
req->key);
if (ver)
{
if (!version_test (ver->comparison, req->version, ver->version))
{
verbose_error ("Package '%s' requires '%s %s %s' but version of %s is %s\n",
pkg->name, req->key,
comparison_to_str (ver->comparison),
ver->version,
req->name,
req->version);
exit (1);
}
}
iter = g_slist_next (iter);
}
recursive_fill_list (pkg, get_requires, &requires);
recursive_fill_list (pkg, get_conflicts, &conflicts);
requires_iter = requires;
while (requires_iter != NULL)
{
Package *req = requires_iter->data;
conflicts_iter = conflicts;
while (conflicts_iter != NULL)
{
RequiredVersion *ver = conflicts_iter->data;
if (version_test (ver->comparison,
req->version,
ver->version))
{
verbose_error ("Version %s of %s creates a conflict.\n"
"(%s %s %s conflicts with %s %s)\n",
req->version, req->name,
ver->name,
comparison_to_str (ver->comparison),
ver->version,
ver->owner->name,
ver->owner->version);
exit (1);
}
conflicts_iter = g_slist_next (conflicts_iter);
}
requires_iter = g_slist_next (requires_iter);
}
g_slist_free (requires);
g_slist_free (conflicts);
system_directories = g_slist_append (NULL, g_strdup ("/usr/include"));
c_include_path = g_getenv ("C_INCLUDE_PATH");
if (c_include_path != NULL)
{
system_directories = add_env_variable_to_list (system_directories, c_include_path);
}
c_include_path = g_getenv ("CPLUS_INCLUDE_PATH");
if (c_include_path != NULL)
{
system_directories = add_env_variable_to_list (system_directories, c_include_path);
}
count = 0;
iter = pkg->I_cflags;
while (iter != NULL)
{
gint offset = 0;
if (((strncmp (iter->data, "-I", 2) == 0) && (offset = 2))||
((strncmp (iter->data, "-I ", 3) == 0) && (offset = 3)))
{
if (offset == 0)
{
iter = iter->next;
continue;
}
system_dir_iter = system_directories;
while (system_dir_iter != NULL)
{
if (strcmp (system_dir_iter->data,
((char*)iter->data) + offset) == 0)
{
debug_spew ("Package %s has %s in Cflags\n",
pkg->name, (gchar *)iter->data);
if (g_getenv ("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS") == NULL)
{
debug_spew ("Removing %s from cflags for %s\n", iter->data, pkg->key);
++count;
iter->data = NULL;
break;
}
}
system_dir_iter = system_dir_iter->next;
}
}
iter = iter->next;
}
while (count)
{
pkg->I_cflags = g_slist_remove (pkg->I_cflags, NULL);
--count;
}
g_slist_foreach (system_directories, (GFunc) g_free, NULL);
g_slist_free (system_directories);
count = 0;
iter = pkg->L_libs;
while (iter != NULL)
{
if (strcmp (iter->data, "-L/usr/lib") == 0 ||
strcmp (iter->data, "-L /usr/lib") == 0)
{
debug_spew ("Package %s has -L/usr/lib in Libs\n",
pkg->name);
if (g_getenv ("PKG_CONFIG_ALLOW_SYSTEM_LIBS") == NULL)
{
iter->data = NULL;
++count;
debug_spew ("Removing -L/usr/lib from libs for %s\n", pkg->key);
}
}
iter = iter->next;
}
while (count)
{
pkg->L_libs = g_slist_remove (pkg->L_libs, NULL);
--count;
}
}
static char*
get_merged (Package *pkg, GetListFunc func, gboolean in_path_order)
{
GSList *list;
GSList *dups_list = NULL;
char *retval;
fill_list_single_package (pkg, func, &dups_list, in_path_order);
list = string_list_strip_duplicates (dups_list);
g_slist_free (dups_list);
retval = string_list_to_string (list);
g_slist_free (list);
return retval;
}
static char*
get_merged_from_back (Package *pkg, GetListFunc func, gboolean in_path_order)
{
GSList *list;
GSList *dups_list = NULL;
char *retval;
fill_list_single_package (pkg, func, &dups_list, in_path_order);
list = string_list_strip_duplicates_from_back (dups_list);
g_slist_free (dups_list);
retval = string_list_to_string (list);
g_slist_free (list);
return retval;
}
static char*
get_multi_merged (GSList *pkgs, GetListFunc func, gboolean in_path_order)
{
GSList *tmp;
GSList *dups_list = NULL;
GSList *list;
char *retval;
fill_list (pkgs, func, &dups_list, in_path_order);
list = string_list_strip_duplicates (dups_list);
g_slist_free (dups_list);
retval = string_list_to_string (list);
g_slist_free (list);
return retval;
}
static char*
get_multi_merged_from_back (GSList *pkgs, GetListFunc func, gboolean in_path_order)
{
GSList *tmp;
GSList *dups_list = NULL;
GSList *list;
char *retval;
fill_list (pkgs, func, &dups_list, in_path_order);
list = string_list_strip_duplicates_from_back (dups_list);
g_slist_free (dups_list);
retval = string_list_to_string (list);
g_slist_free (list);
return retval;
}
char *
package_get_l_libs (Package *pkg)
{
if (pkg->l_libs_merged == NULL)
pkg->l_libs_merged = get_merged_from_back (pkg, get_l_libs, FALSE);
return pkg->l_libs_merged;
}
char *
packages_get_l_libs (GSList *pkgs)
{
return get_multi_merged_from_back (pkgs, get_l_libs, FALSE);
}
char *
package_get_L_libs (Package *pkg)
{
if (pkg->L_libs_merged == NULL)
pkg->L_libs_merged = get_merged (pkg, get_L_libs, TRUE);
return pkg->L_libs_merged;
}
char *
packages_get_L_libs (GSList *pkgs)
{
return get_multi_merged (pkgs, get_L_libs, TRUE);
}
char *
package_get_other_libs (Package *pkg)
{
if (pkg->other_libs_merged == NULL)
pkg->other_libs_merged = get_merged (pkg, get_other_libs, TRUE);
return pkg->other_libs_merged;
}
char *
packages_get_other_libs (GSList *pkgs)
{
return get_multi_merged (pkgs, get_other_libs, TRUE);
}
char *
packages_get_all_libs (GSList *pkgs)
{
char *l_libs;
char *L_libs;
char *other_libs;
GString *str;
char *retval;
str = g_string_new ("");
other_libs = packages_get_other_libs (pkgs);
L_libs = packages_get_L_libs (pkgs);
l_libs = packages_get_l_libs (pkgs);
if (other_libs)
g_string_append (str, other_libs);
if (L_libs)
g_string_append (str, L_libs);
if (l_libs)
g_string_append (str, l_libs);
g_free (l_libs);
g_free (L_libs);
g_free (other_libs);
retval = str->str;
g_string_free (str, FALSE);
return retval;
}
char *
package_get_I_cflags (Package *pkg)
{
if (pkg->I_cflags_merged == NULL)
pkg->I_cflags_merged = get_merged (pkg, get_I_cflags, TRUE);
return pkg->I_cflags_merged;
}
char *
packages_get_I_cflags (GSList *pkgs)
{
return get_multi_merged (pkgs, get_I_cflags, TRUE);
}
char *
package_get_other_cflags (Package *pkg)
{
if (pkg->other_cflags_merged == NULL)
pkg->other_cflags_merged = get_merged (pkg, get_other_cflags, TRUE);
return pkg->other_cflags_merged;
}
char *
packages_get_other_cflags (GSList *pkgs)
{
return get_multi_merged (pkgs, get_other_cflags, TRUE);
}
char *
package_get_cflags (Package *pkg)
{
g_assert_not_reached ();
return NULL;
}
char *
packages_get_all_cflags (GSList *pkgs)
{
char *I_cflags;
char *other_cflags;
GString *str;
char *retval;
str = g_string_new ("");
other_cflags = packages_get_other_cflags (pkgs);
I_cflags = packages_get_I_cflags (pkgs);
if (other_cflags)
g_string_append (str, other_cflags);
if (I_cflags)
g_string_append (str, I_cflags);
g_free (I_cflags);
g_free (other_cflags);
retval = str->str;
g_string_free (str, FALSE);
return retval;
}
void
define_global_variable (const char *varname,
const char *varval)
{
if (globals == NULL)
globals = g_hash_table_new (g_str_hash, g_str_equal);
if (g_hash_table_lookup (globals, varname))
{
verbose_error ("Variable '%s' defined twice globally\n", varname);
exit (1);
}
g_hash_table_insert (globals, g_strdup (varname), g_strdup (varval));
debug_spew ("Global variable definition '%s' = '%s'\n",
varname, varval);
}
char *
package_get_var (Package *pkg,
const char *var)
{
char *varval = NULL;
if (globals)
varval = g_hash_table_lookup (globals, var);
if (varval == NULL && pkg->vars)
varval = g_strdup (g_hash_table_lookup (pkg->vars, var));
if (varval == NULL && pkg->pcfiledir && strcmp (var, "pcfiledir") == 0)
varval = g_strdup (pkg->pcfiledir);
return varval;
}
char *
packages_get_var (GSList *pkgs,
const char *varname)
{
GSList *tmp;
GString *str;
char *retval;
str = g_string_new ("");
tmp = pkgs;
while (tmp != NULL)
{
Package *pkg = tmp->data;
char *var;
var = package_get_var (pkg, varname);
if (var)
{
g_string_append (str, var);
g_string_append_c (str, ' ');
g_free (var);
}
tmp = g_slist_next (tmp);
}
str->str[str->len - 1] = '\0';
retval = str->str;
g_string_free (str, FALSE);
return retval;
}
static int rpmvercmp(const char * a, const char * b) {
char oldch1, oldch2;
char * str1, * str2;
char * one, * two;
int rc;
int isnum;
if (!strcmp(a, b)) return 0;
str1 = alloca(strlen(a) + 1);
str2 = alloca(strlen(b) + 1);
strcpy(str1, a);
strcpy(str2, b);
one = str1;
two = str2;
while (*one && *two) {
while (*one && !isalnum((guchar)*one)) one++;
while (*two && !isalnum((guchar)*two)) two++;
str1 = one;
str2 = two;
if (isdigit((guchar)*str1)) {
while (*str1 && isdigit((guchar)*str1)) str1++;
while (*str2 && isdigit((guchar)*str2)) str2++;
isnum = 1;
} else {
while (*str1 && isalpha((guchar)*str1)) str1++;
while (*str2 && isalpha((guchar)*str2)) str2++;
isnum = 0;
}
oldch1 = *str1;
*str1 = '\0';
oldch2 = *str2;
*str2 = '\0';
if (one == str1) return -1;
if (two == str2) return -1;
if (isnum) {
while (*one == '0') one++;
while (*two == '0') two++;
if (strlen(one) > strlen(two)) return 1;
if (strlen(two) > strlen(one)) return -1;
}
rc = strcmp(one, two);
if (rc) return rc;
*str1 = oldch1;
one = str1;
*str2 = oldch2;
two = str2;
}
if ((!*one) && (!*two)) return 0;
if (!*one) return -1; else return 1;
}
int
compare_versions (const char * a, const char *b)
{
return rpmvercmp (a, b);
}
gboolean
version_test (ComparisonType comparison,
const char *a,
const char *b)
{
switch (comparison)
{
case LESS_THAN:
return compare_versions (a, b) < 0;
break;
case GREATER_THAN:
return compare_versions (a, b) > 0;
break;
case LESS_THAN_EQUAL:
return compare_versions (a, b) <= 0;
break;
case GREATER_THAN_EQUAL:
return compare_versions (a, b) >= 0;
break;
case EQUAL:
return compare_versions (a, b) == 0;
break;
case NOT_EQUAL:
return compare_versions (a, b) != 0;
break;
case ALWAYS_MATCH:
return TRUE;
break;
default:
g_assert_not_reached ();
break;
}
return FALSE;
}
const char *
comparison_to_str (ComparisonType comparison)
{
switch (comparison)
{
case LESS_THAN:
return "<";
break;
case GREATER_THAN:
return ">";
break;
case LESS_THAN_EQUAL:
return "<=";
break;
case GREATER_THAN_EQUAL:
return ">=";
break;
case EQUAL:
return "=";
break;
case NOT_EQUAL:
return "!=";
break;
case ALWAYS_MATCH:
return "(any)";
break;
default:
g_assert_not_reached ();
break;
}
return "???";
}
static void
max_len_foreach (gpointer key, gpointer value, gpointer data)
{
int *mlen = data;
*mlen = MAX (*mlen, strlen (key));
}
static void
packages_foreach (gpointer key, gpointer value, gpointer data)
{
Package *pkg = get_package (key);
if (pkg != NULL)
{
char *pad;
pad = g_strnfill (GPOINTER_TO_INT (data) - strlen (pkg->key), ' ');
printf ("%s%s%s - %s\n",
pkg->key, pad, pkg->name, pkg->description);
g_free (pad);
}
}
void
print_package_list (void)
{
int mlen = 0;
g_hash_table_foreach (locations, max_len_foreach, &mlen);
g_hash_table_foreach (locations, packages_foreach, GINT_TO_POINTER (mlen + 1));
}