source: trunk/third/pkgconfig/pkg.c @ 18548

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