2 * Copyright (C) 2001, 2002 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
40 #include <sys/types.h>
51 static void verify_package (Package *pkg);
53 static GHashTable *packages = NULL;
54 static GHashTable *locations = NULL;
55 static GHashTable *path_positions = NULL;
56 static GHashTable *globals = NULL;
57 static GSList *search_dirs = NULL;
58 static int scanned_dir_count = 0;
60 gboolean disable_uninstalled = FALSE;
61 gboolean ignore_requires = FALSE;
62 gboolean ignore_requires_private = TRUE;
63 gboolean ignore_private_libs = TRUE;
66 add_search_dir (const char *path)
68 search_dirs = g_slist_append (search_dirs, g_strdup (path));
72 add_search_dirs (const char *path, const char *separator)
77 search_dirs = g_strsplit (path, separator, -1);
82 debug_spew ("Adding directory '%s' from PKG_CONFIG_PATH\n",
84 add_search_dir (*iter);
89 g_strfreev (search_dirs);
93 /* Guard against .pc file being installed with UPPER CASE name */
94 # define FOLD(x) tolower(x)
95 # define FOLDCMP(a, b) g_ascii_strcasecmp (a, b)
98 # define FOLDCMP(a, b) strcmp (a, b)
104 ends_in_dotpc (const char *str)
106 int len = strlen (str);
109 str[len - 3] == '.' &&
110 FOLD (str[len - 2]) == 'p' &&
111 FOLD (str[len - 1]) == 'c')
117 /* strlen ("uninstalled") */
118 #define UNINSTALLED_LEN 11
121 name_ends_in_uninstalled (const char *str)
123 int len = strlen (str);
125 if (len > UNINSTALLED_LEN &&
126 FOLDCMP ((str + len - UNINSTALLED_LEN), "uninstalled") == 0)
133 /* Look for .pc files in the given directory and add them into
134 * locations, ignoring duplicates
137 scan_dir (const char *dirname)
141 int dirnamelen = strlen (dirname);
142 /* Use a copy of dirname cause Win32 opendir doesn't like
143 * superfluous trailing (back)slashes in the directory name.
145 char *dirname_copy = g_strdup (dirname);
147 if (dirnamelen > 1 && dirname[dirnamelen-1] == G_DIR_SEPARATOR)
150 dirname_copy[dirnamelen] = '\0';
155 /* Turn backslashes into slashes or
156 * poptParseArgvString() will eat them when ${prefix}
157 * has been expanded in parse_libs().
168 dir = opendir (dirname_copy);
169 g_free (dirname_copy);
172 debug_spew ("Cannot open directory '%s' in package search path: %s\n",
173 dirname, g_strerror (errno));
177 debug_spew ("Scanning directory '%s'\n", dirname);
179 scanned_dir_count += 1;
181 while ((dent = readdir (dir)))
183 int len = strlen (dent->d_name);
185 if (ends_in_dotpc (dent->d_name))
187 char *pkgname = g_malloc (len - 2);
189 debug_spew ("File '%s' appears to be a .pc file\n", dent->d_name);
191 strncpy (pkgname, dent->d_name, len - EXT_LEN);
192 pkgname[len-EXT_LEN] = '\0';
194 if (g_hash_table_lookup (locations, pkgname))
196 debug_spew ("File '%s' ignored, we already know about package '%s'\n", dent->d_name, pkgname);
201 char *filename = g_malloc (dirnamelen + 1 + len + 1);
202 strncpy (filename, dirname, dirnamelen);
203 filename[dirnamelen] = G_DIR_SEPARATOR;
204 strcpy (filename + dirnamelen + 1, dent->d_name);
206 g_hash_table_insert (locations, pkgname, filename);
207 g_hash_table_insert (path_positions, pkgname,
208 GINT_TO_POINTER (scanned_dir_count));
210 debug_spew ("Will find package '%s' in file '%s'\n",
216 debug_spew ("Ignoring file '%s' in search directory; not a .pc file\n",
224 add_virtual_pkgconfig_package (void)
228 pkg = g_new0 (Package, 1);
230 pkg->key = g_strdup ("pkg-config");
231 pkg->version = g_strdup (VERSION);
232 pkg->name = g_strdup ("pkg-config");
233 pkg->description = g_strdup ("pkg-config is a system for managing "
234 "compile/link flags for libraries");
235 pkg->url = g_strdup ("http://pkg-config.freedesktop.org/");
237 if (pkg->vars == NULL)
238 pkg->vars = g_hash_table_new (g_str_hash, g_str_equal);
239 g_hash_table_insert (pkg->vars, "pc_path", PKG_CONFIG_PC_PATH);
241 debug_spew ("Adding virtual 'pkg-config' package to list of known packages\n");
242 g_hash_table_insert (packages, pkg->key, pkg);
250 static gboolean initted = FALSE;
256 packages = g_hash_table_new (g_str_hash, g_str_equal);
257 locations = g_hash_table_new (g_str_hash, g_str_equal);
258 path_positions = g_hash_table_new (g_str_hash, g_str_equal);
260 add_virtual_pkgconfig_package ();
262 g_slist_foreach (search_dirs, (GFunc)scan_dir, NULL);
267 file_readable (const char *path)
269 FILE *f = fopen (path, "r");
282 internal_get_package (const char *name, gboolean warn, gboolean check_compat)
285 const char *location;
287 pkg = g_hash_table_lookup (packages, name);
292 debug_spew ("Looking for package '%s'\n", name);
294 /* treat "name" as a filename if it ends in .pc and exists */
295 if ( ends_in_dotpc (name) )
297 debug_spew ("Considering '%s' to be a filename rather than a package name\n", name);
302 /* See if we should auto-prefer the uninstalled version */
303 if (!disable_uninstalled &&
304 !name_ends_in_uninstalled (name))
308 un = g_strconcat (name, "-uninstalled", NULL);
310 pkg = internal_get_package (un, FALSE, FALSE);
316 debug_spew ("Preferring uninstalled version of package '%s'\n", name);
321 location = g_hash_table_lookup (locations, name);
324 if (location == NULL && check_compat)
326 pkg = get_compat_package (name);
330 debug_spew ("Returning values for '%s' from a legacy -config script\n",
337 if (location == NULL)
340 verbose_error ("Package %s was not found in the pkg-config search path.\n"
341 "Perhaps you should add the directory containing `%s.pc'\n"
342 "to the PKG_CONFIG_PATH environment variable\n",
348 debug_spew ("Reading '%s' from file '%s'\n", name, location);
349 pkg = parse_package_file (location, ignore_requires, ignore_private_libs,
350 ignore_requires_private);
354 debug_spew ("Failed to parse '%s'\n", location);
358 if (strstr (location, "uninstalled.pc"))
359 pkg->uninstalled = TRUE;
361 if (location != name)
362 pkg->key = g_strdup (name);
365 /* need to strip package name out of the filename */
366 int len = strlen (name);
367 const char *end = name + (len - EXT_LEN);
368 const char *start = end;
370 while (start != name && *start != G_DIR_SEPARATOR)
373 g_assert (end >= start);
375 pkg->key = g_strndup (start, end - start);
379 GPOINTER_TO_INT (g_hash_table_lookup (path_positions, pkg->key));
381 debug_spew ("Path position of '%s' is %d\n",
382 pkg->name, pkg->path_position);
384 verify_package (pkg);
386 debug_spew ("Adding '%s' to list of known packages, returning as package '%s'\n",
389 g_hash_table_insert (packages, pkg->key, pkg);
395 get_package (const char *name)
397 return internal_get_package (name, TRUE, TRUE);
401 get_package_quiet (const char *name)
403 return internal_get_package (name, FALSE, TRUE);
407 string_list_strip_duplicates (GSList *list)
411 GSList *nodups = NULL;
413 table = g_hash_table_new (g_str_hash, g_str_equal);
418 if (g_hash_table_lookup (table, tmp->data) == NULL)
420 nodups = g_slist_prepend (nodups, tmp->data);
421 g_hash_table_insert (table, tmp->data, tmp->data);
425 debug_spew (" removing duplicate \"%s\"\n", tmp->data);
428 tmp = g_slist_next (tmp);
431 nodups = g_slist_reverse (nodups);
433 g_hash_table_destroy (table);
439 string_list_strip_duplicates_from_back (GSList *list)
443 GSList *nodups = NULL;
446 table = g_hash_table_new (g_str_hash, g_str_equal);
448 reversed = g_slist_reverse (g_slist_copy (list));
453 if (g_hash_table_lookup (table, tmp->data) == NULL)
455 /* This unreverses the reversed list */
456 nodups = g_slist_prepend (nodups, tmp->data);
457 g_hash_table_insert (table, tmp->data, tmp->data);
461 debug_spew (" removing duplicate (from back) \"%s\"\n", tmp->data);
464 tmp = g_slist_next (tmp);
467 g_slist_free (reversed);
469 g_hash_table_destroy (table);
475 string_list_to_string (GSList *list)
478 GString *str = g_string_new ("");
484 char *tmpstr = (char*) tmp->data;
485 if (pcsysrootdir != NULL)
487 if (tmpstr[0] == '-' &&
491 g_string_append_c (str, '-');
492 g_string_append_c (str, tmpstr[1]);
493 g_string_append (str, pcsysrootdir);
494 g_string_append (str, tmpstr+2);
498 g_string_append (str, tmpstr);
503 g_string_append (str, tmpstr);
505 g_string_append_c (str, ' ');
507 tmp = g_slist_next (tmp);
511 g_string_free (str, FALSE);
516 typedef GSList *(* GetListFunc) (Package *pkg);
519 get_l_libs (Package *pkg)
525 get_L_libs (Package *pkg)
531 get_other_libs (Package *pkg)
533 return pkg->other_libs;
537 get_I_cflags (Package *pkg)
539 return pkg->I_cflags;
543 get_other_cflags (Package *pkg)
545 return pkg->other_cflags;
549 get_conflicts (Package *pkg)
551 return pkg->conflicts;
555 get_requires (Package *pkg)
557 return pkg->requires;
561 get_requires_private (Package *pkg)
563 return pkg->requires_private;
567 pathposcmp (gconstpointer a, gconstpointer b)
569 const Package *pa = a;
570 const Package *pb = b;
572 if (pa->path_position < pb->path_position)
574 else if (pa->path_position > pb->path_position)
581 spew_package_list (const char *name,
586 debug_spew (" %s: ", name);
591 Package *pkg = tmp->data;
592 debug_spew (" %s ", pkg->name);
599 spew_string_list (const char *name,
604 debug_spew (" %s: ", name);
609 debug_spew (" %s ", tmp->data);
616 packages_sort_by_path_position (GSList *list)
618 return g_slist_sort (list, pathposcmp);
622 fill_one_level (Package *pkg, GetListFunc func, GSList **listp)
626 copy = g_slist_copy ((*func)(pkg));
628 *listp = g_slist_concat (*listp, copy);
632 recursive_fill_list (Package *pkg, GetListFunc func, GSList **listp)
636 fill_one_level (pkg, func, listp);
642 recursive_fill_list (tmp->data, func, listp);
644 tmp = g_slist_next (tmp);
649 fill_list_single_package (Package *pkg, GetListFunc func,
650 GSList **listp, gboolean in_path_order,
651 gboolean include_private)
653 /* First we get the list in natural/recursive order, then
654 * stable sort by path position
659 /* Get list of packages */
661 packages = g_slist_append (packages, pkg);
662 recursive_fill_list (pkg,
663 include_private ? get_requires_private : get_requires,
668 spew_package_list ("original", packages);
670 packages = packages_sort_by_path_position (packages);
672 spew_package_list ("sorted", packages);
675 /* Convert package list to string list */
679 fill_one_level (tmp->data, func, listp);
684 g_slist_free (packages);
688 fill_list (GSList *packages, GetListFunc func,
689 GSList **listp, gboolean in_path_order, gboolean include_private)
698 expanded = g_slist_append (expanded, tmp->data);
699 recursive_fill_list (tmp->data,
700 include_private ? get_requires_private : get_requires,
708 spew_package_list ("original", expanded);
710 expanded = packages_sort_by_path_position (expanded);
712 spew_package_list ("sorted", expanded);
718 fill_one_level (tmp->data, func, listp);
723 g_slist_free (expanded);
727 compare_req_version_names (gconstpointer a, gconstpointer b)
729 const RequiredVersion *ver_a = a;
730 const RequiredVersion *ver_b = b;
732 return strcmp (ver_a->name, ver_b->name);
736 compare_package_keys (gconstpointer a, gconstpointer b)
738 const Package *pkg_a = a;
739 const Package *pkg_b = b;
741 return strcmp (pkg_a->key, pkg_b->key);
745 add_env_variable_to_list (GSList *list, const gchar *env)
750 values = g_strsplit (env, G_SEARCHPATH_SEPARATOR_S, 0);
751 for (i = 0; values[i] != NULL; i++)
753 list = g_slist_append (list, g_strdup (values[i]));
761 verify_package (Package *pkg)
763 GSList *requires = NULL;
764 GSList *conflicts = NULL;
765 GSList *system_directories = NULL;
767 GSList *requires_iter;
768 GSList *conflicts_iter;
769 GSList *system_dir_iter = NULL;
771 const gchar *c_include_path;
773 /* Be sure we have the required fields */
775 if (pkg->key == NULL)
778 "Internal pkg-config error, package with no key, please file a bug report\n");
782 if (pkg->name == NULL)
784 verbose_error ("Package '%s' has no Name: field\n",
789 if (pkg->version == NULL)
791 verbose_error ("Package '%s' has no Version: field\n",
796 if (pkg->description == NULL)
798 verbose_error ("Package '%s' has no Description: field\n",
803 /* Make sure we have the right version for all requirements */
805 iter = pkg->requires_private;
809 Package *req = iter->data;
810 RequiredVersion *ver = NULL;
812 if (pkg->required_versions)
813 ver = g_hash_table_lookup (pkg->required_versions,
818 if (!version_test (ver->comparison, req->version, ver->version))
820 verbose_error ("Package '%s' requires '%s %s %s' but version of %s is %s\n",
822 comparison_to_str (ver->comparison),
827 verbose_error ("You may find new versions of %s at %s\n",
828 req->name, req->url);
834 iter = g_slist_next (iter);
837 /* Make sure we didn't drag in any conflicts via Requires
838 * (inefficient algorithm, who cares)
841 recursive_fill_list (pkg, get_requires_private, &requires);
842 conflicts = get_conflicts (pkg);
844 requires_iter = requires;
845 while (requires_iter != NULL)
847 Package *req = requires_iter->data;
849 conflicts_iter = conflicts;
851 while (conflicts_iter != NULL)
853 RequiredVersion *ver = conflicts_iter->data;
855 if (strcmp (ver->name, req->key) == 0 &&
856 version_test (ver->comparison,
860 verbose_error ("Version %s of %s creates a conflict.\n"
861 "(%s %s %s conflicts with %s %s)\n",
862 req->version, req->name,
864 comparison_to_str (ver->comparison),
865 ver->version ? ver->version : "(any)",
867 ver->owner->version);
872 conflicts_iter = g_slist_next (conflicts_iter);
875 requires_iter = g_slist_next (requires_iter);
878 g_slist_free (requires);
880 /* We make a list of system directories that gcc expects so we can remove
884 system_directories = g_slist_append (NULL, g_strdup ("/usr/include"));
887 c_include_path = g_getenv ("C_INCLUDE_PATH");
888 if (c_include_path != NULL)
890 system_directories = add_env_variable_to_list (system_directories, c_include_path);
893 c_include_path = g_getenv ("CPLUS_INCLUDE_PATH");
894 if (c_include_path != NULL)
896 system_directories = add_env_variable_to_list (system_directories, c_include_path);
900 iter = pkg->I_cflags;
904 /* we put things in canonical -I/usr/include (vs. -I /usr/include) format,
905 * but if someone changes it later we may as well be robust
907 if (((strncmp (iter->data, "-I", 2) == 0) && (offset = 2))||
908 ((strncmp (iter->data, "-I ", 3) == 0) && (offset = 3)))
916 system_dir_iter = system_directories;
917 while (system_dir_iter != NULL)
919 if (strcmp (system_dir_iter->data,
920 ((char*)iter->data) + offset) == 0)
922 debug_spew ("Package %s has %s in Cflags\n",
923 pkg->name, (gchar *)iter->data);
924 if (g_getenv ("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS") == NULL)
926 debug_spew ("Removing %s from cflags for %s\n", iter->data, pkg->key);
933 system_dir_iter = system_dir_iter->next;
942 pkg->I_cflags = g_slist_remove (pkg->I_cflags, NULL);
946 g_slist_foreach (system_directories, (GFunc) g_free, NULL);
947 g_slist_free (system_directories);
950 #define SYSTEM_LIBDIR "/usr/lib64"
952 #define SYSTEM_LIBDIR "/usr/lib"
958 if (strcmp (iter->data, "-L" SYSTEM_LIBDIR) == 0 ||
959 strcmp (iter->data, "-L " SYSTEM_LIBDIR) == 0)
961 debug_spew ("Package %s has -L" SYSTEM_LIBDIR " in Libs\n",
963 if (g_getenv ("PKG_CONFIG_ALLOW_SYSTEM_LIBS") == NULL)
967 debug_spew ("Removing -L" SYSTEM_LIBDIR " from libs for %s\n", pkg->key);
977 pkg->L_libs = g_slist_remove (pkg->L_libs, NULL);
983 get_merged (Package *pkg, GetListFunc func, gboolean in_path_order,
984 gboolean include_private)
987 GSList *dups_list = NULL;
990 fill_list_single_package (pkg, func, &dups_list, in_path_order,
993 list = string_list_strip_duplicates (dups_list);
995 g_slist_free (dups_list);
997 retval = string_list_to_string (list);
1005 get_merged_from_back (Package *pkg, GetListFunc func, gboolean in_path_order,
1006 gboolean include_private)
1009 GSList *dups_list = NULL;
1012 fill_list_single_package (pkg, func, &dups_list, in_path_order,
1015 list = string_list_strip_duplicates_from_back (dups_list);
1017 g_slist_free (dups_list);
1019 retval = string_list_to_string (list);
1021 g_slist_free (list);
1027 get_multi_merged (GSList *pkgs, GetListFunc func, gboolean in_path_order,
1028 gboolean include_private)
1031 GSList *dups_list = NULL;
1035 fill_list (pkgs, func, &dups_list, in_path_order, include_private);
1037 list = string_list_strip_duplicates (dups_list);
1039 g_slist_free (dups_list);
1041 retval = string_list_to_string (list);
1043 g_slist_free (list);
1049 get_multi_merged_from_back (GSList *pkgs, GetListFunc func,
1050 gboolean in_path_order, gboolean include_private)
1053 GSList *dups_list = NULL;
1057 fill_list (pkgs, func, &dups_list, in_path_order, include_private);
1059 list = string_list_strip_duplicates_from_back (dups_list);
1061 g_slist_free (dups_list);
1063 retval = string_list_to_string (list);
1065 g_slist_free (list);
1071 package_get_l_libs (Package *pkg)
1073 /* We don't want these in search path order, rather in dependency
1074 * order, so static linking works.
1076 if (pkg->l_libs_merged == NULL)
1077 pkg->l_libs_merged = get_merged_from_back (pkg, get_l_libs, FALSE,
1078 !ignore_private_libs);
1080 return pkg->l_libs_merged;
1084 packages_get_l_libs (GSList *pkgs)
1086 return get_multi_merged_from_back (pkgs, get_l_libs, FALSE,
1087 !ignore_private_libs);
1091 package_get_L_libs (Package *pkg)
1093 /* We want these in search path order so the -L flags don't override PKG_CONFIG_PATH */
1094 if (pkg->L_libs_merged == NULL)
1095 pkg->L_libs_merged = get_merged (pkg, get_L_libs, TRUE,
1096 !ignore_private_libs);
1098 return pkg->L_libs_merged;
1102 packages_get_L_libs (GSList *pkgs)
1104 return get_multi_merged (pkgs, get_L_libs, TRUE, !ignore_private_libs);
1108 package_get_other_libs (Package *pkg)
1110 if (pkg->other_libs_merged == NULL)
1111 pkg->other_libs_merged = get_merged (pkg, get_other_libs, TRUE,
1112 !ignore_private_libs);
1114 return pkg->other_libs_merged;
1118 packages_get_other_libs (GSList *pkgs)
1120 return get_multi_merged (pkgs, get_other_libs, TRUE, !ignore_private_libs);
1124 packages_get_all_libs (GSList *pkgs)
1132 str = g_string_new ("");
1134 other_libs = packages_get_other_libs (pkgs);
1135 L_libs = packages_get_L_libs (pkgs);
1136 l_libs = packages_get_l_libs (pkgs);
1139 g_string_append (str, other_libs);
1142 g_string_append (str, L_libs);
1145 g_string_append (str, l_libs);
1149 g_free (other_libs);
1153 g_string_free (str, FALSE);
1159 package_get_I_cflags (Package *pkg)
1161 /* sort by path position so PKG_CONFIG_PATH affects -I flag order */
1162 if (pkg->I_cflags_merged == NULL)
1163 pkg->I_cflags_merged = get_merged (pkg, get_I_cflags, TRUE, FALSE);
1165 return pkg->I_cflags_merged;
1169 packages_get_I_cflags (GSList *pkgs)
1171 /* sort by path position so PKG_CONFIG_PATH affects -I flag order */
1172 return get_multi_merged (pkgs, get_I_cflags, TRUE, TRUE);
1176 package_get_other_cflags (Package *pkg)
1178 if (pkg->other_cflags_merged == NULL)
1179 pkg->other_cflags_merged = get_merged (pkg, get_other_cflags, TRUE, TRUE);
1181 return pkg->other_cflags_merged;
1185 packages_get_other_cflags (GSList *pkgs)
1187 return get_multi_merged (pkgs, get_other_cflags, TRUE, TRUE);
1191 package_get_cflags (Package *pkg)
1194 g_assert_not_reached ();
1199 packages_get_all_cflags (GSList *pkgs)
1206 str = g_string_new ("");
1208 other_cflags = packages_get_other_cflags (pkgs);
1209 I_cflags = packages_get_I_cflags (pkgs);
1212 g_string_append (str, other_cflags);
1215 g_string_append (str, I_cflags);
1218 g_free (other_cflags);
1222 g_string_free (str, FALSE);
1229 define_global_variable (const char *varname,
1232 if (globals == NULL)
1233 globals = g_hash_table_new (g_str_hash, g_str_equal);
1235 if (g_hash_table_lookup (globals, varname))
1237 verbose_error ("Variable '%s' defined twice globally\n", varname);
1241 g_hash_table_insert (globals, g_strdup (varname), g_strdup (varval));
1243 debug_spew ("Global variable definition '%s' = '%s'\n",
1248 package_get_var (Package *pkg,
1251 char *varval = NULL;
1254 varval = g_strdup (g_hash_table_lookup (globals, var));
1256 if (varval == NULL && pkg->vars)
1257 varval = g_strdup (g_hash_table_lookup (pkg->vars, var));
1259 /* Magic "pcfiledir" variable */
1260 if (varval == NULL && pkg->pcfiledir && strcmp (var, "pcfiledir") == 0)
1261 varval = g_strdup (pkg->pcfiledir);
1267 packages_get_var (GSList *pkgs,
1268 const char *varname)
1274 str = g_string_new ("");
1279 Package *pkg = tmp->data;
1282 var = package_get_var (pkg, varname);
1286 g_string_append (str, var);
1287 g_string_append_c (str, ' ');
1291 tmp = g_slist_next (tmp);
1294 /* chop last space */
1296 str->str[str->len - 1] = '\0';
1298 g_string_free (str, FALSE);
1305 /* Stolen verbatim from rpm/lib/misc.c
1306 RPM is Copyright (c) 1998 by Red Hat Software, Inc.,
1307 and may be distributed under the terms of the GPL and LGPL.
1309 /* compare alpha and numeric segments of two versions */
1310 /* return 1: a is newer than b */
1311 /* 0: a and b are the same version */
1312 /* -1: b is newer than a */
1313 static int rpmvercmp(const char * a, const char * b) {
1314 char oldch1, oldch2;
1315 char * str1, * str2;
1320 /* easy comparison to see if versions are identical */
1321 if (!strcmp(a, b)) return 0;
1323 str1 = alloca(strlen(a) + 1);
1324 str2 = alloca(strlen(b) + 1);
1332 /* loop through each version segment of str1 and str2 and compare them */
1333 while (*one && *two) {
1334 while (*one && !isalnum((guchar)*one)) one++;
1335 while (*two && !isalnum((guchar)*two)) two++;
1340 /* grab first completely alpha or completely numeric segment */
1341 /* leave one and two pointing to the start of the alpha or numeric */
1342 /* segment and walk str1 and str2 to end of segment */
1343 if (isdigit((guchar)*str1)) {
1344 while (*str1 && isdigit((guchar)*str1)) str1++;
1345 while (*str2 && isdigit((guchar)*str2)) str2++;
1348 while (*str1 && isalpha((guchar)*str1)) str1++;
1349 while (*str2 && isalpha((guchar)*str2)) str2++;
1353 /* save character at the end of the alpha or numeric segment */
1354 /* so that they can be restored after the comparison */
1360 /* take care of the case where the two version segments are */
1361 /* different types: one numeric and one alpha */
1362 if (one == str1) return -1; /* arbitrary */
1363 if (two == str2) return -1;
1366 /* this used to be done by converting the digit segments */
1367 /* to ints using atoi() - it's changed because long */
1368 /* digit segments can overflow an int - this should fix that. */
1370 /* throw away any leading zeros - it's a number, right? */
1371 while (*one == '0') one++;
1372 while (*two == '0') two++;
1374 /* whichever number has more digits wins */
1375 if (strlen(one) > strlen(two)) return 1;
1376 if (strlen(two) > strlen(one)) return -1;
1379 /* strcmp will return which one is greater - even if the two */
1380 /* segments are alpha or if they are numeric. don't return */
1381 /* if they are equal because there might be more segments to */
1383 rc = strcmp(one, two);
1386 /* restore character that was replaced by null above */
1393 /* this catches the case where all numeric and alpha segments have */
1394 /* compared identically but the segment sepparating characters were */
1396 if ((!*one) && (!*two)) return 0;
1398 /* whichever version still has characters left over wins */
1399 if (!*one) return -1; else return 1;
1403 compare_versions (const char * a, const char *b)
1405 return rpmvercmp (a, b);
1409 version_test (ComparisonType comparison,
1416 return compare_versions (a, b) < 0;
1420 return compare_versions (a, b) > 0;
1423 case LESS_THAN_EQUAL:
1424 return compare_versions (a, b) <= 0;
1427 case GREATER_THAN_EQUAL:
1428 return compare_versions (a, b) >= 0;
1432 return compare_versions (a, b) == 0;
1436 return compare_versions (a, b) != 0;
1444 g_assert_not_reached ();
1452 comparison_to_str (ComparisonType comparison)
1464 case LESS_THAN_EQUAL:
1468 case GREATER_THAN_EQUAL:
1485 g_assert_not_reached ();
1493 max_len_foreach (gpointer key, gpointer value, gpointer data)
1497 *mlen = MAX (*mlen, strlen (key));
1501 packages_foreach (gpointer key, gpointer value, gpointer data)
1503 Package *pkg = get_package (key);
1509 pad = g_strnfill (GPOINTER_TO_INT (data) - strlen (pkg->key), ' ');
1511 printf ("%s%s%s - %s\n",
1512 pkg->key, pad, pkg->name, pkg->description);
1519 print_package_list (void)
1523 ignore_requires = TRUE;
1524 ignore_requires_private = TRUE;
1526 g_hash_table_foreach (locations, max_len_foreach, &mlen);
1527 g_hash_table_foreach (locations, packages_foreach, GINT_TO_POINTER (mlen + 1));
1531 enable_private_libs(void)
1533 ignore_private_libs = FALSE;
1537 disable_private_libs(void)
1539 ignore_private_libs = TRUE;
1543 enable_requires(void)
1545 ignore_requires = FALSE;
1549 disable_requires(void)
1551 ignore_requires = TRUE;
1555 enable_requires_private(void)
1557 ignore_requires_private = FALSE;
1561 disable_requires_private(void)
1563 ignore_requires_private = TRUE;