1 
2 /*
3 * Copyright (C) 2001, 2002 Red Hat Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 */
20 
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "pkg.h"
27 #include "parse.h"
28 
29 #ifdef HAVE_MALLOC_H
30 # include <malloc.h>
31 #endif
32 
33 #include <sys/types.h>
34 #include <dirent.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #include <stdlib.h>
42 #include <ctype.h>
43 
44 static void verify_package (Package *pkg);
45 
46 static GHashTable *packages = NULL;
47 static GHashTable *locations = NULL;
48 static GHashTable *path_positions = NULL;
49 static GHashTable *globals = NULL;
50 static GList *search_dirs = NULL;
51 static int scanned_dir_count = 0;
52 
53 gboolean disable_uninstalled = FALSE;
54 gboolean ignore_requires = FALSE;
55 gboolean ignore_requires_private = TRUE;
56 gboolean ignore_private_libs = TRUE;
57 
58 void
add_search_dir(const char * path)59 add_search_dir (const char *path)
60 {
61 search_dirs = g_list_append (search_dirs, g_strdup (path));
62 }
63 
64 void
add_search_dirs(const char * path,const char * separator)65 add_search_dirs (const char *path, const char *separator)
66 {
67 char **search_dirs;
68 char **iter;
69 
70 search_dirs = g_strsplit (path, separator, -1);
71 
72 iter = search_dirs;
73 while (*iter)
74 {
75 debug_spew ("Adding directory '%s' from PKG_CONFIG_PATH\n",
76 *iter);
77 add_search_dir (*iter);
78 
79 ++iter;
80 }
81 
82 g_strfreev (search_dirs);
83 }
84 
85 #ifdef G_OS_WIN32
86 /* Guard against .pc file being installed with UPPER CASE name */
87 # define FOLD(x) tolower(x)
88 # define FOLDCMP(a, b) g_ascii_strcasecmp (a, b)
89 #else
90 # define FOLD(x) (x)
91 # define FOLDCMP(a, b) strcmp (a, b)
92 #endif
93 
94 #define EXT_LEN 3
95 
96 static gboolean
ends_in_dotpc(const char * str)97 ends_in_dotpc (const char *str)
98 {
99 int len = strlen (str);
100 
101 if (len > EXT_LEN &&
102 str[len - 3] == '.' &&
103 FOLD (str[len - 2]) == 'p' &&
104 FOLD (str[len - 1]) == 'c')
105 return TRUE;
106 else
107 return FALSE;
108 }
109 
110 /* strlen ("-uninstalled") */
111 #define UNINSTALLED_LEN 12
112 
113 gboolean
name_ends_in_uninstalled(const char * str)114 name_ends_in_uninstalled (const char *str)
115 {
116 int len = strlen (str);
117 
118 if (len > UNINSTALLED_LEN &&
119 FOLDCMP ((str + len - UNINSTALLED_LEN), "-uninstalled") == 0)
120 return TRUE;
121 else
122 return FALSE;
123 }
124 
125 
126 /* Look for .pc files in the given directory and add them into
127 * locations, ignoring duplicates
128 */
129 static void
scan_dir(const char * dirname)130 scan_dir (const char *dirname)
131 {
132 DIR *dir;
133 struct dirent *dent;
134 int dirnamelen = strlen (dirname);
135 /* Use a copy of dirname cause Win32 opendir doesn't like
136 * superfluous trailing (back)slashes in the directory name.
137 */
138 char *dirname_copy = g_strdup (dirname);
139 
140 if (dirnamelen > 1 && dirname[dirnamelen-1] == G_DIR_SEPARATOR)
141 {
142 dirnamelen--;
143 dirname_copy[dirnamelen] = '\0';
144 }
145 #ifdef G_OS_WIN32
146 {
147 gchar *p;
148 /* Turn backslashes into slashes or
149 * g_shell_parse_argv() will eat them when ${prefix}
150 * has been expanded in parse_libs().
151 */
152 p = dirname;
153 while (*p)
154 {
155 if (*p == '\\')
156 *p = '/';
157 p++;
158 }
159 }
160 #endif
161 dir = opendir (dirname_copy);
162 g_free (dirname_copy);
163 if (!dir)
164 {
165 debug_spew ("Cannot open directory '%s' in package search path: %s\n",
166 dirname, g_strerror (errno));
167 return;
168 }
169 
170 debug_spew ("Scanning directory '%s'\n", dirname);
171 
172 scanned_dir_count += 1;
173 
174 while ((dent = readdir (dir)))
175 {
176 int len = strlen (dent->d_name);
177 
178 if (ends_in_dotpc (dent->d_name))
179 {
180 char *pkgname = g_malloc (len - 2);
181 
182 debug_spew ("File '%s' appears to be a .pc file\n", dent->d_name);
183 
184 strncpy (pkgname, dent->d_name, len - EXT_LEN);
185 pkgname[len-EXT_LEN] = '\0';
186 
187 if (g_hash_table_lookup (locations, pkgname))
188 {
189 debug_spew ("File '%s' ignored, we already know about package '%s'\n", dent->d_name, pkgname);
190 g_free (pkgname);
191 }
192 else
193 {
194 char *filename = g_malloc (dirnamelen + 1 + len + 1);
195 strncpy (filename, dirname, dirnamelen);
196 filename[dirnamelen] = G_DIR_SEPARATOR;
197 strcpy (filename + dirnamelen + 1, dent->d_name);
198 
199 if (g_file_test(filename, G_FILE_TEST_IS_REGULAR) == TRUE) {
200 g_hash_table_insert (locations, pkgname, filename);
201 g_hash_table_insert (path_positions, pkgname,
202 GINT_TO_POINTER (scanned_dir_count));
203 debug_spew ("Will find package '%s' in file '%s'\n",
204 pkgname, filename);
205 } else {
206 debug_spew ("Ignoring '%s' while looking for '%s'; not a "
207 "regular file.\n", pkgname, filename);
208 }
209 }
210 }
211 else
212 {
213 debug_spew ("Ignoring file '%s' in search directory; not a .pc file\n",
214 dent->d_name);
215 }
216 }
217 closedir(dir);
218 }
219 
220 static Package *
add_virtual_pkgconfig_package(void)221 add_virtual_pkgconfig_package (void)
222 {
223 Package *pkg = NULL;
224 
225 pkg = g_new0 (Package, 1);
226 
227 pkg->key = g_strdup ("pkg-config");
228 pkg->version = g_strdup (VERSION);
229 pkg->name = g_strdup ("pkg-config");
230 pkg->description = g_strdup ("pkg-config is a system for managing "
231 "compile/link flags for libraries");
232 pkg->url = g_strdup ("http://pkg-config.freedesktop.org/");
233 
234 if (pkg->vars == NULL)
235 pkg->vars = g_hash_table_new (g_str_hash, g_str_equal);
236 g_hash_table_insert (pkg->vars, "pc_path", pkg_config_pc_path);
237 
238 debug_spew ("Adding virtual 'pkg-config' package to list of known packages\n");
239 g_hash_table_insert (packages, pkg->key, pkg);
240 
241 return pkg;
242 }
243 
244 void
package_init()245 package_init ()
246 {
247 static gboolean initted = FALSE;
248 
249 if (!initted)
250 {
251 initted = TRUE;
252 
253 packages = g_hash_table_new (g_str_hash, g_str_equal);
254 locations = g_hash_table_new (g_str_hash, g_str_equal);
255 path_positions = g_hash_table_new (g_str_hash, g_str_equal);
256 
257 add_virtual_pkgconfig_package ();
258 
259 g_list_foreach (search_dirs, (GFunc)scan_dir, NULL);
260 }
261 }
262 
263 static Package *
internal_get_package(const char * name,gboolean warn)264 internal_get_package (const char *name, gboolean warn)
265 {
266 Package *pkg = NULL;
267 const char *location;
268 GList *iter;
269 
270 pkg = g_hash_table_lookup (packages, name);
271 
272 if (pkg)
273 return pkg;
274 
275 debug_spew ("Looking for package '%s'\n", name);
276 
277 /* treat "name" as a filename if it ends in .pc and exists */
278 if ( ends_in_dotpc (name) )
279 {
280 debug_spew ("Considering '%s' to be a filename rather than a package name\n", name);
281 location = name;
282 }
283 else
284 {
285 /* See if we should auto-prefer the uninstalled version */
286 if (!disable_uninstalled &&
287 !name_ends_in_uninstalled (name))
288 {
289 char *un;
290 
291 un = g_strconcat (name, "-uninstalled", NULL);
292 
293 pkg = internal_get_package (un, FALSE);
294 
295 g_free (un);
296 
297 if (pkg)
298 {
299 debug_spew ("Preferring uninstalled version of package '%s'\n", name);
300 return pkg;
301 }
302 }
303 
304 location = g_hash_table_lookup (locations, name);
305 }
306 
307 if (location == NULL)
308 {
309 if (warn)
310 verbose_error ("Package %s was not found in the pkg-config search path.\n"
311 "Perhaps you should add the directory containing `%s.pc'\n"
312 "to the PKG_CONFIG_PATH environment variable\n",
313 name, name);
314 
315 return NULL;
316 }
317 
318 debug_spew ("Reading '%s' from file '%s'\n", name, location);
319 pkg = parse_package_file (location, ignore_requires, ignore_private_libs,
320 ignore_requires_private);
321 
322 if (pkg == NULL)
323 {
324 debug_spew ("Failed to parse '%s'\n", location);
325 return NULL;
326 }
327 
328 if (strstr (location, "uninstalled.pc"))
329 pkg->uninstalled = TRUE;
330 
331 if (location != name)
332 pkg->key = g_strdup (name);
333 else
334 {
335 /* need to strip package name out of the filename */
336 int len = strlen (name);
337 const char *end = name + (len - EXT_LEN);
338 const char *start = end;
339 
340 while (start != name && *start != G_DIR_SEPARATOR)
341 --start;
342 
343 g_assert (end >= start);
344 
345 pkg->key = g_strndup (start, end - start);
346 }
347 
348 pkg->path_position =
349 GPOINTER_TO_INT (g_hash_table_lookup (path_positions, pkg->key));
350 
351 debug_spew ("Path position of '%s' is %d\n",
352 pkg->key, pkg->path_position);
353 
354 debug_spew ("Adding '%s' to list of known packages\n", pkg->key);
355 g_hash_table_insert (packages, pkg->key, pkg);
356 
357 /* pull in Requires packages */
358 for (iter = pkg->requires_entries; iter != NULL; iter = g_list_next (iter))
359 {
360 Package *req;
361 RequiredVersion *ver = iter->data;
362 
363 debug_spew ("Searching for '%s' requirement '%s'\n",
364 pkg->key, ver->name);
365 req = internal_get_package (ver->name, warn);
366 if (req == NULL)
367 {
368 verbose_error ("Package '%s', required by '%s', not found\n",
369 ver->name, pkg->key);
370 exit (1);
371 }
372 
373 if (pkg->required_versions == NULL)
374 pkg->required_versions = g_hash_table_new (g_str_hash, g_str_equal);
375 
376 g_hash_table_insert (pkg->required_versions, ver->name, ver);
377 pkg->requires = g_list_prepend (pkg->requires, req);
378 }
379 
380 /* pull in Requires.private packages */
381 for (iter = pkg->requires_private_entries; iter != NULL;
382 iter = g_list_next (iter))
383 {
384 Package *req;
385 RequiredVersion *ver = iter->data;
386 
387 debug_spew ("Searching for '%s' private requirement '%s'\n",
388 pkg->key, ver->name);
389 req = internal_get_package (ver->name, warn);
390 if (req == NULL)
391 {
392 verbose_error ("Package '%s', required by '%s', not found\n",
393 ver->name, pkg->key);
394 exit (1);
395 }
396 
397 if (pkg->required_versions == NULL)
398 pkg->required_versions = g_hash_table_new (g_str_hash, g_str_equal);
399 
400 g_hash_table_insert (pkg->required_versions, ver->name, ver);
401 pkg->requires_private = g_list_prepend (pkg->requires_private, req);
402 }
403 
404 /* make requires_private include a copy of the public requires too */
405 pkg->requires_private = g_list_concat (g_list_copy (pkg->requires),
406 pkg->requires_private);
407 
408 pkg->requires = g_list_reverse (pkg->requires);
409 pkg->requires_private = g_list_reverse (pkg->requires_private);
410 
411 verify_package (pkg);
412 
413 return pkg;
414 }
415 
416 Package *
get_package(const char * name)417 get_package (const char *name)
418 {
419 return internal_get_package (name, TRUE);
420 }
421 
422 Package *
get_package_quiet(const char * name)423 get_package_quiet (const char *name)
424 {
425 return internal_get_package (name, FALSE);
426 }
427 
428 /* Strip consecutive duplicate arguments in the flag list. */
429 static GList *
flag_list_strip_duplicates(GList * list)430 flag_list_strip_duplicates (GList *list)
431 {
432 GList *tmp;
433 
434 /* Start at the 2nd element of the list so we don't have to check for an
435 * existing previous element. */
436 for (tmp = g_list_next (list); tmp != NULL; tmp = g_list_next (tmp))
437 {
438 Flag *cur = tmp->data;
439 Flag *prev = tmp->prev->data;
440 
441 if (cur->type == prev->type && g_strcmp0 (cur->arg, prev->arg) == 0)
442 {
443 /* Remove the duplicate flag from the list and move to the last
444 * element to prepare for the next iteration. */
445 GList *dup = tmp;
446 
447 debug_spew (" removing duplicate \"%s\"\n", cur->arg);
448 tmp = g_list_previous (tmp);
449 list = g_list_remove_link (list, dup);
450 }
451 }
452 
453 return list;
454 }
455 
456 static char *
flag_list_to_string(GList * list)457 flag_list_to_string (GList *list)
458 {
459 GList *tmp;
460 GString *str = g_string_new ("");
461 char *retval;
462 
463 tmp = list;
464 while (tmp != NULL) {
465 Flag *flag = tmp->data;
466 char *tmpstr = flag->arg;
467 
468 if (pcsysrootdir != NULL && flag->type & (CFLAGS_I | LIBS_L)) {
469 g_string_append_c (str, '-');
470 g_string_append_c (str, tmpstr[1]);
471 g_string_append (str, pcsysrootdir);
472 g_string_append (str, tmpstr+2);
473 } else {
474 g_string_append (str, tmpstr);
475 }
476 g_string_append_c (str, ' ');
477 tmp = g_list_next (tmp);
478 }
479 
480 retval = str->str;
481 g_string_free (str, FALSE);
482 
483 return retval;
484 }
485 
486 static int
pathposcmp(gconstpointer a,gconstpointer b)487 pathposcmp (gconstpointer a, gconstpointer b)
488 {
489 const Package *pa = a;
490 const Package *pb = b;
491 
492 if (pa->path_position < pb->path_position)
493 return -1;
494 else if (pa->path_position > pb->path_position)
495 return 1;
496 else
497 return 0;
498 }
499 
500 static void
spew_package_list(const char * name,GList * list)501 spew_package_list (const char *name,
502 GList *list)
503 {
504 GList *tmp;
505 
506 debug_spew (" %s:", name);
507 
508 tmp = list;
509 while (tmp != NULL)
510 {
511 Package *pkg = tmp->data;
512 debug_spew (" %s", pkg->key);
513 tmp = tmp->next;
514 }
515 debug_spew ("\n");
516 }
517 
518 
519 static GList *
packages_sort_by_path_position(GList * list)520 packages_sort_by_path_position (GList *list)
521 {
522 return g_list_sort (list, pathposcmp);
523 }
524 
525 static void
recursive_fill_list(Package * pkg,gboolean include_private,GList ** listp)526 recursive_fill_list (Package *pkg, gboolean include_private, GList **listp)
527 {
528 GList *tmp;
529 
530 /*
531 * If the package is one of the parents, we can skip it. This allows
532 * circular requires loops to be broken.
533 */
534 if (pkg->in_requires_chain)
535 {
536 debug_spew ("Package %s already in requires chain, skipping\n",
537 pkg->key);
538 return;
539 }
540 
541 /* record this package in the dependency chain */
542 pkg->in_requires_chain = TRUE;
543 
544 /* Start from the end of the required package list to maintain order since
545 * the recursive list is built by prepending. */
546 tmp = include_private ? pkg->requires_private : pkg->requires;
547 for (tmp = g_list_last (tmp); tmp != NULL; tmp = g_list_previous (tmp))
548 recursive_fill_list (tmp->data, include_private, listp);
549 
550 *listp = g_list_prepend (*listp, pkg);
551 
552 /* remove this package from the dependency chain now that we've unwound */
553 pkg->in_requires_chain = FALSE;
554 }
555 
556 /* merge the flags from the individual packages */
557 static GList *
merge_flag_lists(GList * packages,FlagType type)558 merge_flag_lists (GList *packages, FlagType type)
559 {
560 GList *last = NULL;
561 GList *merged = NULL;
562 
563 /* keep track of the last element to avoid traversing the whole list */
564 for (; packages != NULL; packages = g_list_next (packages))
565 {
566 Package *pkg = packages->data;
567 GList *flags = (type & LIBS_ANY) ? pkg->libs : pkg->cflags;
568 
569 /* manually copy the elements so we can keep track of the end */
570 for (; flags != NULL; flags = g_list_next (flags))
571 {
572 Flag *flag = flags->data;
573 
574 if (flag->type & type)
575 {
576 if (last == NULL)
577 {
578 merged = g_list_prepend (NULL, flags->data);
579 last = merged;
580 }
581 else
582 last = g_list_next (g_list_append (last, flags->data));
583 }
584 }
585 }
586 
587 return merged;
588 }
589 
590 /* Work backwards from the end of the package list to remove duplicate
591 * packages. This could happen because the package was specified multiple
592 * times on the command line, or because multiple packages require the same
593 * package. When we have duplicate dependencies, starting from the end of the
594 * list ensures that the dependency shows up later in the package list and
595 * Libs will come out correctly. */
596 static GList *
package_list_strip_duplicates(GList * packages)597 package_list_strip_duplicates (GList *packages)
598 {
599 GList *cur;
600 GHashTable *requires;
601 
602 requires = g_hash_table_new (g_str_hash, g_str_equal);
603 for (cur = g_list_last (packages); cur != NULL; cur = g_list_previous (cur))
604 {
605 Package *pkg = cur->data;
606 
607 if (g_hash_table_lookup_extended (requires, pkg->key, NULL, NULL))
608 {
609 GList *dup = cur;
610 
611 /* Remove the duplicate package from the list */
612 debug_spew ("Removing duplicate package %s\n", pkg->key);
613 cur = cur->next;
614 packages = g_list_delete_link (packages, dup);
615 }
616 else
617 {
618 /* Unique package. Track it and move to the next. */
619 g_hash_table_replace (requires, pkg->key, pkg->key);
620 }
621 }
622 g_hash_table_destroy (requires);
623 
624 return packages;
625 }
626 
627 static GList *
fill_list(GList * packages,FlagType type,gboolean in_path_order,gboolean include_private)628 fill_list (GList *packages, FlagType type,
629 gboolean in_path_order, gboolean include_private)
630 {
631 GList *tmp;
632 GList *expanded = NULL;
633 GList *flags;
634 
635 /* Start from the end of the requested package list to maintain order since
636 * the recursive list is built by prepending. */
637 for (tmp = g_list_last (packages); tmp != NULL; tmp = g_list_previous (tmp))
638 recursive_fill_list (tmp->data, include_private, &expanded);
639 
640 /* Remove duplicate packages from the recursive list. This should provide a
641 * serialized package list where all interdependencies are resolved
642 * consistently. */
643 spew_package_list (" pre-remove", expanded);
644 expanded = package_list_strip_duplicates (expanded);
645 spew_package_list ("post-remove", expanded);
646 
647 if (in_path_order)
648 {
649 spew_package_list ("original", expanded);
650 expanded = packages_sort_by_path_position (expanded);
651 spew_package_list (" sorted", expanded);
652 }
653 
654 flags = merge_flag_lists (expanded, type);
655 g_list_free (expanded);
656 
657 return flags;
658 }
659 
660 static GList *
add_env_variable_to_list(GList * list,const gchar * env)661 add_env_variable_to_list (GList *list, const gchar *env)
662 {
663 gchar **values;
664 gint i;
665 
666 values = g_strsplit (env, G_SEARCHPATH_SEPARATOR_S, 0);
667 for (i = 0; values[i] != NULL; i++)
668 {
669 list = g_list_append (list, g_strdup (values[i]));
670 }
671 g_strfreev (values);
672 
673 return list;
674 }
675 
676 static void
verify_package(Package * pkg)677 verify_package (Package *pkg)
678 {
679 GList *requires = NULL;
680 GList *conflicts = NULL;
681 GList *system_directories = NULL;
682 GList *iter;
683 GList *requires_iter;
684 GList *conflicts_iter;
685 GList *system_dir_iter = NULL;
686 int count;
687 const gchar *search_path;
688 
689 /* Be sure we have the required fields */
690 
691 if (pkg->key == NULL)
692 {
693 fprintf (stderr,
694 "Internal pkg-config error, package with no key, please file a bug report\n");
695 exit (1);
696 }
697 
698 if (pkg->name == NULL)
699 {
700 verbose_error ("Package '%s' has no Name: field\n",
701 pkg->key);
702 exit (1);
703 }
704 
705 if (pkg->version == NULL)
706 {
707 verbose_error ("Package '%s' has no Version: field\n",
708 pkg->key);
709 exit (1);
710 }
711 
712 if (pkg->description == NULL)
713 {
714 verbose_error ("Package '%s' has no Description: field\n",
715 pkg->key);
716 exit (1);
717 }
718 
719 /* Make sure we have the right version for all requirements */
720 
721 iter = pkg->requires_private;
722 
723 while (iter != NULL)
724 {
725 Package *req = iter->data;
726 RequiredVersion *ver = NULL;
727 
728 if (pkg->required_versions)
729 ver = g_hash_table_lookup (pkg->required_versions,
730 req->key);
731 
732 if (ver)
733 {
734 if (!version_test (ver->comparison, req->version, ver->version))
735 {
736 verbose_error ("Package '%s' requires '%s %s %s' but version of %s is %s\n",
737 pkg->key, req->key,
738 comparison_to_str (ver->comparison),
739 ver->version,
740 req->key,
741 req->version);
742 if (req->url)
743 verbose_error ("You may find new versions of %s at %s\n",
744 req->name, req->url);
745 
746 exit (1);
747 }
748 }
749 
750 iter = g_list_next (iter);
751 }
752 
753 /* Make sure we didn't drag in any conflicts via Requires
754 * (inefficient algorithm, who cares)
755 */
756 recursive_fill_list (pkg, TRUE, &requires);
757 conflicts = pkg->conflicts;
758 
759 requires_iter = requires;
760 while (requires_iter != NULL)
761 {
762 Package *req = requires_iter->data;
763 
764 conflicts_iter = conflicts;
765 
766 while (conflicts_iter != NULL)
767 {
768 RequiredVersion *ver = conflicts_iter->data;
769 
770 if (strcmp (ver->name, req->key) == 0 &&
771 version_test (ver->comparison,
772 req->version,
773 ver->version))
774 {
775 verbose_error ("Version %s of %s creates a conflict.\n"
776 "(%s %s %s conflicts with %s %s)\n",
777 req->version, req->key,
778 ver->name,
779 comparison_to_str (ver->comparison),
780 ver->version ? ver->version : "(any)",
781 ver->owner->key,
782 ver->owner->version);
783 
784 exit (1);
785 }
786 
787 conflicts_iter = g_list_next (conflicts_iter);
788 }
789 
790 requires_iter = g_list_next (requires_iter);
791 }
792 
793 g_list_free (requires);
794 
795 /* We make a list of system directories that gcc expects so we can remove
796 * them.
797 */
798 
799 search_path = g_getenv ("PKG_CONFIG_SYSTEM_INCLUDE_PATH");
800 
801 if (search_path == NULL)
802 {
803 search_path = PKG_CONFIG_SYSTEM_INCLUDE_PATH;
804 }
805 
806 system_directories = add_env_variable_to_list (system_directories, search_path);
807 
808 search_path = g_getenv ("C_INCLUDE_PATH");
809 if (search_path != NULL)
810 {
811 system_directories = add_env_variable_to_list (system_directories, search_path);
812 }
813 
814 search_path = g_getenv ("CPLUS_INCLUDE_PATH");
815 if (search_path != NULL)
816 {
817 system_directories = add_env_variable_to_list (system_directories, search_path);
818 }
819 
820 count = 0;
821 for (iter = pkg->cflags; iter != NULL; iter = g_list_next (iter))
822 {
823 gint offset = 0;
824 Flag *flag = iter->data;
825 
826 if (!(flag->type & CFLAGS_I))
827 continue;
828 
829 /* we put things in canonical -I/usr/include (vs. -I /usr/include) format,
830 * but if someone changes it later we may as well be robust
831 */
832 if (((strncmp (flag->arg, "-I", 2) == 0) && (offset = 2))||
833 ((strncmp (flag->arg, "-I ", 3) == 0) && (offset = 3)))
834 {
835 if (offset == 0)
836 {
837 iter = iter->next;
838 continue;
839 }
840 
841 system_dir_iter = system_directories;
842 while (system_dir_iter != NULL)
843 {
844 if (strcmp (system_dir_iter->data,
845 ((char*)flag->arg) + offset) == 0)
846 {
847 debug_spew ("Package %s has %s in Cflags\n",
848 pkg->key, (gchar *)flag->arg);
849 if (g_getenv ("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS") == NULL)
850 {
851 debug_spew ("Removing %s from cflags for %s\n",
852 flag->arg, pkg->key);
853 ++count;
854 iter->data = NULL;
855 
856 break;
857 }
858 }
859 system_dir_iter = system_dir_iter->next;
860 }
861 }
862 }
863 
864 while (count)
865 {
866 pkg->cflags = g_list_remove (pkg->cflags, NULL);
867 --count;
868 }
869 
870 g_list_foreach (system_directories, (GFunc) g_free, NULL);
871 g_list_free (system_directories);
872 
873 system_directories = NULL;
874 
875 search_path = g_getenv ("PKG_CONFIG_SYSTEM_LIBRARY_PATH");
876 
877 if (search_path == NULL)
878 {
879 search_path = PKG_CONFIG_SYSTEM_LIBRARY_PATH;
880 }
881 
882 system_directories = add_env_variable_to_list (system_directories, search_path);
883 
884 count = 0;
885 for (iter = pkg->libs; iter != NULL; iter = g_list_next (iter))
886 {
887 GList *system_dir_iter = system_directories;
888 Flag *flag = iter->data;
889 
890 if (!(flag->type & LIBS_L))
891 continue;
892 
893 while (system_dir_iter != NULL)
894 {
895 gboolean is_system = FALSE;
896 const char *linker_arg = flag->arg;
897 const char *system_libpath = system_dir_iter->data;
898 
899 if (strncmp (linker_arg, "-L ", 3) == 0 &&
900 strcmp (linker_arg + 3, system_libpath) == 0)
901 is_system = TRUE;
902 else if (strncmp (linker_arg, "-L", 2) == 0 &&
903 strcmp (linker_arg + 2, system_libpath) == 0)
904 is_system = TRUE;
905 if (is_system)
906 {
907 debug_spew ("Package %s has -L %s in Libs\n",
908 pkg->key, system_libpath);
909 if (g_getenv ("PKG_CONFIG_ALLOW_SYSTEM_LIBS") == NULL)
910 {
911 iter->data = NULL;
912 ++count;
913 debug_spew ("Removing -L %s from libs for %s\n",
914 system_libpath, pkg->key);
915 break;
916 }
917 }
918 system_dir_iter = system_dir_iter->next;
919 }
920 }
921 g_list_free (system_directories);
922 
923 while (count)
924 {
925 pkg->libs = g_list_remove (pkg->libs, NULL);
926 --count;
927 }
928 }
929 
930 /* Create a merged list of required packages and retrieve the flags from them.
931 * Strip the duplicates from the flags list. The sorting and stripping can be
932 * done in one of two ways: packages sorted by position in the pkg-config path
933 * and stripping done from the beginning of the list, or packages sorted from
934 * most dependent to least dependent and stripping from the end of the list.
935 * The former is done for -I/-L flags, and the latter for all others.
936 */
937 static char *
get_multi_merged(GList * pkgs,FlagType type,gboolean in_path_order,gboolean include_private)938 get_multi_merged (GList *pkgs, FlagType type, gboolean in_path_order,
939 gboolean include_private)
940 {
941 GList *list;
942 char *retval;
943 
944 list = fill_list (pkgs, type, in_path_order, include_private);
945 list = flag_list_strip_duplicates (list);
946 retval = flag_list_to_string (list);
947 g_list_free (list);
948 
949 return retval;
950 }
951 
952 char *
packages_get_flags(GList * pkgs,FlagType flags)953 packages_get_flags (GList *pkgs, FlagType flags)
954 {
955 GString *str;
956 char *cur;
957 
958 str = g_string_new (NULL);
959 
960 /* sort packages in path order for -L/-I, dependency order otherwise */
961 if (flags & CFLAGS_OTHER)
962 {
963 cur = get_multi_merged (pkgs, CFLAGS_OTHER, FALSE, TRUE);
964 debug_spew ("adding CFLAGS_OTHER string \"%s\"\n", cur);
965 g_string_append (str, cur);
966 g_free (cur);
967 }
968 if (flags & CFLAGS_I)
969 {
970 cur = get_multi_merged (pkgs, CFLAGS_I, TRUE, TRUE);
971 debug_spew ("adding CFLAGS_I string \"%s\"\n", cur);
972 g_string_append (str, cur);
973 g_free (cur);
974 }
975 if (flags & LIBS_L)
976 {
977 cur = get_multi_merged (pkgs, LIBS_L, TRUE, !ignore_private_libs);
978 debug_spew ("adding LIBS_L string \"%s\"\n", cur);
979 g_string_append (str, cur);
980 g_free (cur);
981 }
982 if (flags & (LIBS_OTHER | LIBS_l))
983 {
984 cur = get_multi_merged (pkgs, flags & (LIBS_OTHER | LIBS_l), FALSE,
985 !ignore_private_libs);
986 debug_spew ("adding LIBS_OTHER | LIBS_l string \"%s\"\n", cur);
987 g_string_append (str, cur);
988 g_free (cur);
989 }
990 
991 debug_spew ("returning flags string \"%s\"\n", str->str);
992 return g_string_free (str, FALSE);
993 }
994 
995 void
define_global_variable(const char * varname,const char * varval)996 define_global_variable (const char *varname,
997 const char *varval)
998 {
999 if (globals == NULL)
1000 globals = g_hash_table_new (g_str_hash, g_str_equal);
1001 
1002 if (g_hash_table_lookup (globals, varname))
1003 {
1004 verbose_error ("Variable '%s' defined twice globally\n", varname);
1005 exit (1);
1006 }
1007 
1008 g_hash_table_insert (globals, g_strdup (varname), g_strdup (varval));
1009 
1010 debug_spew ("Global variable definition '%s' = '%s'\n",
1011 varname, varval);
1012 }
1013 
1014 char *
package_get_var(Package * pkg,const char * var)1015 package_get_var (Package *pkg,
1016 const char *var)
1017 {
1018 char *varval = NULL;
1019 
1020 if (globals)
1021 varval = g_strdup (g_hash_table_lookup (globals, var));
1022 
1023 if (varval == NULL && pkg->vars)
1024 varval = g_strdup (g_hash_table_lookup (pkg->vars, var));
1025 
1026 /* Magic "pcfiledir" variable */
1027 if (varval == NULL && pkg->pcfiledir && strcmp (var, "pcfiledir") == 0)
1028 varval = g_strdup (pkg->pcfiledir);
1029 
1030 return varval;
1031 }
1032 
1033 char *
packages_get_var(GList * pkgs,const char * varname)1034 packages_get_var (GList *pkgs,
1035 const char *varname)
1036 {
1037 GList *tmp;
1038 GString *str;
1039 char *retval;
1040 
1041 str = g_string_new ("");
1042 
1043 tmp = pkgs;
1044 while (tmp != NULL)
1045 {
1046 Package *pkg = tmp->data;
1047 char *var;
1048 
1049 var = package_get_var (pkg, varname);
1050 
1051 if (var)
1052 {
1053 g_string_append (str, var);
1054 g_string_append_c (str, ' ');
1055 g_free (var);
1056 }
1057 
1058 tmp = g_list_next (tmp);
1059 }
1060 
1061 /* chop last space */
1062 if (str->len > 0)
1063 str->str[str->len - 1] = '\0';
1064 retval = str->str;
1065 g_string_free (str, FALSE);
1066 
1067 return retval;
1068 }
1069 
1070 
1071 
1072 /* Stolen verbatim from rpm/lib/misc.c
1073 RPM is Copyright (c) 1998 by Red Hat Software, Inc.,
1074 and may be distributed under the terms of the GPL and LGPL.
1075 */
1076 /* compare alpha and numeric segments of two versions */
1077 /* return 1: a is newer than b */
1078 /* 0: a and b are the same version */
1079 /* -1: b is newer than a */
rpmvercmp(const char * a,const char * b)1080 static int rpmvercmp(const char * a, const char * b) {
1081 char oldch1, oldch2;
1082 char * str1, * str2;
1083 char * one, * two;
1084 int rc;
1085 int isnum;
1086 
1087 /* easy comparison to see if versions are identical */
1088 if (!strcmp(a, b)) return 0;
1089 
1090 str1 = g_alloca(strlen(a) + 1);
1091 str2 = g_alloca(strlen(b) + 1);
1092 
1093 strcpy(str1, a);
1094 strcpy(str2, b);
1095 
1096 one = str1;
1097 two = str2;
1098 
1099 /* loop through each version segment of str1 and str2 and compare them */
1100 while (*one && *two) {
1101 while (*one && !isalnum((guchar)*one)) one++;
1102 while (*two && !isalnum((guchar)*two)) two++;
1103 
1104 /* If we ran to the end of either, we are finished with the loop */
1105 if (!(*one && *two)) break;
1106 
1107 str1 = one;
1108 str2 = two;
1109 
1110 /* grab first completely alpha or completely numeric segment */
1111 /* leave one and two pointing to the start of the alpha or numeric */
1112 /* segment and walk str1 and str2 to end of segment */
1113 if (isdigit((guchar)*str1)) {
1114 while (*str1 && isdigit((guchar)*str1)) str1++;
1115 while (*str2 && isdigit((guchar)*str2)) str2++;
1116 isnum = 1;
1117 } else {
1118 while (*str1 && isalpha((guchar)*str1)) str1++;
1119 while (*str2 && isalpha((guchar)*str2)) str2++;
1120 isnum = 0;
1121 }
1122 
1123 /* save character at the end of the alpha or numeric segment */
1124 /* so that they can be restored after the comparison */
1125 oldch1 = *str1;
1126 *str1 = '\0';
1127 oldch2 = *str2;
1128 *str2 = '\0';
1129 
1130 /* take care of the case where the two version segments are */
1131 /* different types: one numeric and one alpha */
1132 if (one == str1) return -1; /* arbitrary */
1133 /* XXX See patch #60884 (and details) from bugzilla #50977. */
1134 if (two == str2) return (isnum ? 1 : -1);
1135 
1136 if (isnum) {
1137 /* this used to be done by converting the digit segments */
1138 /* to ints using atoi() - it's changed because long */
1139 /* digit segments can overflow an int - this should fix that. */
1140 
1141 /* throw away any leading zeros - it's a number, right? */
1142 while (*one == '0') one++;
1143 while (*two == '0') two++;
1144 
1145 /* whichever number has more digits wins */
1146 if (strlen(one) > strlen(two)) return 1;
1147 if (strlen(two) > strlen(one)) return -1;
1148 }
1149 
1150 /* strcmp will return which one is greater - even if the two */
1151 /* segments are alpha or if they are numeric. don't return */
1152 /* if they are equal because there might be more segments to */
1153 /* compare */
1154 rc = strcmp(one, two);
1155 if (rc) return rc;
1156 
1157 /* restore character that was replaced by null above */
1158 *str1 = oldch1;
1159 one = str1;
1160 *str2 = oldch2;
1161 two = str2;
1162 }
1163 
1164 /* this catches the case where all numeric and alpha segments have */
1165 /* compared identically but the segment sepparating characters were */
1166 /* different */
1167 if ((!*one) && (!*two)) return 0;
1168 
1169 /* whichever version still has characters left over wins */
1170 if (!*one) return -1; else return 1;
1171 }
1172 
1173 int
compare_versions(const char * a,const char * b)1174 compare_versions (const char * a, const char *b)
1175 {
1176 return rpmvercmp (a, b);
1177 }
1178 
1179 gboolean
version_test(ComparisonType comparison,const char * a,const char * b)1180 version_test (ComparisonType comparison,
1181 const char *a,
1182 const char *b)
1183 {
1184 switch (comparison)
1185 {
1186 case LESS_THAN:
1187 return compare_versions (a, b) < 0;
1188 break;
1189 
1190 case GREATER_THAN:
1191 return compare_versions (a, b) > 0;
1192 break;
1193 
1194 case LESS_THAN_EQUAL:
1195 return compare_versions (a, b) <= 0;
1196 break;
1197 
1198 case GREATER_THAN_EQUAL:
1199 return compare_versions (a, b) >= 0;
1200 break;
1201 
1202 case EQUAL:
1203 return compare_versions (a, b) == 0;
1204 break;
1205 
1206 case NOT_EQUAL:
1207 return compare_versions (a, b) != 0;
1208 break;
1209 
1210 case ALWAYS_MATCH:
1211 return TRUE;
1212 break;
1213 
1214 default:
1215 g_assert_not_reached ();
1216 break;
1217 }
1218 
1219 return FALSE;
1220 }
1221 
1222 const char *
comparison_to_str(ComparisonType comparison)1223 comparison_to_str (ComparisonType comparison)
1224 {
1225 switch (comparison)
1226 {
1227 case LESS_THAN:
1228 return "<";
1229 break;
1230 
1231 case GREATER_THAN:
1232 return ">";
1233 break;
1234 
1235 case LESS_THAN_EQUAL:
1236 return "<=";
1237 break;
1238 
1239 case GREATER_THAN_EQUAL:
1240 return ">=";
1241 break;
1242 
1243 case EQUAL:
1244 return "=";
1245 break;
1246 
1247 case NOT_EQUAL:
1248 return "!=";
1249 break;
1250 
1251 case ALWAYS_MATCH:
1252 return "(any)";
1253 break;
1254 
1255 default:
1256 g_assert_not_reached ();
1257 break;
1258 }
1259 
1260 return "???";
1261 }
1262 
1263 static void
max_len_foreach(gpointer key,gpointer value,gpointer data)1264 max_len_foreach (gpointer key, gpointer value, gpointer data)
1265 {
1266 int *mlen = data;
1267 
1268 *mlen = MAX (*mlen, strlen (key));
1269 }
1270 
1271 static void
packages_foreach(gpointer key,gpointer value,gpointer data)1272 packages_foreach (gpointer key, gpointer value, gpointer data)
1273 {
1274 Package *pkg = get_package (key);
1275 
1276 if (pkg != NULL)
1277 {
1278 char *pad;
1279 
1280 pad = g_strnfill (GPOINTER_TO_INT (data) - strlen (pkg->key), ' ');
1281 
1282 printf ("%s%s%s - %s\n",
1283 pkg->key, pad, pkg->name, pkg->description);
1284 
1285 g_free (pad);
1286 }
1287 }
1288 
1289 void
print_package_list(void)1290 print_package_list (void)
1291 {
1292 int mlen = 0;
1293 
1294 ignore_requires = TRUE;
1295 ignore_requires_private = TRUE;
1296 
1297 g_hash_table_foreach (locations, max_len_foreach, &mlen);
1298 g_hash_table_foreach (locations, packages_foreach, GINT_TO_POINTER (mlen + 1));
1299 }
1300 
1301 void
enable_private_libs(void)1302 enable_private_libs(void)
1303 {
1304 ignore_private_libs = FALSE;
1305 }
1306 
1307 void
disable_private_libs(void)1308 disable_private_libs(void)
1309 {
1310 ignore_private_libs = TRUE;
1311 }
1312 
1313 void
enable_requires(void)1314 enable_requires(void)
1315 {
1316 ignore_requires = FALSE;
1317 }
1318 
1319 void
disable_requires(void)1320 disable_requires(void)
1321 {
1322 ignore_requires = TRUE;
1323 }
1324 
1325 void
enable_requires_private(void)1326 enable_requires_private(void)
1327 {
1328 ignore_requires_private = FALSE;
1329 }
1330 
1331 void
disable_requires_private(void)1332 disable_requires_private(void)
1333 {
1334 ignore_requires_private = TRUE;
1335 }