Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
     5         kx /* 
     5         kx  * Copyright (C) 2006-2011 Tollef Fog Heen <tfheen@err.no>
     5         kx  * Copyright (C) 2001, 2002, 2005-2006 Red Hat Inc.
     5         kx  * Copyright (C) 2010 Dan Nicholson <dbn.lists@gmail.com>
     5         kx  * 
     5         kx  * This program is free software; you can redistribute it and/or
     5         kx  * modify it under the terms of the GNU General Public License as
     5         kx  * published by the Free Software Foundation; either version 2 of the
     5         kx  * License, or (at your option) any later version.
     5         kx  *
     5         kx  * This program is distributed in the hope that it will be useful, but
     5         kx  * WITHOUT ANY WARRANTY; without even the implied warranty of
     5         kx  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     5         kx  * General Public License for more details.
     5         kx  * 
     5         kx  * You should have received a copy of the GNU General Public License
     5         kx  * along with this program; if not, write to the Free Software
     5         kx  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
     5         kx  * 02111-1307, USA.
     5         kx  */
     5         kx 
     5         kx #ifdef HAVE_CONFIG_H
     5         kx #include "config.h"
     5         kx #endif
     5         kx 
     5         kx #include "parse.h"
     5         kx #include <stdio.h>
     5         kx #include <errno.h>
     5         kx #include <string.h>
     5         kx #include <stdlib.h>
     5         kx #include <ctype.h>
     5         kx #ifdef HAVE_SYS_WAIT_H
     5         kx #include <sys/wait.h>
     5         kx #endif
     5         kx #include <sys/types.h>
     5         kx 
     5         kx gboolean parse_strict = TRUE;
     5         kx gboolean define_prefix = ENABLE_DEFINE_PREFIX;
     5         kx char *prefix_variable = "prefix";
     5         kx 
     5         kx #ifdef G_OS_WIN32
     5         kx gboolean msvc_syntax = FALSE;
     5         kx #endif
     5         kx 
     5         kx /**
     5         kx  * Read an entire line from a file into a buffer. Lines may
     5         kx  * be delimited with '\n', '\r', '\n\r', or '\r\n'. The delimiter
     5         kx  * is not written into the buffer. Text after a '#' character is treated as
     5         kx  * a comment and skipped. '\' can be used to escape a # character.
     5         kx  * '\' proceding a line delimiter combines adjacent lines. A '\' proceding
     5         kx  * any other character is ignored and written into the output buffer
     5         kx  * unmodified.
     5         kx  * 
     5         kx  * Return value: %FALSE if the stream was already at an EOF character.
     5         kx  **/
     5         kx static gboolean
     5         kx read_one_line (FILE *stream, GString *str)
     5         kx {
     5         kx   gboolean quoted = FALSE;
     5         kx   gboolean comment = FALSE;
     5         kx   int n_read = 0;
     5         kx 
     5         kx   g_string_truncate (str, 0);
     5         kx   
     5         kx   while (1)
     5         kx     {
     5         kx       int c;
     5         kx       
     5         kx       c = getc (stream);
     5         kx 
     5         kx       if (c == EOF)
     5         kx 	{
     5         kx 	  if (quoted)
     5         kx 	    g_string_append_c (str, '\\');
     5         kx 	  
     5         kx 	  goto done;
     5         kx 	}
     5         kx       else
     5         kx 	n_read++;
     5         kx 
     5         kx       if (quoted)
     5         kx 	{
     5         kx 	  quoted = FALSE;
     5         kx 	  
     5         kx 	  switch (c)
     5         kx 	    {
     5         kx 	    case '#':
     5         kx 	      g_string_append_c (str, '#');
     5         kx 	      break;
     5         kx 	    case '\r':
     5         kx 	    case '\n':
     5         kx 	      {
     5         kx 		int next_c = getc (stream);
     5         kx 
     5         kx 		if (!(c == EOF ||
     5         kx 		      (c == '\r' && next_c == '\n') ||
     5         kx 		      (c == '\n' && next_c == '\r')))
     5         kx 		  ungetc (next_c, stream);
     5         kx 		
     5         kx 		break;
     5         kx 	      }
     5         kx 	    default:
     5         kx 	      g_string_append_c (str, '\\');	      
     5         kx 	      g_string_append_c (str, c);
     5         kx 	    }
     5         kx 	}
     5         kx       else
     5         kx 	{
     5         kx 	  switch (c)
     5         kx 	    {
     5         kx 	    case '#':
     5         kx 	      comment = TRUE;
     5         kx 	      break;
     5         kx 	    case '\\':
     5         kx 	      if (!comment)
     5         kx 		quoted = TRUE;
     5         kx 	      break;
     5         kx 	    case '\n':
     5         kx 	      {
     5         kx 		int next_c = getc (stream);
     5         kx 
     5         kx 		if (!(c == EOF ||
     5         kx 		      (c == '\r' && next_c == '\n') ||
     5         kx 		      (c == '\n' && next_c == '\r')))
     5         kx 		  ungetc (next_c, stream);
     5         kx 
     5         kx 		goto done;
     5         kx 	      }
     5         kx 	    default:
     5         kx 	      if (!comment)
     5         kx 		g_string_append_c (str, c);
     5         kx 	    }
     5         kx 	}
     5         kx     }
     5         kx 
     5         kx  done:
     5         kx 
     5         kx   return n_read > 0;
     5         kx }
     5         kx 
     5         kx static char *
     5         kx trim_string (const char *str)
     5         kx {
     5         kx   int len;
     5         kx 
     5         kx   g_return_val_if_fail (str != NULL, NULL);
     5         kx   
     5         kx   while (*str && isspace ((guchar)*str))
     5         kx     str++;
     5         kx 
     5         kx   len = strlen (str);
     5         kx   while (len > 0 && isspace ((guchar)str[len-1]))
     5         kx     len--;
     5         kx 
     5         kx   return g_strndup (str, len);
     5         kx }
     5         kx 
     5         kx static char *
     5         kx trim_and_sub (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   char *trimmed;
     5         kx   GString *subst;
     5         kx   char *p;
     5         kx   
     5         kx   trimmed = trim_string (str);
     5         kx 
     5         kx   subst = g_string_new ("");
     5         kx 
     5         kx   p = trimmed;
     5         kx   while (*p)
     5         kx     {
     5         kx       if (p[0] == '$' &&
     5         kx           p[1] == '$')
     5         kx         {
     5         kx           /* escaped $ */
     5         kx           g_string_append_c (subst, '$');
     5         kx           p += 2;
     5         kx         }
     5         kx       else if (p[0] == '$' &&
     5         kx                p[1] == '{')
     5         kx         {
     5         kx           /* variable */
     5         kx           char *var_start;
     5         kx           char *varname;
     5         kx           char *varval;
     5         kx           
     5         kx           var_start = &p[2];
     5         kx 
     5         kx           /* Get up to close brace. */
     5         kx           while (*p && *p != '}')
     5         kx             ++p;
     5         kx 
     5         kx           varname = g_strndup (var_start, p - var_start);
     5         kx 
     5         kx           ++p; /* past brace */
     5         kx           
     5         kx           varval = package_get_var (pkg, varname);
     5         kx           
     5         kx           if (varval == NULL)
     5         kx             {
     5         kx               verbose_error ("Variable '%s' not defined in '%s'\n",
     5         kx                              varname, path);
     5         kx               if (parse_strict)
     5         kx                 exit (1);
     5         kx             }
     5         kx 
     5         kx           g_free (varname);
     5         kx 
     5         kx           g_string_append (subst, varval);
     5         kx           g_free (varval);
     5         kx         }
     5         kx       else
     5         kx         {
     5         kx           g_string_append_c (subst, *p);
     5         kx 
     5         kx           ++p;          
     5         kx         }
     5         kx     }
     5         kx 
     5         kx   g_free (trimmed);
     5         kx   p = subst->str;
     5         kx   g_string_free (subst, FALSE);
     5         kx 
     5         kx   return p;
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_name (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   if (pkg->name)
     5         kx     {
     5         kx       verbose_error ("Name field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx   
     5         kx   pkg->name = trim_and_sub (pkg, str, path);
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_version (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   if (pkg->version)
     5         kx     {
     5         kx       verbose_error ("Version field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx   
     5         kx   pkg->version = trim_and_sub (pkg, str, path);
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_description (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   if (pkg->description)
     5         kx     {
     5         kx       verbose_error ("Description field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx   
     5         kx   pkg->description = trim_and_sub (pkg, str, path);
     5         kx }
     5         kx 
     5         kx 
     5         kx #define MODULE_SEPARATOR(c) ((c) == ',' || isspace ((guchar)(c)))
     5         kx #define OPERATOR_CHAR(c) ((c) == '<' || (c) == '>' || (c) == '!' || (c) == '=')
     5         kx 
     5         kx /* A module list is a list of modules with optional version specification,
     5         kx  * separated by commas and/or spaces. Commas are treated just like whitespace,
     5         kx  * in order to allow stuff like: Requires: @FRIBIDI_PC@, glib, gmodule
     5         kx  * where @FRIBIDI_PC@ gets substituted to nothing or to 'fribidi'
     5         kx  */
     5         kx 
     5         kx typedef enum
     5         kx {
     5         kx   /* put numbers to help interpret lame debug spew ;-) */
     5         kx   OUTSIDE_MODULE = 0,
     5         kx   IN_MODULE_NAME = 1,
     5         kx   BEFORE_OPERATOR = 2,
     5         kx   IN_OPERATOR = 3,
     5         kx   AFTER_OPERATOR = 4,
     5         kx   IN_MODULE_VERSION = 5  
     5         kx } ModuleSplitState;
     5         kx 
     5         kx #define PARSE_SPEW 0
     5         kx 
     5         kx static GList *
     5         kx split_module_list (const char *str, const char *path)
     5         kx {
     5         kx   GList *retval = NULL;
     5         kx   const char *p;
     5         kx   const char *start;
     5         kx   ModuleSplitState state = OUTSIDE_MODULE;
     5         kx   ModuleSplitState last_state = OUTSIDE_MODULE;
     5         kx 
     5         kx   /*   fprintf (stderr, "Parsing: '%s'\n", str); */
     5         kx   
     5         kx   start = str;
     5         kx   p = str;
     5         kx 
     5         kx   while (*p)
     5         kx     {
     5         kx #if PARSE_SPEW
     5         kx       fprintf (stderr, "p: %c state: %d last_state: %d\n", *p, state, last_state);
     5         kx #endif
     5         kx       
     5         kx       switch (state)
     5         kx         {
     5         kx         case OUTSIDE_MODULE:
     5         kx           if (!MODULE_SEPARATOR (*p))
     5         kx             state = IN_MODULE_NAME;          
     5         kx           break;
     5         kx 
     5         kx         case IN_MODULE_NAME:
     5         kx           if (isspace ((guchar)*p))
     5         kx             {
     5         kx               /* Need to look ahead to determine next state */
     5         kx               const char *s = p;
     5         kx               while (*s && isspace ((guchar)*s))
     5         kx                 ++s;
     5         kx 
     5         kx               if (*s == '\0')
     5         kx                 state = OUTSIDE_MODULE;
     5         kx               else if (MODULE_SEPARATOR (*s))
     5         kx                 state = OUTSIDE_MODULE;
     5         kx               else if (OPERATOR_CHAR (*s))
     5         kx                 state = BEFORE_OPERATOR;
     5         kx               else
     5         kx                 state = OUTSIDE_MODULE;
     5         kx             }
     5         kx           else if (MODULE_SEPARATOR (*p))
     5         kx             state = OUTSIDE_MODULE; /* comma precludes any operators */
     5         kx           break;
     5         kx 
     5         kx         case BEFORE_OPERATOR:
     5         kx           /* We know an operator is coming up here due to lookahead from
     5         kx            * IN_MODULE_NAME
     5         kx            */
     5         kx           if (isspace ((guchar)*p))
     5         kx             ; /* no change */
     5         kx           else if (OPERATOR_CHAR (*p))
     5         kx             state = IN_OPERATOR;
     5         kx           else
     5         kx             g_assert_not_reached ();
     5         kx           break;
     5         kx 
     5         kx         case IN_OPERATOR:
     5         kx           if (!OPERATOR_CHAR (*p))
     5         kx             state = AFTER_OPERATOR;
     5         kx           break;
     5         kx 
     5         kx         case AFTER_OPERATOR:
     5         kx           if (!isspace ((guchar)*p))
     5         kx             state = IN_MODULE_VERSION;
     5         kx           break;
     5         kx 
     5         kx         case IN_MODULE_VERSION:
     5         kx           if (MODULE_SEPARATOR (*p))
     5         kx             state = OUTSIDE_MODULE;
     5         kx           break;
     5         kx           
     5         kx         default:
     5         kx           g_assert_not_reached ();
     5         kx         }
     5         kx 
     5         kx       if (state == OUTSIDE_MODULE &&
     5         kx           last_state != OUTSIDE_MODULE)
     5         kx         {
     5         kx           /* We left a module */
     5         kx           char *module = g_strndup (start, p - start);
     5         kx           retval = g_list_prepend (retval, module);
     5         kx 
     5         kx #if PARSE_SPEW
     5         kx           fprintf (stderr, "found module: '%s'\n", module);
     5         kx #endif
     5         kx           
     5         kx           /* reset start */
     5         kx           start = p;
     5         kx         }
     5         kx       
     5         kx       last_state = state;
     5         kx       ++p;
     5         kx     }
     5         kx 
     5         kx   if (p != start)
     5         kx     {
     5         kx       /* get the last module */
     5         kx       char *module = g_strndup (start, p - start);
     5         kx       retval = g_list_prepend (retval, module);
     5         kx 
     5         kx #if PARSE_SPEW
     5         kx       fprintf (stderr, "found module: '%s'\n", module);
     5         kx #endif
     5         kx       
     5         kx     }
     5         kx   
     5         kx   retval = g_list_reverse (retval);
     5         kx 
     5         kx   return retval;
     5         kx }
     5         kx 
     5         kx GList *
     5         kx parse_module_list (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   GList *split;
     5         kx   GList *iter;
     5         kx   GList *retval = NULL;
     5         kx 
     5         kx   split = split_module_list (str, path);
     5         kx 
     5         kx   for (iter = split; iter != NULL; iter = g_list_next (iter))
     5         kx     {
     5         kx       RequiredVersion *ver;
     5         kx       char *p;
     5         kx       char *start;
     5         kx       
     5         kx       p = iter->data;
     5         kx 
     5         kx       ver = g_new0 (RequiredVersion, 1);
     5         kx       ver->comparison = ALWAYS_MATCH;
     5         kx       ver->owner = pkg;
     5         kx       retval = g_list_prepend (retval, ver);
     5         kx       
     5         kx       while (*p && MODULE_SEPARATOR (*p))
     5         kx         ++p;
     5         kx       
     5         kx       start = p;
     5         kx 
     5         kx       while (*p && !isspace ((guchar)*p))
     5         kx         ++p;
     5         kx 
     5         kx       while (*p && MODULE_SEPARATOR (*p))
     5         kx         {
     5         kx           *p = '\0';
     5         kx           ++p;
     5         kx         }
     5         kx 
     5         kx       if (*start == '\0')
     5         kx         {
     5         kx           verbose_error ("Empty package name in Requires or Conflicts in file '%s'\n", path);
     5         kx           if (parse_strict)
     5         kx             exit (1);
     5         kx           else
     5         kx             continue;
     5         kx         }
     5         kx       
     5         kx       ver->name = g_strdup (start);
     5         kx 
     5         kx       start = p;
     5         kx 
     5         kx       while (*p && !isspace ((guchar)*p))
     5         kx         ++p;
     5         kx 
     5         kx       while (*p && isspace ((guchar)*p))
     5         kx         {
     5         kx           *p = '\0';
     5         kx           ++p;
     5         kx         }
     5         kx       
     5         kx       if (*start != '\0')
     5         kx         {
     5         kx           if (strcmp (start, "=") == 0)
     5         kx             ver->comparison = EQUAL;
     5         kx           else if (strcmp (start, ">=") == 0)
     5         kx             ver->comparison = GREATER_THAN_EQUAL;
     5         kx           else if (strcmp (start, "<=") == 0)
     5         kx             ver->comparison = LESS_THAN_EQUAL;
     5         kx           else if (strcmp (start, ">") == 0)
     5         kx             ver->comparison = GREATER_THAN;
     5         kx           else if (strcmp (start, "<") == 0)
     5         kx             ver->comparison = LESS_THAN;
     5         kx           else if (strcmp (start, "!=") == 0)
     5         kx             ver->comparison = NOT_EQUAL;
     5         kx           else
     5         kx             {
     5         kx               verbose_error ("Unknown version comparison operator '%s' after "
     5         kx                              "package name '%s' in file '%s'\n", start,
     5         kx                              ver->name, path);
     5         kx               if (parse_strict)
     5         kx                 exit (1);
     5         kx               else
     5         kx                 continue;
     5         kx             }
     5         kx         }
     5         kx 
     5         kx       start = p;
     5         kx       
     5         kx       while (*p && !MODULE_SEPARATOR (*p))
     5         kx         ++p;
     5         kx 
     5         kx       while (*p && MODULE_SEPARATOR (*p))
     5         kx         {
     5         kx           *p = '\0';
     5         kx           ++p;
     5         kx         }
     5         kx       
     5         kx       if (ver->comparison != ALWAYS_MATCH && *start == '\0')
     5         kx         {
     5         kx           verbose_error ("Comparison operator but no version after package "
     5         kx                          "name '%s' in file '%s'\n", ver->name, path);
     5         kx           if (parse_strict)
     5         kx             exit (1);
     5         kx           else
     5         kx             {
     5         kx               ver->version = g_strdup ("0");
     5         kx               continue;
     5         kx             }
     5         kx         }
     5         kx 
     5         kx       if (*start != '\0')
     5         kx         {
     5         kx           ver->version = g_strdup (start);
     5         kx         }
     5         kx 
     5         kx       g_assert (ver->name);
     5         kx     }
     5         kx 
     5         kx   g_list_foreach (split, (GFunc) g_free, NULL);
     5         kx   g_list_free (split);
     5         kx 
     5         kx   retval = g_list_reverse (retval);
     5         kx 
     5         kx   return retval;
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_requires (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   char *trimmed;
     5         kx 
     5         kx   if (pkg->requires)
     5         kx     {
     5         kx       verbose_error ("Requires field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx 
     5         kx   trimmed = trim_and_sub (pkg, str, path);
     5         kx   pkg->requires_entries = parse_module_list (pkg, trimmed, path);
     5         kx   g_free (trimmed);
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_requires_private (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   char *trimmed;
     5         kx 
     5         kx   if (pkg->requires_private)
     5         kx     {
     5         kx       verbose_error ("Requires.private field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx 
     5         kx   trimmed = trim_and_sub (pkg, str, path);
     5         kx   pkg->requires_private_entries = parse_module_list (pkg, trimmed, path);
     5         kx   g_free (trimmed);
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_conflicts (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   char *trimmed;
     5         kx   
     5         kx   if (pkg->conflicts)
     5         kx     {
     5         kx       verbose_error ("Conflicts field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx 
     5         kx   trimmed = trim_and_sub (pkg, str, path);
     5         kx   pkg->conflicts = parse_module_list (pkg, trimmed, path);
     5         kx   g_free (trimmed);
     5         kx }
     5         kx 
     5         kx static char *strdup_escape_shell(const char *s)
     5         kx {
     5         kx 	size_t r_s = strlen(s)+10, c = 0;
     5         kx 	char *r = g_malloc(r_s);
     5         kx 	while (s[0]) {
     5         kx 		if ((s[0] < '$') ||
     5         kx 		    (s[0] > '$' && s[0] < '(') ||
     5         kx 		    (s[0] > ')' && s[0] < '+') ||
     5         kx 		    (s[0] > ':' && s[0] < '=') ||
     5         kx 		    (s[0] > '=' && s[0] < '@') ||
     5         kx 		    (s[0] > 'Z' && s[0] < '^') ||
     5         kx 		    (s[0] == '`') ||
     5         kx 		    (s[0] > 'z' && s[0] < '~') ||
     5         kx 		    (s[0] > '~')) {
     5         kx 			r[c] = '\\';
     5         kx 			c++;
     5         kx 		}
     5         kx 		r[c] = *s;
     5         kx 		c++;
     5         kx 		if (c+2 >= r_s) {
     5         kx 			r_s *= 2;
     5         kx 			r = g_realloc(r, r_s);
     5         kx 		}
     5         kx 		s++;
     5         kx 	}
     5         kx 	r[c] = 0;
     5         kx 	return r;
     5         kx }
     5         kx 
     5         kx static void _do_parse_libs (Package *pkg, int argc, char **argv)
     5         kx {
     5         kx   int i;
     5         kx #ifdef G_OS_WIN32
     5         kx   char *L_flag = (msvc_syntax ? "/libpath:" : "-L");
     5         kx   char *l_flag = (msvc_syntax ? "" : "-l");
     5         kx   char *lib_suffix = (msvc_syntax ? ".lib" : "");
     5         kx #else
     5         kx   char *L_flag = "-L";
     5         kx   char *l_flag = "-l";
     5         kx   char *lib_suffix = "";
     5         kx #endif
     5         kx 
     5         kx   i = 0;
     5         kx   while (i < argc)
     5         kx     {
     5         kx       Flag *flag = g_new (Flag, 1);
     5         kx       char *tmp = trim_string (argv[i]);
     5         kx       char *arg = strdup_escape_shell(tmp);
     5         kx       char *p;
     5         kx       p = arg;
     5         kx       g_free(tmp);
     5         kx 
     5         kx       if (p[0] == '-' &&
     5         kx           p[1] == 'l' &&
     5         kx 	  /* -lib: is used by the C# compiler for libs; it's not an -l
     5         kx               flag. */
     5         kx 	  (strncmp(p, "-lib:", 5) != 0))
     5         kx         {
     5         kx           p += 2;
     5         kx           while (*p && isspace ((guchar)*p))
     5         kx             ++p;
     5         kx 
     5         kx           flag->type = LIBS_l;
     5         kx           flag->arg = g_strconcat (l_flag, p, lib_suffix, NULL);
     5         kx           pkg->libs = g_list_prepend (pkg->libs, flag);
     5         kx         }
     5         kx       else if (p[0] == '-' &&
     5         kx                p[1] == 'L')
     5         kx         {
     5         kx           p += 2;
     5         kx           while (*p && isspace ((guchar)*p))
     5         kx             ++p;
     5         kx 
     5         kx           flag->type = LIBS_L;
     5         kx           flag->arg = g_strconcat (L_flag, p, NULL);
     5         kx           pkg->libs = g_list_prepend (pkg->libs, flag);
     5         kx 	}
     5         kx       else if ((strcmp("-framework", p) == 0 ||
     5         kx                 strcmp("-Wl,-framework", p) == 0) &&
     5         kx                i+1 < argc)
     5         kx         {
     5         kx           /* Mac OS X has a -framework Foo which is really one option,
     5         kx            * so we join those to avoid having -framework Foo
     5         kx            * -framework Bar being changed into -framework Foo Bar
     5         kx            * later
     5         kx           */
     5         kx           gchar *framework, *tmp = trim_string (argv[i+1]);
     5         kx 
     5         kx           framework = strdup_escape_shell(tmp);
     5         kx           flag->type = LIBS_OTHER;
     5         kx           flag->arg = g_strconcat (arg, " ", framework, NULL);
     5         kx           pkg->libs = g_list_prepend (pkg->libs, flag);
     5         kx           i++;
     5         kx           g_free (framework);
     5         kx           g_free (tmp);
     5         kx         }
     5         kx       else if (*arg != '\0')
     5         kx         {
     5         kx           flag->type = LIBS_OTHER;
     5         kx           flag->arg = g_strdup (arg);
     5         kx           pkg->libs = g_list_prepend (pkg->libs, flag);
     5         kx         }
     5         kx       else
     5         kx         /* flag wasn't used */
     5         kx         g_free (flag);
     5         kx 
     5         kx       g_free (arg);
     5         kx 
     5         kx       ++i;
     5         kx     }
     5         kx 
     5         kx }
     5         kx 
     5         kx 
     5         kx static void
     5         kx parse_libs (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   /* Strip out -l and -L flags, put them in a separate list. */
     5         kx   
     5         kx   char *trimmed;
     5         kx   char **argv = NULL;
     5         kx   int argc = 0;
     5         kx   GError *error = NULL;
     5         kx   
     5         kx   if (pkg->libs_num > 0)
     5         kx     {
     5         kx       verbose_error ("Libs field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx   
     5         kx   trimmed = trim_and_sub (pkg, str, path);
     5         kx 
     5         kx   if (trimmed && *trimmed &&
     5         kx       !g_shell_parse_argv (trimmed, &argc, &argv, &error))
     5         kx     {
     5         kx       verbose_error ("Couldn't parse Libs field into an argument vector: %s\n",
     5         kx                      error ? error->message : "unknown");
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         {
     5         kx           g_free (trimmed);
     5         kx           return;
     5         kx         }
     5         kx     }
     5         kx 
     5         kx   _do_parse_libs(pkg, argc, argv);
     5         kx 
     5         kx   g_free (trimmed);
     5         kx   g_strfreev (argv);
     5         kx   pkg->libs_num++;
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_libs_private (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   /*
     5         kx     List of private libraries.  Private libraries are libraries which
     5         kx     are needed in the case of static linking or on platforms not
     5         kx     supporting inter-library dependencies.  They are not supposed to
     5         kx     be used for libraries which are exposed through the library in
     5         kx     question.  An example of an exposed library is GTK+ exposing Glib.
     5         kx     A common example of a private library is libm.
     5         kx     
     5         kx     Generally, if include another library's headers in your own, it's
     5         kx     a public dependency and not a private one.
     5         kx   */
     5         kx   
     5         kx   char *trimmed;
     5         kx   char **argv = NULL;
     5         kx   int argc = 0;
     5         kx   GError *error = NULL;
     5         kx   
     5         kx   if (pkg->libs_private_num > 0)
     5         kx     {
     5         kx       verbose_error ("Libs.private field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx   
     5         kx   trimmed = trim_and_sub (pkg, str, path);
     5         kx 
     5         kx   if (trimmed && *trimmed &&
     5         kx       !g_shell_parse_argv (trimmed, &argc, &argv, &error))
     5         kx     {
     5         kx       verbose_error ("Couldn't parse Libs.private field into an argument vector: %s\n",
     5         kx                      error ? error->message : "unknown");
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         {
     5         kx           g_free (trimmed);
     5         kx           return;
     5         kx         }
     5         kx     }
     5         kx 
     5         kx   _do_parse_libs(pkg, argc, argv);
     5         kx 
     5         kx   g_strfreev (argv);
     5         kx   g_free (trimmed);
     5         kx 
     5         kx   pkg->libs_private_num++;
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_cflags (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   /* Strip out -I flags, put them in a separate list. */
     5         kx   
     5         kx   char *trimmed;
     5         kx   char **argv = NULL;
     5         kx   int argc = 0;
     5         kx   GError *error = NULL;
     5         kx   int i;
     5         kx   
     5         kx   if (pkg->cflags)
     5         kx     {
     5         kx       verbose_error ("Cflags field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx   
     5         kx   trimmed = trim_and_sub (pkg, str, path);
     5         kx 
     5         kx   if (trimmed && *trimmed &&
     5         kx       !g_shell_parse_argv (trimmed, &argc, &argv, &error))
     5         kx     {
     5         kx       verbose_error ("Couldn't parse Cflags field into an argument vector: %s\n",
     5         kx                      error ? error->message : "unknown");
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         {
     5         kx           g_free (trimmed);
     5         kx           return;
     5         kx         }
     5         kx     }
     5         kx 
     5         kx   i = 0;
     5         kx   while (i < argc)
     5         kx     {
     5         kx       Flag *flag = g_new (Flag, 1);
     5         kx       char *tmp = trim_string (argv[i]);
     5         kx       char *arg = strdup_escape_shell(tmp);
     5         kx       char *p = arg;
     5         kx       g_free(tmp);
     5         kx 
     5         kx       if (p[0] == '-' &&
     5         kx           p[1] == 'I')
     5         kx         {
     5         kx           p += 2;
     5         kx           while (*p && isspace ((guchar)*p))
     5         kx             ++p;
     5         kx 
     5         kx           flag->type = CFLAGS_I;
     5         kx           flag->arg = g_strconcat ("-I", p, NULL);
     5         kx           pkg->cflags = g_list_prepend (pkg->cflags, flag);
     5         kx         }
     5         kx       else if ((strcmp ("-idirafter", arg) == 0 ||
     5         kx                 strcmp ("-isystem", arg) == 0) &&
     5         kx                i+1 < argc)
     5         kx         {
     5         kx           char *option, *tmp;
     5         kx 
     5         kx           tmp = trim_string (argv[i+1]);
     5         kx           option = strdup_escape_shell (tmp);
     5         kx 
     5         kx           /* These are -I flags since they control the search path */
     5         kx           flag->type = CFLAGS_I;
     5         kx           flag->arg = g_strconcat (arg, " ", option, NULL);
     5         kx           pkg->cflags = g_list_prepend (pkg->cflags, flag);
     5         kx           i++;
     5         kx           g_free (option);
     5         kx           g_free (tmp);
     5         kx         }
     5         kx       else if (*arg != '\0')
     5         kx         {
     5         kx           flag->type = CFLAGS_OTHER;
     5         kx           flag->arg = g_strdup (arg);
     5         kx           pkg->cflags = g_list_prepend (pkg->cflags, flag);
     5         kx         }
     5         kx       else
     5         kx         /* flag wasn't used */
     5         kx         g_free (flag);
     5         kx 
     5         kx       g_free (arg);
     5         kx       
     5         kx       ++i;
     5         kx     }
     5         kx 
     5         kx   g_strfreev (argv);
     5         kx   g_free (trimmed);
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_url (Package *pkg, const char *str, const char *path)
     5         kx {
     5         kx   if (pkg->url != NULL)
     5         kx     {
     5         kx       verbose_error ("URL field occurs twice in '%s'\n", path);
     5         kx       if (parse_strict)
     5         kx         exit (1);
     5         kx       else
     5         kx         return;
     5         kx     }
     5         kx 
     5         kx   pkg->url = trim_and_sub (pkg, str, path);
     5         kx }
     5         kx 
     5         kx static void
     5         kx parse_line (Package *pkg, const char *untrimmed, const char *path,
     5         kx 	    gboolean ignore_requires, gboolean ignore_private_libs,
     5         kx 	    gboolean ignore_requires_private)
     5         kx {
     5         kx   char *str;
     5         kx   char *p;
     5         kx   char *tag;
     5         kx 
     5         kx   debug_spew ("  line>%s\n", untrimmed);
     5         kx   
     5         kx   str = trim_string (untrimmed);
     5         kx   
     5         kx   if (*str == '\0') /* empty line */
     5         kx     {
     5         kx       g_free(str);
     5         kx       return;
     5         kx     }
     5         kx   
     5         kx   p = str;
     5         kx 
     5         kx   /* Get first word */
     5         kx   while ((*p >= 'A' && *p <= 'Z') ||
     5         kx 	 (*p >= 'a' && *p <= 'z') ||
     5         kx 	 (*p >= '0' && *p <= '9') ||
     5         kx 	 *p == '_' || *p == '.')
     5         kx     p++;
     5         kx 
     5         kx   tag = g_strndup (str, p - str);
     5         kx   
     5         kx   while (*p && isspace ((guchar)*p))
     5         kx     ++p;
     5         kx 
     5         kx   if (*p == ':')
     5         kx     {
     5         kx       /* keyword */
     5         kx       ++p;
     5         kx       while (*p && isspace ((guchar)*p))
     5         kx         ++p;
     5         kx 
     5         kx       if (strcmp (tag, "Name") == 0)
     5         kx         parse_name (pkg, p, path);
     5         kx       else if (strcmp (tag, "Description") == 0)
     5         kx         parse_description (pkg, p, path);
     5         kx       else if (strcmp (tag, "Version") == 0)
     5         kx         parse_version (pkg, p, path);
     5         kx       else if (strcmp (tag, "Requires.private") == 0)
     5         kx 	{
     5         kx 	  if (!ignore_requires_private)
     5         kx 	    parse_requires_private (pkg, p, path);
     5         kx 	}
     5         kx       else if (strcmp (tag, "Requires") == 0)
     5         kx 	{
     5         kx           if (ignore_requires == FALSE)
     5         kx 	    parse_requires (pkg, p, path);
     5         kx           else
     5         kx 	    goto cleanup;
     5         kx         }
     5         kx       else if ((strcmp (tag, "Libs.private") == 0) && 
     5         kx                ignore_private_libs == FALSE)
     5         kx         parse_libs_private (pkg, p, path);
     5         kx       else if (strcmp (tag, "Libs") == 0)
     5         kx         parse_libs (pkg, p, path);
     5         kx       else if (strcmp (tag, "Cflags") == 0 ||
     5         kx                strcmp (tag, "CFlags") == 0)
     5         kx         parse_cflags (pkg, p, path);
     5         kx       else if (strcmp (tag, "Conflicts") == 0)
     5         kx         parse_conflicts (pkg, p, path);
     5         kx       else if (strcmp (tag, "URL") == 0)
     5         kx         parse_url (pkg, p, path);
     5         kx       else
     5         kx         {
     5         kx 	  /* we don't error out on unknown keywords because they may
     5         kx 	   * represent additions to the .pc file format from future
     5         kx 	   * versions of pkg-config.  We do make a note of them in the
     5         kx 	   * debug spew though, in order to help catch mistakes in .pc
     5         kx 	   * files. */
     5         kx           debug_spew ("Unknown keyword '%s' in '%s'\n",
     5         kx 		      tag, path);
     5         kx         }
     5         kx     }
     5         kx   else if (*p == '=')
     5         kx     {
     5         kx       /* variable */
     5         kx       char *varname;
     5         kx       char *varval;
     5         kx       
     5         kx       ++p;
     5         kx       while (*p && isspace ((guchar)*p))
     5         kx         ++p;
     5         kx 
     5         kx       if (define_prefix && strcmp (tag, prefix_variable) == 0)
     5         kx 	{
     5         kx 	  /* This is the prefix variable. Try to guesstimate a value for it
     5         kx 	   * for this package from the location of the .pc file.
     5         kx 	   */
     5         kx           gchar *base;
     5         kx           gboolean is_pkgconfigdir;
     5         kx 
     5         kx           base = g_path_get_basename (pkg->pcfiledir);
     5         kx           is_pkgconfigdir = g_ascii_strcasecmp (base, "pkgconfig") == 0;
     5         kx           g_free (base);
     5         kx           if (is_pkgconfigdir)
     5         kx             {
     5         kx               /* It ends in pkgconfig. Good. */
     5         kx               gchar *q;
     5         kx               gchar *prefix;
     5         kx 	      
     5         kx               /* Keep track of the original prefix value. */
     5         kx               pkg->orig_prefix = g_strdup (p);
     5         kx 
     5         kx               /* Get grandparent directory for new prefix. */
     5         kx               q = g_path_get_dirname (pkg->pcfiledir);
     5         kx               prefix = g_path_get_dirname (q);
     5         kx               g_free (q);
     5         kx 	      
     5         kx 	      /* Turn backslashes into slashes or
     5         kx 	       * g_shell_parse_argv() will eat them when ${prefix}
     5         kx 	       * has been expanded in parse_libs().
     5         kx 	       */
     5         kx 	      q = prefix;
     5         kx 	      while (*q)
     5         kx 		{
     5         kx 		  if (*q == '\\')
     5         kx 		    *q = '/';
     5         kx 		  q++;
     5         kx 		}
     5         kx 
     5         kx 	      /* Now escape the special characters so that there's no danger
     5         kx 	       * of arguments that include the prefix getting split.
     5         kx 	       */
     5         kx 	      q = prefix;
     5         kx 	      prefix = strdup_escape_shell (prefix);
     5         kx 	      g_free (q);
     5         kx 
     5         kx 	      varname = g_strdup (tag);
     5         kx 	      debug_spew (" Variable declaration, '%s' overridden with '%s'\n",
     5         kx 			  tag, prefix);
     5         kx 	      g_hash_table_insert (pkg->vars, varname, prefix);
     5         kx 	      goto cleanup;
     5         kx 	    }
     5         kx 	}
     5         kx       else if (define_prefix &&
     5         kx 	       pkg->orig_prefix != NULL &&
     5         kx 	       *(pkg->orig_prefix) != '\0' &&
     5         kx 	       strncmp (p, pkg->orig_prefix, strlen (pkg->orig_prefix)) == 0 &&
     5         kx 	       G_IS_DIR_SEPARATOR (p[strlen (pkg->orig_prefix)]))
     5         kx 	{
     5         kx 	  char *oldstr = str;
     5         kx 
     5         kx 	  p = str = g_strconcat (g_hash_table_lookup (pkg->vars, prefix_variable),
     5         kx 				 p + strlen (pkg->orig_prefix), NULL);
     5         kx 	  g_free (oldstr);
     5         kx 	}
     5         kx 
     5         kx       if (g_hash_table_lookup (pkg->vars, tag))
     5         kx         {
     5         kx           verbose_error ("Duplicate definition of variable '%s' in '%s'\n",
     5         kx                          tag, path);
     5         kx           if (parse_strict)
     5         kx             exit (1);
     5         kx           else
     5         kx             goto cleanup;
     5         kx         }
     5         kx 
     5         kx       varname = g_strdup (tag);
     5         kx       varval = trim_and_sub (pkg, p, path);     
     5         kx 
     5         kx       debug_spew (" Variable declaration, '%s' has value '%s'\n",
     5         kx                   varname, varval);
     5         kx       g_hash_table_insert (pkg->vars, varname, varval);
     5         kx   
     5         kx     }
     5         kx 
     5         kx  cleanup:  
     5         kx   g_free (str);
     5         kx   g_free (tag);
     5         kx }
     5         kx 
     5         kx Package*
     5         kx parse_package_file (const char *key, const char *path,
     5         kx                     gboolean ignore_requires,
     5         kx                     gboolean ignore_private_libs,
     5         kx                     gboolean ignore_requires_private)
     5         kx {
     5         kx   FILE *f;
     5         kx   Package *pkg;
     5         kx   GString *str;
     5         kx   gboolean one_line = FALSE;
     5         kx   
     5         kx   f = fopen (path, "r");
     5         kx 
     5         kx   if (f == NULL)
     5         kx     {
     5         kx       verbose_error ("Failed to open '%s': %s\n",
     5         kx                      path, strerror (errno));
     5         kx       
     5         kx       return NULL;
     5         kx     }
     5         kx 
     5         kx   debug_spew ("Parsing package file '%s'\n", path);
     5         kx   
     5         kx   pkg = g_new0 (Package, 1);
     5         kx   pkg->key = g_strdup (key);
     5         kx 
     5         kx   if (path)
     5         kx     {
     5         kx       pkg->pcfiledir = g_path_get_dirname (path);
     5         kx     }
     5         kx   else
     5         kx     {
     5         kx       debug_spew ("No pcfiledir determined for package\n");
     5         kx       pkg->pcfiledir = g_strdup ("???????");
     5         kx     }
     5         kx 
     5         kx   if (pkg->vars == NULL)
     5         kx     pkg->vars = g_hash_table_new (g_str_hash, g_str_equal);
     5         kx 
     5         kx   /* Variable storing directory of pc file */
     5         kx   g_hash_table_insert (pkg->vars, "pcfiledir", pkg->pcfiledir);
     5         kx 
     5         kx   str = g_string_new ("");
     5         kx 
     5         kx   while (read_one_line (f, str))
     5         kx     {
     5         kx       one_line = TRUE;
     5         kx       
     5         kx       parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs,
     5         kx 		  ignore_requires_private);
     5         kx 
     5         kx       g_string_truncate (str, 0);
     5         kx     }
     5         kx 
     5         kx   if (!one_line)
     5         kx     verbose_error ("Package file '%s' appears to be empty\n",
     5         kx                    path);
     5         kx   g_string_free (str, TRUE);
     5         kx   fclose(f);
     5         kx 
     5         kx   pkg->cflags = g_list_reverse (pkg->cflags);
     5         kx   pkg->libs = g_list_reverse (pkg->libs);
     5         kx   
     5         kx   return pkg;
     5         kx }
     5         kx 
     5         kx /* Parse a package variable. When the value appears to be quoted,
     5         kx  * unquote it so it can be more easily used in a shell. Otherwise,
     5         kx  * return the raw value.
     5         kx  */
     5         kx char *
     5         kx parse_package_variable (Package *pkg, const char *variable)
     5         kx {
     5         kx   char *value;
     5         kx   char *unquoted;
     5         kx   GError *error = NULL;
     5         kx 
     5         kx   value = package_get_var (pkg, variable);
     5         kx   if (!value)
     5         kx     return NULL;
     5         kx 
     5         kx   if (*value != '"' && *value != '\'')
     5         kx     /* Not quoted, return raw value */
     5         kx     return value;
     5         kx 
     5         kx   /* Maybe too naive, but assume a fully quoted variable */
     5         kx   unquoted = g_shell_unquote (value, &error);
     5         kx   if (unquoted)
     5         kx     {
     5         kx       g_free (value);
     5         kx       return unquoted;
     5         kx     }
     5         kx   else
     5         kx     {
     5         kx       /* Note the issue, but just return the raw value */
     5         kx       debug_spew ("Couldn't unquote value of \"%s\": %s\n",
     5         kx                   variable, error ? error->message : "unknown");
     5         kx       g_clear_error (&error);
     5         kx       return value;
     5         kx     }
     5         kx }