"Fossies" - the Fresh Open Source Software Archive

Member "pkg-config-0.29.2/parse.c" (20 Mar 2017, 28168 Bytes) of package /linux/misc/pkg-config-0.29.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "parse.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.29.1_vs_0.29.2.

    1 /* 
    2  * Copyright (C) 2006-2011 Tollef Fog Heen <tfheen@err.no>
    3  * Copyright (C) 2001, 2002, 2005-2006 Red Hat Inc.
    4  * Copyright (C) 2010 Dan Nicholson <dbn.lists@gmail.com>
    5  * 
    6  * This program is free software; you can redistribute it and/or
    7  * modify it under the terms of the GNU General Public License as
    8  * published by the Free Software Foundation; either version 2 of the
    9  * License, or (at your option) any later version.
   10  *
   11  * This program is distributed in the hope that it will be useful, but
   12  * WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14  * General Public License for more details.
   15  * 
   16  * You should have received a copy of the GNU General Public License
   17  * along with this program; if not, write to the Free Software
   18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   19  * 02111-1307, USA.
   20  */
   21 
   22 #ifdef HAVE_CONFIG_H
   23 #include "config.h"
   24 #endif
   25 
   26 #include "parse.h"
   27 #include <stdio.h>
   28 #include <errno.h>
   29 #include <string.h>
   30 #include <stdlib.h>
   31 #include <ctype.h>
   32 #ifdef HAVE_SYS_WAIT_H
   33 #include <sys/wait.h>
   34 #endif
   35 #include <sys/types.h>
   36 
   37 gboolean parse_strict = TRUE;
   38 gboolean define_prefix = ENABLE_DEFINE_PREFIX;
   39 char *prefix_variable = "prefix";
   40 
   41 #ifdef G_OS_WIN32
   42 gboolean msvc_syntax = FALSE;
   43 #endif
   44 
   45 /**
   46  * Read an entire line from a file into a buffer. Lines may
   47  * be delimited with '\n', '\r', '\n\r', or '\r\n'. The delimiter
   48  * is not written into the buffer. Text after a '#' character is treated as
   49  * a comment and skipped. '\' can be used to escape a # character.
   50  * '\' proceding a line delimiter combines adjacent lines. A '\' proceding
   51  * any other character is ignored and written into the output buffer
   52  * unmodified.
   53  * 
   54  * Return value: %FALSE if the stream was already at an EOF character.
   55  **/
   56 static gboolean
   57 read_one_line (FILE *stream, GString *str)
   58 {
   59   gboolean quoted = FALSE;
   60   gboolean comment = FALSE;
   61   int n_read = 0;
   62 
   63   g_string_truncate (str, 0);
   64   
   65   while (1)
   66     {
   67       int c;
   68       
   69       c = getc (stream);
   70 
   71       if (c == EOF)
   72     {
   73       if (quoted)
   74         g_string_append_c (str, '\\');
   75       
   76       goto done;
   77     }
   78       else
   79     n_read++;
   80 
   81       if (quoted)
   82     {
   83       quoted = FALSE;
   84       
   85       switch (c)
   86         {
   87         case '#':
   88           g_string_append_c (str, '#');
   89           break;
   90         case '\r':
   91         case '\n':
   92           {
   93         int next_c = getc (stream);
   94 
   95         if (!(c == EOF ||
   96               (c == '\r' && next_c == '\n') ||
   97               (c == '\n' && next_c == '\r')))
   98           ungetc (next_c, stream);
   99         
  100         break;
  101           }
  102         default:
  103           g_string_append_c (str, '\\');          
  104           g_string_append_c (str, c);
  105         }
  106     }
  107       else
  108     {
  109       switch (c)
  110         {
  111         case '#':
  112           comment = TRUE;
  113           break;
  114         case '\\':
  115           if (!comment)
  116         quoted = TRUE;
  117           break;
  118         case '\n':
  119           {
  120         int next_c = getc (stream);
  121 
  122         if (!(c == EOF ||
  123               (c == '\r' && next_c == '\n') ||
  124               (c == '\n' && next_c == '\r')))
  125           ungetc (next_c, stream);
  126 
  127         goto done;
  128           }
  129         default:
  130           if (!comment)
  131         g_string_append_c (str, c);
  132         }
  133     }
  134     }
  135 
  136  done:
  137 
  138   return n_read > 0;
  139 }
  140 
  141 static char *
  142 trim_string (const char *str)
  143 {
  144   int len;
  145 
  146   g_return_val_if_fail (str != NULL, NULL);
  147   
  148   while (*str && isspace ((guchar)*str))
  149     str++;
  150 
  151   len = strlen (str);
  152   while (len > 0 && isspace ((guchar)str[len-1]))
  153     len--;
  154 
  155   return g_strndup (str, len);
  156 }
  157 
  158 static char *
  159 trim_and_sub (Package *pkg, const char *str, const char *path)
  160 {
  161   char *trimmed;
  162   GString *subst;
  163   char *p;
  164   
  165   trimmed = trim_string (str);
  166 
  167   subst = g_string_new ("");
  168 
  169   p = trimmed;
  170   while (*p)
  171     {
  172       if (p[0] == '$' &&
  173           p[1] == '$')
  174         {
  175           /* escaped $ */
  176           g_string_append_c (subst, '$');
  177           p += 2;
  178         }
  179       else if (p[0] == '$' &&
  180                p[1] == '{')
  181         {
  182           /* variable */
  183           char *var_start;
  184           char *varname;
  185           char *varval;
  186           
  187           var_start = &p[2];
  188 
  189           /* Get up to close brace. */
  190           while (*p && *p != '}')
  191             ++p;
  192 
  193           varname = g_strndup (var_start, p - var_start);
  194 
  195           ++p; /* past brace */
  196           
  197           varval = package_get_var (pkg, varname);
  198           
  199           if (varval == NULL)
  200             {
  201               verbose_error ("Variable '%s' not defined in '%s'\n",
  202                              varname, path);
  203               if (parse_strict)
  204                 exit (1);
  205             }
  206 
  207           g_free (varname);
  208 
  209           g_string_append (subst, varval);
  210           g_free (varval);
  211         }
  212       else
  213         {
  214           g_string_append_c (subst, *p);
  215 
  216           ++p;          
  217         }
  218     }
  219 
  220   g_free (trimmed);
  221   p = subst->str;
  222   g_string_free (subst, FALSE);
  223 
  224   return p;
  225 }
  226 
  227 static void
  228 parse_name (Package *pkg, const char *str, const char *path)
  229 {
  230   if (pkg->name)
  231     {
  232       verbose_error ("Name field occurs twice in '%s'\n", path);
  233       if (parse_strict)
  234         exit (1);
  235       else
  236         return;
  237     }
  238   
  239   pkg->name = trim_and_sub (pkg, str, path);
  240 }
  241 
  242 static void
  243 parse_version (Package *pkg, const char *str, const char *path)
  244 {
  245   if (pkg->version)
  246     {
  247       verbose_error ("Version field occurs twice in '%s'\n", path);
  248       if (parse_strict)
  249         exit (1);
  250       else
  251         return;
  252     }
  253   
  254   pkg->version = trim_and_sub (pkg, str, path);
  255 }
  256 
  257 static void
  258 parse_description (Package *pkg, const char *str, const char *path)
  259 {
  260   if (pkg->description)
  261     {
  262       verbose_error ("Description field occurs twice in '%s'\n", path);
  263       if (parse_strict)
  264         exit (1);
  265       else
  266         return;
  267     }
  268   
  269   pkg->description = trim_and_sub (pkg, str, path);
  270 }
  271 
  272 
  273 #define MODULE_SEPARATOR(c) ((c) == ',' || isspace ((guchar)(c)))
  274 #define OPERATOR_CHAR(c) ((c) == '<' || (c) == '>' || (c) == '!' || (c) == '=')
  275 
  276 /* A module list is a list of modules with optional version specification,
  277  * separated by commas and/or spaces. Commas are treated just like whitespace,
  278  * in order to allow stuff like: Requires: @FRIBIDI_PC@, glib, gmodule
  279  * where @FRIBIDI_PC@ gets substituted to nothing or to 'fribidi'
  280  */
  281 
  282 typedef enum
  283 {
  284   /* put numbers to help interpret lame debug spew ;-) */
  285   OUTSIDE_MODULE = 0,
  286   IN_MODULE_NAME = 1,
  287   BEFORE_OPERATOR = 2,
  288   IN_OPERATOR = 3,
  289   AFTER_OPERATOR = 4,
  290   IN_MODULE_VERSION = 5  
  291 } ModuleSplitState;
  292 
  293 #define PARSE_SPEW 0
  294 
  295 static GList *
  296 split_module_list (const char *str, const char *path)
  297 {
  298   GList *retval = NULL;
  299   const char *p;
  300   const char *start;
  301   ModuleSplitState state = OUTSIDE_MODULE;
  302   ModuleSplitState last_state = OUTSIDE_MODULE;
  303 
  304   /*   fprintf (stderr, "Parsing: '%s'\n", str); */
  305   
  306   start = str;
  307   p = str;
  308 
  309   while (*p)
  310     {
  311 #if PARSE_SPEW
  312       fprintf (stderr, "p: %c state: %d last_state: %d\n", *p, state, last_state);
  313 #endif
  314       
  315       switch (state)
  316         {
  317         case OUTSIDE_MODULE:
  318           if (!MODULE_SEPARATOR (*p))
  319             state = IN_MODULE_NAME;          
  320           break;
  321 
  322         case IN_MODULE_NAME:
  323           if (isspace ((guchar)*p))
  324             {
  325               /* Need to look ahead to determine next state */
  326               const char *s = p;
  327               while (*s && isspace ((guchar)*s))
  328                 ++s;
  329 
  330               if (*s == '\0')
  331                 state = OUTSIDE_MODULE;
  332               else if (MODULE_SEPARATOR (*s))
  333                 state = OUTSIDE_MODULE;
  334               else if (OPERATOR_CHAR (*s))
  335                 state = BEFORE_OPERATOR;
  336               else
  337                 state = OUTSIDE_MODULE;
  338             }
  339           else if (MODULE_SEPARATOR (*p))
  340             state = OUTSIDE_MODULE; /* comma precludes any operators */
  341           break;
  342 
  343         case BEFORE_OPERATOR:
  344           /* We know an operator is coming up here due to lookahead from
  345            * IN_MODULE_NAME
  346            */
  347           if (isspace ((guchar)*p))
  348             ; /* no change */
  349           else if (OPERATOR_CHAR (*p))
  350             state = IN_OPERATOR;
  351           else
  352             g_assert_not_reached ();
  353           break;
  354 
  355         case IN_OPERATOR:
  356           if (!OPERATOR_CHAR (*p))
  357             state = AFTER_OPERATOR;
  358           break;
  359 
  360         case AFTER_OPERATOR:
  361           if (!isspace ((guchar)*p))
  362             state = IN_MODULE_VERSION;
  363           break;
  364 
  365         case IN_MODULE_VERSION:
  366           if (MODULE_SEPARATOR (*p))
  367             state = OUTSIDE_MODULE;
  368           break;
  369           
  370         default:
  371           g_assert_not_reached ();
  372         }
  373 
  374       if (state == OUTSIDE_MODULE &&
  375           last_state != OUTSIDE_MODULE)
  376         {
  377           /* We left a module */
  378           char *module = g_strndup (start, p - start);
  379           retval = g_list_prepend (retval, module);
  380 
  381 #if PARSE_SPEW
  382           fprintf (stderr, "found module: '%s'\n", module);
  383 #endif
  384           
  385           /* reset start */
  386           start = p;
  387         }
  388       
  389       last_state = state;
  390       ++p;
  391     }
  392 
  393   if (p != start)
  394     {
  395       /* get the last module */
  396       char *module = g_strndup (start, p - start);
  397       retval = g_list_prepend (retval, module);
  398 
  399 #if PARSE_SPEW
  400       fprintf (stderr, "found module: '%s'\n", module);
  401 #endif
  402       
  403     }
  404   
  405   retval = g_list_reverse (retval);
  406 
  407   return retval;
  408 }
  409 
  410 GList *
  411 parse_module_list (Package *pkg, const char *str, const char *path)
  412 {
  413   GList *split;
  414   GList *iter;
  415   GList *retval = NULL;
  416 
  417   split = split_module_list (str, path);
  418 
  419   for (iter = split; iter != NULL; iter = g_list_next (iter))
  420     {
  421       RequiredVersion *ver;
  422       char *p;
  423       char *start;
  424       
  425       p = iter->data;
  426 
  427       ver = g_new0 (RequiredVersion, 1);
  428       ver->comparison = ALWAYS_MATCH;
  429       ver->owner = pkg;
  430       retval = g_list_prepend (retval, ver);
  431       
  432       while (*p && MODULE_SEPARATOR (*p))
  433         ++p;
  434       
  435       start = p;
  436 
  437       while (*p && !isspace ((guchar)*p))
  438         ++p;
  439 
  440       while (*p && MODULE_SEPARATOR (*p))
  441         {
  442           *p = '\0';
  443           ++p;
  444         }
  445 
  446       if (*start == '\0')
  447         {
  448           verbose_error ("Empty package name in Requires or Conflicts in file '%s'\n", path);
  449           if (parse_strict)
  450             exit (1);
  451           else
  452             continue;
  453         }
  454       
  455       ver->name = g_strdup (start);
  456 
  457       start = p;
  458 
  459       while (*p && !isspace ((guchar)*p))
  460         ++p;
  461 
  462       while (*p && isspace ((guchar)*p))
  463         {
  464           *p = '\0';
  465           ++p;
  466         }
  467       
  468       if (*start != '\0')
  469         {
  470           if (strcmp (start, "=") == 0)
  471             ver->comparison = EQUAL;
  472           else if (strcmp (start, ">=") == 0)
  473             ver->comparison = GREATER_THAN_EQUAL;
  474           else if (strcmp (start, "<=") == 0)
  475             ver->comparison = LESS_THAN_EQUAL;
  476           else if (strcmp (start, ">") == 0)
  477             ver->comparison = GREATER_THAN;
  478           else if (strcmp (start, "<") == 0)
  479             ver->comparison = LESS_THAN;
  480           else if (strcmp (start, "!=") == 0)
  481             ver->comparison = NOT_EQUAL;
  482           else
  483             {
  484               verbose_error ("Unknown version comparison operator '%s' after "
  485                              "package name '%s' in file '%s'\n", start,
  486                              ver->name, path);
  487               if (parse_strict)
  488                 exit (1);
  489               else
  490                 continue;
  491             }
  492         }
  493 
  494       start = p;
  495       
  496       while (*p && !MODULE_SEPARATOR (*p))
  497         ++p;
  498 
  499       while (*p && MODULE_SEPARATOR (*p))
  500         {
  501           *p = '\0';
  502           ++p;
  503         }
  504       
  505       if (ver->comparison != ALWAYS_MATCH && *start == '\0')
  506         {
  507           verbose_error ("Comparison operator but no version after package "
  508                          "name '%s' in file '%s'\n", ver->name, path);
  509           if (parse_strict)
  510             exit (1);
  511           else
  512             {
  513               ver->version = g_strdup ("0");
  514               continue;
  515             }
  516         }
  517 
  518       if (*start != '\0')
  519         {
  520           ver->version = g_strdup (start);
  521         }
  522 
  523       g_assert (ver->name);
  524     }
  525 
  526   g_list_foreach (split, (GFunc) g_free, NULL);
  527   g_list_free (split);
  528 
  529   retval = g_list_reverse (retval);
  530 
  531   return retval;
  532 }
  533 
  534 static void
  535 parse_requires (Package *pkg, const char *str, const char *path)
  536 {
  537   char *trimmed;
  538 
  539   if (pkg->requires)
  540     {
  541       verbose_error ("Requires field occurs twice in '%s'\n", path);
  542       if (parse_strict)
  543         exit (1);
  544       else
  545         return;
  546     }
  547 
  548   trimmed = trim_and_sub (pkg, str, path);
  549   pkg->requires_entries = parse_module_list (pkg, trimmed, path);
  550   g_free (trimmed);
  551 }
  552 
  553 static void
  554 parse_requires_private (Package *pkg, const char *str, const char *path)
  555 {
  556   char *trimmed;
  557 
  558   if (pkg->requires_private)
  559     {
  560       verbose_error ("Requires.private field occurs twice in '%s'\n", path);
  561       if (parse_strict)
  562         exit (1);
  563       else
  564         return;
  565     }
  566 
  567   trimmed = trim_and_sub (pkg, str, path);
  568   pkg->requires_private_entries = parse_module_list (pkg, trimmed, path);
  569   g_free (trimmed);
  570 }
  571 
  572 static void
  573 parse_conflicts (Package *pkg, const char *str, const char *path)
  574 {
  575   char *trimmed;
  576   
  577   if (pkg->conflicts)
  578     {
  579       verbose_error ("Conflicts field occurs twice in '%s'\n", path);
  580       if (parse_strict)
  581         exit (1);
  582       else
  583         return;
  584     }
  585 
  586   trimmed = trim_and_sub (pkg, str, path);
  587   pkg->conflicts = parse_module_list (pkg, trimmed, path);
  588   g_free (trimmed);
  589 }
  590 
  591 static char *strdup_escape_shell(const char *s)
  592 {
  593     size_t r_s = strlen(s)+10, c = 0;
  594     char *r = g_malloc(r_s);
  595     while (s[0]) {
  596         if ((s[0] < '$') ||
  597             (s[0] > '$' && s[0] < '(') ||
  598             (s[0] > ')' && s[0] < '+') ||
  599             (s[0] > ':' && s[0] < '=') ||
  600             (s[0] > '=' && s[0] < '@') ||
  601             (s[0] > 'Z' && s[0] < '^') ||
  602             (s[0] == '`') ||
  603             (s[0] > 'z' && s[0] < '~') ||
  604             (s[0] > '~')) {
  605             r[c] = '\\';
  606             c++;
  607         }
  608         r[c] = *s;
  609         c++;
  610         if (c+2 >= r_s) {
  611             r_s *= 2;
  612             r = g_realloc(r, r_s);
  613         }
  614         s++;
  615     }
  616     r[c] = 0;
  617     return r;
  618 }
  619 
  620 static void _do_parse_libs (Package *pkg, int argc, char **argv)
  621 {
  622   int i;
  623 #ifdef G_OS_WIN32
  624   char *L_flag = (msvc_syntax ? "/libpath:" : "-L");
  625   char *l_flag = (msvc_syntax ? "" : "-l");
  626   char *lib_suffix = (msvc_syntax ? ".lib" : "");
  627 #else
  628   char *L_flag = "-L";
  629   char *l_flag = "-l";
  630   char *lib_suffix = "";
  631 #endif
  632 
  633   i = 0;
  634   while (i < argc)
  635     {
  636       Flag *flag = g_new (Flag, 1);
  637       char *tmp = trim_string (argv[i]);
  638       char *arg = strdup_escape_shell(tmp);
  639       char *p;
  640       p = arg;
  641       g_free(tmp);
  642 
  643       if (p[0] == '-' &&
  644           p[1] == 'l' &&
  645       /* -lib: is used by the C# compiler for libs; it's not an -l
  646               flag. */
  647       (strncmp(p, "-lib:", 5) != 0))
  648         {
  649           p += 2;
  650           while (*p && isspace ((guchar)*p))
  651             ++p;
  652 
  653           flag->type = LIBS_l;
  654           flag->arg = g_strconcat (l_flag, p, lib_suffix, NULL);
  655           pkg->libs = g_list_prepend (pkg->libs, flag);
  656         }
  657       else if (p[0] == '-' &&
  658                p[1] == 'L')
  659         {
  660           p += 2;
  661           while (*p && isspace ((guchar)*p))
  662             ++p;
  663 
  664           flag->type = LIBS_L;
  665           flag->arg = g_strconcat (L_flag, p, NULL);
  666           pkg->libs = g_list_prepend (pkg->libs, flag);
  667     }
  668       else if ((strcmp("-framework", p) == 0 ||
  669                 strcmp("-Wl,-framework", p) == 0) &&
  670                i+1 < argc)
  671         {
  672           /* Mac OS X has a -framework Foo which is really one option,
  673            * so we join those to avoid having -framework Foo
  674            * -framework Bar being changed into -framework Foo Bar
  675            * later
  676           */
  677           gchar *framework, *tmp = trim_string (argv[i+1]);
  678 
  679           framework = strdup_escape_shell(tmp);
  680           flag->type = LIBS_OTHER;
  681           flag->arg = g_strconcat (arg, " ", framework, NULL);
  682           pkg->libs = g_list_prepend (pkg->libs, flag);
  683           i++;
  684           g_free (framework);
  685           g_free (tmp);
  686         }
  687       else if (*arg != '\0')
  688         {
  689           flag->type = LIBS_OTHER;
  690           flag->arg = g_strdup (arg);
  691           pkg->libs = g_list_prepend (pkg->libs, flag);
  692         }
  693       else
  694         /* flag wasn't used */
  695         g_free (flag);
  696 
  697       g_free (arg);
  698 
  699       ++i;
  700     }
  701 
  702 }
  703 
  704 
  705 static void
  706 parse_libs (Package *pkg, const char *str, const char *path)
  707 {
  708   /* Strip out -l and -L flags, put them in a separate list. */
  709   
  710   char *trimmed;
  711   char **argv = NULL;
  712   int argc = 0;
  713   GError *error = NULL;
  714   
  715   if (pkg->libs_num > 0)
  716     {
  717       verbose_error ("Libs field occurs twice in '%s'\n", path);
  718       if (parse_strict)
  719         exit (1);
  720       else
  721         return;
  722     }
  723   
  724   trimmed = trim_and_sub (pkg, str, path);
  725 
  726   if (trimmed && *trimmed &&
  727       !g_shell_parse_argv (trimmed, &argc, &argv, &error))
  728     {
  729       verbose_error ("Couldn't parse Libs field into an argument vector: %s\n",
  730                      error ? error->message : "unknown");
  731       if (parse_strict)
  732         exit (1);
  733       else
  734         {
  735           g_free (trimmed);
  736           return;
  737         }
  738     }
  739 
  740   _do_parse_libs(pkg, argc, argv);
  741 
  742   g_free (trimmed);
  743   g_strfreev (argv);
  744   pkg->libs_num++;
  745 }
  746 
  747 static void
  748 parse_libs_private (Package *pkg, const char *str, const char *path)
  749 {
  750   /*
  751     List of private libraries.  Private libraries are libraries which
  752     are needed in the case of static linking or on platforms not
  753     supporting inter-library dependencies.  They are not supposed to
  754     be used for libraries which are exposed through the library in
  755     question.  An example of an exposed library is GTK+ exposing Glib.
  756     A common example of a private library is libm.
  757     
  758     Generally, if include another library's headers in your own, it's
  759     a public dependency and not a private one.
  760   */
  761   
  762   char *trimmed;
  763   char **argv = NULL;
  764   int argc = 0;
  765   GError *error = NULL;
  766   
  767   if (pkg->libs_private_num > 0)
  768     {
  769       verbose_error ("Libs.private field occurs twice in '%s'\n", path);
  770       if (parse_strict)
  771         exit (1);
  772       else
  773         return;
  774     }
  775   
  776   trimmed = trim_and_sub (pkg, str, path);
  777 
  778   if (trimmed && *trimmed &&
  779       !g_shell_parse_argv (trimmed, &argc, &argv, &error))
  780     {
  781       verbose_error ("Couldn't parse Libs.private field into an argument vector: %s\n",
  782                      error ? error->message : "unknown");
  783       if (parse_strict)
  784         exit (1);
  785       else
  786         {
  787           g_free (trimmed);
  788           return;
  789         }
  790     }
  791 
  792   _do_parse_libs(pkg, argc, argv);
  793 
  794   g_strfreev (argv);
  795   g_free (trimmed);
  796 
  797   pkg->libs_private_num++;
  798 }
  799 
  800 static void
  801 parse_cflags (Package *pkg, const char *str, const char *path)
  802 {
  803   /* Strip out -I flags, put them in a separate list. */
  804   
  805   char *trimmed;
  806   char **argv = NULL;
  807   int argc = 0;
  808   GError *error = NULL;
  809   int i;
  810   
  811   if (pkg->cflags)
  812     {
  813       verbose_error ("Cflags field occurs twice in '%s'\n", path);
  814       if (parse_strict)
  815         exit (1);
  816       else
  817         return;
  818     }
  819   
  820   trimmed = trim_and_sub (pkg, str, path);
  821 
  822   if (trimmed && *trimmed &&
  823       !g_shell_parse_argv (trimmed, &argc, &argv, &error))
  824     {
  825       verbose_error ("Couldn't parse Cflags field into an argument vector: %s\n",
  826                      error ? error->message : "unknown");
  827       if (parse_strict)
  828         exit (1);
  829       else
  830         {
  831           g_free (trimmed);
  832           return;
  833         }
  834     }
  835 
  836   i = 0;
  837   while (i < argc)
  838     {
  839       Flag *flag = g_new (Flag, 1);
  840       char *tmp = trim_string (argv[i]);
  841       char *arg = strdup_escape_shell(tmp);
  842       char *p = arg;
  843       g_free(tmp);
  844 
  845       if (p[0] == '-' &&
  846           p[1] == 'I')
  847         {
  848           p += 2;
  849           while (*p && isspace ((guchar)*p))
  850             ++p;
  851 
  852           flag->type = CFLAGS_I;
  853           flag->arg = g_strconcat ("-I", p, NULL);
  854           pkg->cflags = g_list_prepend (pkg->cflags, flag);
  855         }
  856       else if ((strcmp ("-idirafter", arg) == 0 ||
  857                 strcmp ("-isystem", arg) == 0) &&
  858                i+1 < argc)
  859         {
  860           char *option, *tmp;
  861 
  862           tmp = trim_string (argv[i+1]);
  863           option = strdup_escape_shell (tmp);
  864 
  865           /* These are -I flags since they control the search path */
  866           flag->type = CFLAGS_I;
  867           flag->arg = g_strconcat (arg, " ", option, NULL);
  868           pkg->cflags = g_list_prepend (pkg->cflags, flag);
  869           i++;
  870           g_free (option);
  871           g_free (tmp);
  872         }
  873       else if (*arg != '\0')
  874         {
  875           flag->type = CFLAGS_OTHER;
  876           flag->arg = g_strdup (arg);
  877           pkg->cflags = g_list_prepend (pkg->cflags, flag);
  878         }
  879       else
  880         /* flag wasn't used */
  881         g_free (flag);
  882 
  883       g_free (arg);
  884       
  885       ++i;
  886     }
  887 
  888   g_strfreev (argv);
  889   g_free (trimmed);
  890 }
  891 
  892 static void
  893 parse_url (Package *pkg, const char *str, const char *path)
  894 {
  895   if (pkg->url != NULL)
  896     {
  897       verbose_error ("URL field occurs twice in '%s'\n", path);
  898       if (parse_strict)
  899         exit (1);
  900       else
  901         return;
  902     }
  903 
  904   pkg->url = trim_and_sub (pkg, str, path);
  905 }
  906 
  907 static void
  908 parse_line (Package *pkg, const char *untrimmed, const char *path,
  909         gboolean ignore_requires, gboolean ignore_private_libs,
  910         gboolean ignore_requires_private)
  911 {
  912   char *str;
  913   char *p;
  914   char *tag;
  915 
  916   debug_spew ("  line>%s\n", untrimmed);
  917   
  918   str = trim_string (untrimmed);
  919   
  920   if (*str == '\0') /* empty line */
  921     {
  922       g_free(str);
  923       return;
  924     }
  925   
  926   p = str;
  927 
  928   /* Get first word */
  929   while ((*p >= 'A' && *p <= 'Z') ||
  930      (*p >= 'a' && *p <= 'z') ||
  931      (*p >= '0' && *p <= '9') ||
  932      *p == '_' || *p == '.')
  933     p++;
  934 
  935   tag = g_strndup (str, p - str);
  936   
  937   while (*p && isspace ((guchar)*p))
  938     ++p;
  939 
  940   if (*p == ':')
  941     {
  942       /* keyword */
  943       ++p;
  944       while (*p && isspace ((guchar)*p))
  945         ++p;
  946 
  947       if (strcmp (tag, "Name") == 0)
  948         parse_name (pkg, p, path);
  949       else if (strcmp (tag, "Description") == 0)
  950         parse_description (pkg, p, path);
  951       else if (strcmp (tag, "Version") == 0)
  952         parse_version (pkg, p, path);
  953       else if (strcmp (tag, "Requires.private") == 0)
  954     {
  955       if (!ignore_requires_private)
  956         parse_requires_private (pkg, p, path);
  957     }
  958       else if (strcmp (tag, "Requires") == 0)
  959     {
  960           if (ignore_requires == FALSE)
  961         parse_requires (pkg, p, path);
  962           else
  963         goto cleanup;
  964         }
  965       else if ((strcmp (tag, "Libs.private") == 0) && 
  966                ignore_private_libs == FALSE)
  967         parse_libs_private (pkg, p, path);
  968       else if (strcmp (tag, "Libs") == 0)
  969         parse_libs (pkg, p, path);
  970       else if (strcmp (tag, "Cflags") == 0 ||
  971                strcmp (tag, "CFlags") == 0)
  972         parse_cflags (pkg, p, path);
  973       else if (strcmp (tag, "Conflicts") == 0)
  974         parse_conflicts (pkg, p, path);
  975       else if (strcmp (tag, "URL") == 0)
  976         parse_url (pkg, p, path);
  977       else
  978         {
  979       /* we don't error out on unknown keywords because they may
  980        * represent additions to the .pc file format from future
  981        * versions of pkg-config.  We do make a note of them in the
  982        * debug spew though, in order to help catch mistakes in .pc
  983        * files. */
  984           debug_spew ("Unknown keyword '%s' in '%s'\n",
  985               tag, path);
  986         }
  987     }
  988   else if (*p == '=')
  989     {
  990       /* variable */
  991       char *varname;
  992       char *varval;
  993       
  994       ++p;
  995       while (*p && isspace ((guchar)*p))
  996         ++p;
  997 
  998       if (define_prefix && strcmp (tag, prefix_variable) == 0)
  999     {
 1000       /* This is the prefix variable. Try to guesstimate a value for it
 1001        * for this package from the location of the .pc file.
 1002        */
 1003           gchar *base;
 1004           gboolean is_pkgconfigdir;
 1005 
 1006           base = g_path_get_basename (pkg->pcfiledir);
 1007           is_pkgconfigdir = g_ascii_strcasecmp (base, "pkgconfig") == 0;
 1008           g_free (base);
 1009           if (is_pkgconfigdir)
 1010             {
 1011               /* It ends in pkgconfig. Good. */
 1012               gchar *q;
 1013               gchar *prefix;
 1014           
 1015               /* Keep track of the original prefix value. */
 1016               pkg->orig_prefix = g_strdup (p);
 1017 
 1018               /* Get grandparent directory for new prefix. */
 1019               q = g_path_get_dirname (pkg->pcfiledir);
 1020               prefix = g_path_get_dirname (q);
 1021               g_free (q);
 1022           
 1023           /* Turn backslashes into slashes or
 1024            * g_shell_parse_argv() will eat them when ${prefix}
 1025            * has been expanded in parse_libs().
 1026            */
 1027           q = prefix;
 1028           while (*q)
 1029         {
 1030           if (*q == '\\')
 1031             *q = '/';
 1032           q++;
 1033         }
 1034 
 1035           /* Now escape the special characters so that there's no danger
 1036            * of arguments that include the prefix getting split.
 1037            */
 1038           q = prefix;
 1039           prefix = strdup_escape_shell (prefix);
 1040           g_free (q);
 1041 
 1042           varname = g_strdup (tag);
 1043           debug_spew (" Variable declaration, '%s' overridden with '%s'\n",
 1044               tag, prefix);
 1045           g_hash_table_insert (pkg->vars, varname, prefix);
 1046           goto cleanup;
 1047         }
 1048     }
 1049       else if (define_prefix &&
 1050            pkg->orig_prefix != NULL &&
 1051            *(pkg->orig_prefix) != '\0' &&
 1052            strncmp (p, pkg->orig_prefix, strlen (pkg->orig_prefix)) == 0 &&
 1053            G_IS_DIR_SEPARATOR (p[strlen (pkg->orig_prefix)]))
 1054     {
 1055       char *oldstr = str;
 1056 
 1057       p = str = g_strconcat (g_hash_table_lookup (pkg->vars, prefix_variable),
 1058                  p + strlen (pkg->orig_prefix), NULL);
 1059       g_free (oldstr);
 1060     }
 1061 
 1062       if (g_hash_table_lookup (pkg->vars, tag))
 1063         {
 1064           verbose_error ("Duplicate definition of variable '%s' in '%s'\n",
 1065                          tag, path);
 1066           if (parse_strict)
 1067             exit (1);
 1068           else
 1069             goto cleanup;
 1070         }
 1071 
 1072       varname = g_strdup (tag);
 1073       varval = trim_and_sub (pkg, p, path);     
 1074 
 1075       debug_spew (" Variable declaration, '%s' has value '%s'\n",
 1076                   varname, varval);
 1077       g_hash_table_insert (pkg->vars, varname, varval);
 1078   
 1079     }
 1080 
 1081  cleanup:  
 1082   g_free (str);
 1083   g_free (tag);
 1084 }
 1085 
 1086 Package*
 1087 parse_package_file (const char *key, const char *path,
 1088                     gboolean ignore_requires,
 1089                     gboolean ignore_private_libs,
 1090                     gboolean ignore_requires_private)
 1091 {
 1092   FILE *f;
 1093   Package *pkg;
 1094   GString *str;
 1095   gboolean one_line = FALSE;
 1096   
 1097   f = fopen (path, "r");
 1098 
 1099   if (f == NULL)
 1100     {
 1101       verbose_error ("Failed to open '%s': %s\n",
 1102                      path, strerror (errno));
 1103       
 1104       return NULL;
 1105     }
 1106 
 1107   debug_spew ("Parsing package file '%s'\n", path);
 1108   
 1109   pkg = g_new0 (Package, 1);
 1110   pkg->key = g_strdup (key);
 1111 
 1112   if (path)
 1113     {
 1114       pkg->pcfiledir = g_dirname (path);
 1115     }
 1116   else
 1117     {
 1118       debug_spew ("No pcfiledir determined for package\n");
 1119       pkg->pcfiledir = g_strdup ("???????");
 1120     }
 1121 
 1122   if (pkg->vars == NULL)
 1123     pkg->vars = g_hash_table_new (g_str_hash, g_str_equal);
 1124 
 1125   /* Variable storing directory of pc file */
 1126   g_hash_table_insert (pkg->vars, "pcfiledir", pkg->pcfiledir);
 1127 
 1128   str = g_string_new ("");
 1129 
 1130   while (read_one_line (f, str))
 1131     {
 1132       one_line = TRUE;
 1133       
 1134       parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs,
 1135           ignore_requires_private);
 1136 
 1137       g_string_truncate (str, 0);
 1138     }
 1139 
 1140   if (!one_line)
 1141     verbose_error ("Package file '%s' appears to be empty\n",
 1142                    path);
 1143   g_string_free (str, TRUE);
 1144   fclose(f);
 1145 
 1146   pkg->cflags = g_list_reverse (pkg->cflags);
 1147   pkg->libs = g_list_reverse (pkg->libs);
 1148   
 1149   return pkg;
 1150 }
 1151 
 1152 /* Parse a package variable. When the value appears to be quoted,
 1153  * unquote it so it can be more easily used in a shell. Otherwise,
 1154  * return the raw value.
 1155  */
 1156 char *
 1157 parse_package_variable (Package *pkg, const char *variable)
 1158 {
 1159   char *value;
 1160   char *unquoted;
 1161   GError *error = NULL;
 1162 
 1163   value = package_get_var (pkg, variable);
 1164   if (!value)
 1165     return NULL;
 1166 
 1167   if (*value != '"' && *value != '\'')
 1168     /* Not quoted, return raw value */
 1169     return value;
 1170 
 1171   /* Maybe too naive, but assume a fully quoted variable */
 1172   unquoted = g_shell_unquote (value, &error);
 1173   if (unquoted)
 1174     {
 1175       g_free (value);
 1176       return unquoted;
 1177     }
 1178   else
 1179     {
 1180       /* Note the issue, but just return the raw value */
 1181       debug_spew ("Couldn't unquote value of \"%s\": %s\n",
 1182                   variable, error ? error->message : "unknown");
 1183       g_clear_error (&error);
 1184       return value;
 1185     }
 1186 }