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

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