]> err.no Git - pkg-config/blob - parse.c
Print out \r\n on windows, not just \n
[pkg-config] / parse.c
1 /* 
2  * Copyright (C) 2006-2009 Tollef Fog Heen <tfheen@err.no>
3  * Copyright (C) 2001, 2002, 2005-2006 Red Hat Inc.
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "parse.h"
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include "popt.h"
32 #ifdef HAVE_SYS_WAIT_H
33 #include <sys/wait.h>
34 #endif
35 #include <sys/types.h>
36
37 #ifdef G_OS_WIN32
38 int dont_define_prefix = FALSE;
39 char *prefix_variable = "prefix";
40 int msvc_syntax = FALSE;
41 #endif
42
43 #ifdef G_OS_WIN32
44 #ifndef G_IS_DIR_SEPARATOR
45 #define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
46 #endif
47 #endif
48
49 /**
50  * Read an entire line from a file into a buffer. Lines may
51  * be delimited with '\n', '\r', '\n\r', or '\r\n'. The delimiter
52  * is not written into the buffer. Text after a '#' character is treated as
53  * a comment and skipped. '\' can be used to escape a # character.
54  * '\' proceding a line delimiter combines adjacent lines. A '\' proceding
55  * any other character is ignored and written into the output buffer
56  * unmodified.
57  * 
58  * Return value: %FALSE if the stream was already at an EOF character.
59  **/
60 static gboolean
61 read_one_line (FILE *stream, GString *str)
62 {
63   gboolean quoted = FALSE;
64   gboolean comment = FALSE;
65   int n_read = 0;
66
67   g_string_truncate (str, 0);
68   
69   while (1)
70     {
71       int c;
72       
73       c = getc (stream);
74
75       if (c == EOF)
76         {
77           if (quoted)
78             g_string_append_c (str, '\\');
79           
80           goto done;
81         }
82       else
83         n_read++;
84
85       if (quoted)
86         {
87           quoted = FALSE;
88           
89           switch (c)
90             {
91             case '#':
92               g_string_append_c (str, '#');
93               break;
94             case '\r':
95             case '\n':
96               {
97                 int next_c = getc (stream);
98
99                 if (!(c == EOF ||
100                       (c == '\r' && next_c == '\n') ||
101                       (c == '\n' && next_c == '\r')))
102                   ungetc (next_c, stream);
103                 
104                 break;
105               }
106             default:
107               g_string_append_c (str, '\\');          
108               g_string_append_c (str, c);
109             }
110         }
111       else
112         {
113           switch (c)
114             {
115             case '#':
116               comment = TRUE;
117               break;
118             case '\\':
119               if (!comment)
120                 quoted = TRUE;
121               break;
122             case '\n':
123               {
124                 int next_c = getc (stream);
125
126                 if (!(c == EOF ||
127                       (c == '\r' && next_c == '\n') ||
128                       (c == '\n' && next_c == '\r')))
129                   ungetc (next_c, stream);
130
131                 goto done;
132               }
133             default:
134               if (!comment)
135                 g_string_append_c (str, c);
136             }
137         }
138     }
139
140  done:
141
142   return n_read > 0;
143 }
144
145 static char *
146 trim_string (const char *str)
147 {
148   int len;
149
150   g_return_val_if_fail (str != NULL, NULL);
151   
152   while (*str && isspace ((guchar)*str))
153     str++;
154
155   len = strlen (str);
156   while (len > 0 && isspace ((guchar)str[len-1]))
157     len--;
158
159   return g_strndup (str, len);
160 }
161
162 static char *
163 trim_and_sub (Package *pkg, const char *str, const char *path)
164 {
165   char *trimmed;
166   GString *subst;
167   char *p;
168   
169   trimmed = trim_string (str);
170
171   subst = g_string_new ("");
172
173   p = trimmed;
174   while (*p)
175     {
176       if (p[0] == '$' &&
177           p[1] == '$')
178         {
179           /* escaped $ */
180           g_string_append_c (subst, '$');
181           p += 2;
182         }
183       else if (p[0] == '$' &&
184                p[1] == '{')
185         {
186           /* variable */
187           char *var_start;
188           char *varname;
189           char *varval;
190           
191           var_start = &p[2];
192
193           /* Get up to close brace. */
194           while (*p && *p != '}')
195             ++p;
196
197           varname = g_strndup (var_start, p - var_start);
198
199           ++p; /* past brace */
200           
201           varval = package_get_var (pkg, varname);
202           
203           if (varval == NULL)
204             {
205               verbose_error ("Variable '%s' not defined in '%s'\n",
206                              varname, path);
207               
208               exit (1);
209             }
210
211           g_free (varname);
212
213           g_string_append (subst, varval);
214           g_free (varval);
215         }
216       else
217         {
218           g_string_append_c (subst, *p);
219
220           ++p;          
221         }
222     }
223
224   g_free (trimmed);
225   p = subst->str;
226   g_string_free (subst, FALSE);
227
228   return p;
229 }
230
231 static void
232 parse_name (Package *pkg, const char *str, const char *path)
233 {
234   if (pkg->name)
235     {
236       verbose_error ("Name field occurs twice in '%s'\n", path);
237
238       exit (1);
239     }
240   
241   pkg->name = trim_and_sub (pkg, str, path);
242 }
243
244 static void
245 parse_version (Package *pkg, const char *str, const char *path)
246 {
247   if (pkg->version)
248     {
249       verbose_error ("Version field occurs twice in '%s'\n", path);
250
251       exit (1);
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
264       exit (1);
265     }
266   
267   pkg->description = trim_and_sub (pkg, str, path);
268 }
269
270
271 #define MODULE_SEPARATOR(c) ((c) == ',' || isspace ((guchar)(c)))
272 #define OPERATOR_CHAR(c) ((c) == '<' || (c) == '>' || (c) == '!' || (c) == '=')
273
274 /* A module list is a list of modules with optional version specification,
275  * separated by commas and/or spaces. Commas are treated just like whitespace,
276  * in order to allow stuff like: Requires: @FRIBIDI_PC@, glib, gmodule
277  * where @FRIBIDI_PC@ gets substituted to nothing or to 'fribidi'
278  */
279
280 typedef enum
281 {
282   /* put numbers to help interpret lame debug spew ;-) */
283   OUTSIDE_MODULE = 0,
284   IN_MODULE_NAME = 1,
285   BEFORE_OPERATOR = 2,
286   IN_OPERATOR = 3,
287   AFTER_OPERATOR = 4,
288   IN_MODULE_VERSION = 5  
289 } ModuleSplitState;
290
291 #define PARSE_SPEW 0
292
293 static GSList*
294 split_module_list (const char *str, const char *path)
295 {
296   GSList *retval = NULL;
297   const char *p;
298   const char *start;
299   ModuleSplitState state = OUTSIDE_MODULE;
300   ModuleSplitState last_state = OUTSIDE_MODULE;
301
302   /*   fprintf (stderr, "Parsing: '%s'\n", str); */
303   
304   start = str;
305   p = str;
306
307   while (*p)
308     {
309 #if PARSE_SPEW
310       fprintf (stderr, "p: %c state: %d last_state: %d\n", *p, state, last_state);
311 #endif
312       
313       switch (state)
314         {
315         case OUTSIDE_MODULE:
316           if (!MODULE_SEPARATOR (*p))
317             state = IN_MODULE_NAME;          
318           break;
319
320         case IN_MODULE_NAME:
321           if (isspace ((guchar)*p))
322             {
323               /* Need to look ahead to determine next state */
324               const char *s = p;
325               while (*s && isspace ((guchar)*s))
326                 ++s;
327
328               if (*s == '\0')
329                 state = OUTSIDE_MODULE;
330               else if (MODULE_SEPARATOR (*s))
331                 state = OUTSIDE_MODULE;
332               else if (OPERATOR_CHAR (*s))
333                 state = BEFORE_OPERATOR;
334               else
335                 state = OUTSIDE_MODULE;
336             }
337           else if (MODULE_SEPARATOR (*p))
338             state = OUTSIDE_MODULE; /* comma precludes any operators */
339           break;
340
341         case BEFORE_OPERATOR:
342           /* We know an operator is coming up here due to lookahead from
343            * IN_MODULE_NAME
344            */
345           if (isspace ((guchar)*p))
346             ; /* no change */
347           else if (OPERATOR_CHAR (*p))
348             state = IN_OPERATOR;
349           else
350             g_assert_not_reached ();
351           break;
352
353         case IN_OPERATOR:
354           if (!OPERATOR_CHAR (*p))
355             state = AFTER_OPERATOR;
356           break;
357
358         case AFTER_OPERATOR:
359           if (!isspace ((guchar)*p))
360             state = IN_MODULE_VERSION;
361           break;
362
363         case IN_MODULE_VERSION:
364           if (MODULE_SEPARATOR (*p))
365             state = OUTSIDE_MODULE;
366           break;
367           
368         default:
369           g_assert_not_reached ();
370         }
371
372       if (state == OUTSIDE_MODULE &&
373           last_state != OUTSIDE_MODULE)
374         {
375           /* We left a module */
376           char *module = g_strndup (start, p - start);
377           retval = g_slist_prepend (retval, module);
378
379 #if PARSE_SPEW
380           fprintf (stderr, "found module: '%s'\n", module);
381 #endif
382           
383           /* reset start */
384           start = p;
385         }
386       
387       last_state = state;
388       ++p;
389     }
390
391   if (p != start)
392     {
393       /* get the last module */
394       char *module = g_strndup (start, p - start);
395       retval = g_slist_prepend (retval, module);
396
397 #if PARSE_SPEW
398       fprintf (stderr, "found module: '%s'\n", module);
399 #endif
400       
401     }
402   
403   retval = g_slist_reverse (retval);
404
405   return retval;
406 }
407
408 GSList*
409 parse_module_list (Package *pkg, const char *str, const char *path)
410 {
411   GSList *split;
412   GSList *iter;
413   GSList *retval = NULL;
414
415   split = split_module_list (str, path);
416   
417   iter = split;
418   while (iter != NULL)
419     {
420       RequiredVersion *ver;
421       char *p;
422       char *start;
423       
424       p = iter->data;
425
426       ver = g_new0 (RequiredVersion, 1);
427       ver->comparison = ALWAYS_MATCH;
428       ver->owner = pkg;
429       retval = g_slist_prepend (retval, ver);
430       
431       while (*p && MODULE_SEPARATOR (*p))
432         ++p;
433       
434       start = p;
435
436       while (*p && !isspace ((guchar)*p))
437         ++p;
438
439       while (*p && MODULE_SEPARATOR (*p))
440         {
441           *p = '\0';
442           ++p;
443         }
444
445       if (*start == '\0')
446         {
447           verbose_error ("Empty package name in Requires or Conflicts in file '%s'\n", path);
448           
449           exit (1);
450         }
451       
452       ver->name = g_strdup (start);
453
454       start = p;
455
456       while (*p && !isspace ((guchar)*p))
457         ++p;
458
459       while (*p && isspace ((guchar)*p))
460         {
461           *p = '\0';
462           ++p;
463         }
464       
465       if (*start != '\0')
466         {
467           if (strcmp (start, "=") == 0)
468             ver->comparison = EQUAL;
469           else if (strcmp (start, ">=") == 0)
470             ver->comparison = GREATER_THAN_EQUAL;
471           else if (strcmp (start, "<=") == 0)
472             ver->comparison = LESS_THAN_EQUAL;
473           else if (strcmp (start, ">") == 0)
474             ver->comparison = GREATER_THAN;
475           else if (strcmp (start, "<") == 0)
476             ver->comparison = LESS_THAN;
477           else if (strcmp (start, "!=") == 0)
478             ver->comparison = NOT_EQUAL;
479           else
480             {
481               verbose_error ("Unknown version comparison operator '%s' after package name '%s' in file '%s'\n", start, ver->name, path);
482               
483               exit (1);
484             }
485         }
486
487       start = p;
488       
489       while (*p && !MODULE_SEPARATOR (*p))
490         ++p;
491
492       while (*p && MODULE_SEPARATOR (*p))
493         {
494           *p = '\0';
495           ++p;
496         }
497       
498       if (ver->comparison != ALWAYS_MATCH && *start == '\0')
499         {
500           verbose_error ("Comparison operator but no version after package name '%s' in file '%s'\n", ver->name, path);
501           
502           exit (1);
503         }
504
505       if (*start != '\0')
506         {
507           ver->version = g_strdup (start);
508         }
509
510       g_assert (ver->name);
511       
512       iter = g_slist_next (iter);
513     }
514
515   g_slist_foreach (split, (GFunc) g_free, NULL);
516   g_slist_free (split);
517
518   retval = g_slist_reverse (retval);
519
520   return retval;
521 }
522
523 static void
524 parse_requires (Package *pkg, const char *str, const char *path)
525 {
526   GSList *parsed;
527   GSList *iter;
528   char *trimmed;
529   
530   if (pkg->requires)
531     {
532       verbose_error ("Requires field occurs twice in '%s'\n", path);
533
534       exit (1);
535     }
536
537   trimmed = trim_and_sub (pkg, str, path);
538   parsed = parse_module_list (pkg, trimmed, path);
539   g_free (trimmed);
540   
541   iter = parsed;
542   while (iter != NULL)
543     {
544       Package *req;
545       RequiredVersion *ver = iter->data;
546       
547       req = get_package (ver->name);
548
549       if (req == NULL)
550         {
551           verbose_error ("Package '%s', required by '%s', not found\n",
552                          ver->name, pkg->name ? pkg->name : path);
553           
554           exit (1);
555         }
556
557       if (pkg->required_versions == NULL)
558         pkg->required_versions = g_hash_table_new (g_str_hash, g_str_equal);
559       
560       g_hash_table_insert (pkg->required_versions, ver->name, ver);
561       
562       pkg->requires = g_slist_prepend (pkg->requires, req);
563
564       iter = g_slist_next (iter);
565     }
566
567   g_slist_free (parsed);
568 }
569
570 static void
571 parse_requires_private (Package *pkg, const char *str, const char *path)
572 {
573   GSList *parsed;
574   GSList *iter;
575   char *trimmed;
576   
577   if (pkg->requires_private)
578     {
579       verbose_error ("Requires.private field occurs twice in '%s'\n", path);
580
581       exit (1);
582     }
583
584   trimmed = trim_and_sub (pkg, str, path);
585   parsed = parse_module_list (pkg, trimmed, path);
586   g_free (trimmed);
587   
588   iter = parsed;
589   while (iter != NULL)
590     {
591       Package *req;
592       RequiredVersion *ver = iter->data;
593       
594       req = get_package (ver->name);
595
596       if (req == NULL)
597         {
598           verbose_error ("Package '%s', required by '%s', not found\n",
599                          ver->name, pkg->name ? pkg->name : path);
600           
601           exit (1);
602         }
603
604       if (pkg->required_versions == NULL)
605         pkg->required_versions = g_hash_table_new (g_str_hash, g_str_equal);
606       
607       g_hash_table_insert (pkg->required_versions, ver->name, ver);
608       
609       pkg->requires_private = g_slist_prepend (pkg->requires_private, req);
610
611       iter = g_slist_next (iter);
612     }
613
614   g_slist_free (parsed);
615 }
616
617 static void
618 parse_conflicts (Package *pkg, const char *str, const char *path)
619 {
620   GSList *parsed;
621   GSList *iter;
622   char *trimmed;
623   
624   if (pkg->conflicts)
625     {
626       verbose_error ("Conflicts field occurs twice in '%s'\n", path);
627
628       exit (1);
629     }
630
631   trimmed = trim_and_sub (pkg, str, path);
632   pkg->conflicts = parse_module_list (pkg, trimmed, path);
633   g_free (trimmed);
634 }
635
636 static void _do_parse_libs (Package *pkg, int argc, char **argv)
637 {
638   int i;
639 #ifdef G_OS_WIN32
640   char *L_flag = (msvc_syntax ? "/libpath:" : "-L");
641   char *l_flag = (msvc_syntax ? "" : "-l");
642   char *lib_suffix = (msvc_syntax ? ".lib" : "");
643 #else
644   char *L_flag = "-L";
645   char *l_flag = "-l";
646   char *lib_suffix = "";
647 #endif
648
649   i = 0;
650   while (i < argc)
651     {
652       char *arg = trim_string (argv[i]);
653       char *p;
654       char *start;
655
656       start = arg;
657       p = start;      
658
659       if (p[0] == '-' &&
660           p[1] == 'l' &&
661           /* -lib: is used by the C# compiler for libs; it's not an -l
662               flag. */
663           (strncmp(p, "-lib:", 5) != 0))
664         {
665           char *libname;          
666               
667           p += 2;
668           while (*p && isspace ((guchar)*p))
669             ++p;
670               
671           start = p;
672           while (*p && !isspace ((guchar)*p))
673             ++p;
674
675           libname = g_strndup (start, p - start);
676           
677           pkg->l_libs = g_slist_prepend (pkg->l_libs,
678                                          g_strconcat (l_flag, libname, lib_suffix, NULL));
679
680           g_free (libname);
681         }
682       else if (p[0] == '-' &&
683                p[1] == 'L')
684         {
685           char *libname;          
686           
687           p += 2;
688           while (*p && isspace ((guchar)*p))
689             ++p;
690               
691           start = p;
692           while (*p && !isspace ((guchar)*p))
693             ++p;
694
695           libname = g_strndup (start, p - start);
696           
697           pkg->L_libs = g_slist_prepend (pkg->L_libs,
698                                          g_strconcat (L_flag, libname, NULL));
699
700           g_free (libname);
701         }
702       else if (strcmp("-framework",p) == 0 && i+1 < argc)
703         {
704           /* Mac OS X has a -framework Foo which is really one option,
705            * so we join those to avoid having -framework Foo
706            * -framework Bar being changed into -framework Foo Bar
707            * later
708           */
709           gchar *framework = trim_string (argv[i+1]);
710
711           pkg->other_libs = g_slist_prepend (pkg->other_libs,
712                                              g_strconcat(arg, " ", framework, NULL));
713           i++;
714           g_free(framework);
715         }
716       else
717         {
718           if (*arg != '\0')
719             pkg->other_libs = g_slist_prepend (pkg->other_libs,
720                                                g_strdup (arg));
721         }
722
723       g_free (arg);
724       
725       ++i;
726     }
727
728 }
729
730
731 static void
732 parse_libs (Package *pkg, const char *str, const char *path)
733 {
734   /* Strip out -l and -L flags, put them in a separate list. */
735   
736   char *trimmed;
737   char **argv = NULL;
738   int argc;
739   int result;
740   
741   if (pkg->libs_num > 0)
742     {
743       verbose_error ("Libs field occurs twice in '%s'\n", path);
744
745       exit (1);
746     }
747   
748   trimmed = trim_and_sub (pkg, str, path);
749
750   result = poptParseArgvString (trimmed, &argc, &argv);
751
752   if (result < 0)
753     {
754       verbose_error ("Couldn't parse Libs field into an argument vector: %s\n",
755                poptStrerror (result));
756
757       exit (1);
758     }
759
760   _do_parse_libs(pkg, argc, argv);
761
762   g_free (trimmed);
763   g_free (argv);
764   pkg->libs_num++;
765 }
766
767 static void
768 parse_libs_private (Package *pkg, const char *str, const char *path)
769 {
770   /*
771     List of private libraries.  Private libraries are libraries which
772     are needed in the case of static linking or on platforms not
773     supporting inter-library dependencies.  They are not supposed to
774     be used for libraries which are exposed through the library in
775     question.  An example of an exposed library is GTK+ exposing Glib.
776     A common example of a private library is libm.
777     
778     Generally, if include another library's headers in your own, it's
779     a public dependency and not a private one.
780   */
781   
782   char *trimmed;
783   char **argv = NULL;
784   int argc;
785   int result;
786   
787   if (pkg->libs_private_num > 0)
788     {
789       verbose_error ("Libs.private field occurs twice in '%s'\n", path);
790
791       exit (1);
792     }
793   
794   trimmed = trim_and_sub (pkg, str, path);
795
796   result = poptParseArgvString (trimmed, &argc, &argv);
797
798   if (result < 0)
799     {
800       verbose_error ("Couldn't parse Libs.private field into an argument vector: %s\n",
801                poptStrerror (result));
802
803       exit (1);
804     }
805
806   _do_parse_libs(pkg, argc, argv);
807
808   g_free (argv);
809   g_free (trimmed);
810
811   pkg->libs_private_num++;
812 }
813
814 static void
815 parse_cflags (Package *pkg, const char *str, const char *path)
816 {
817   /* Strip out -I flags, put them in a separate list. */
818   
819   char *trimmed;
820   char **argv = NULL;
821   int argc;
822   int result;
823   int i;
824   
825   if (pkg->I_cflags || pkg->other_cflags)
826     {
827       verbose_error ("Cflags field occurs twice in '%s'\n", path);
828
829       exit (1);
830     }
831   
832   trimmed = trim_and_sub (pkg, str, path);
833
834   result = poptParseArgvString (trimmed, &argc, &argv);
835
836   if (result < 0)
837     {
838       verbose_error ("Couldn't parse Cflags field into an argument vector: %s\n",
839                      poptStrerror (result));
840
841       exit (1);
842     }
843
844   i = 0;
845   while (i < argc)
846     {
847       char *arg = trim_string (argv[i]);
848       char *p;
849       char *start;
850
851       start = arg;
852       p = start;      
853
854       if (p[0] == '-' &&
855           p[1] == 'I')
856         {
857           char *libname;          
858               
859           p += 2;
860           while (*p && isspace ((guchar)*p))
861             ++p;
862               
863           start = p;
864           while (*p && !isspace ((guchar)*p))
865             ++p;
866
867           libname = g_strndup (start, p - start);
868           
869           pkg->I_cflags = g_slist_prepend (pkg->I_cflags,
870                                            g_strconcat ("-I", libname, NULL));
871
872           g_free (libname);
873         }
874       else
875         {
876           if (*arg != '\0')
877             pkg->other_cflags = g_slist_prepend (pkg->other_cflags,
878                                                  g_strdup (arg));
879         }
880
881       g_free (arg);
882       
883       ++i;
884     }
885
886   g_free (argv);
887   g_free (trimmed);
888 }
889
890 static void
891 parse_url (Package *pkg, const char *str, const char *path)
892 {
893   if (pkg->url != NULL)
894     {
895       verbose_error ("URL field occurs twice in '%s'\n", path);
896
897       exit (1);
898     }
899
900   pkg->url = trim_and_sub (pkg, str, path);
901 }
902
903 #ifdef G_OS_WIN32
904 static char *orig_prefix = NULL;
905
906 static int
907 pathnamecmp (const char *a,
908              const char *b)
909 {
910   while (*a && *b &&
911          ((G_IS_DIR_SEPARATOR (*a) && G_IS_DIR_SEPARATOR (*b)) ||
912           g_ascii_toupper (*a) == g_ascii_toupper (*b)))
913     {
914       a++;
915       b++;
916     }
917   return g_ascii_toupper (*a) - g_ascii_toupper (*b);
918 }
919 #endif
920
921 static void
922 parse_line (Package *pkg, const char *untrimmed, const char *path,
923             gboolean ignore_requires, gboolean ignore_private_libs,
924             gboolean ignore_requires_private)
925 {
926   char *str;
927   char *p;
928   char *tag;
929
930   debug_spew ("  line>%s\n", untrimmed);
931   
932   str = trim_string (untrimmed);
933   
934   if (*str == '\0') /* empty line */
935     {
936       g_free(str);
937       return;
938     }
939   
940   p = str;
941
942   /* Get first word */
943   while ((*p >= 'A' && *p <= 'Z') ||
944          (*p >= 'a' && *p <= 'z') ||
945          (*p >= '0' && *p <= '9') ||
946          *p == '_' || *p == '.')
947     p++;
948
949   tag = g_strndup (str, p - str);
950   
951   while (*p && isspace ((guchar)*p))
952     ++p;
953
954   if (*p == ':')
955     {
956       /* keyword */
957       ++p;
958       while (*p && isspace ((guchar)*p))
959         ++p;
960
961       if (strcmp (tag, "Name") == 0)
962         parse_name (pkg, p, path);
963       else if (strcmp (tag, "Description") == 0)
964         parse_description (pkg, p, path);
965       else if (strcmp (tag, "Version") == 0)
966         parse_version (pkg, p, path);
967       else if (strcmp (tag, "Requires.private") == 0)
968         {
969           if (!ignore_requires_private)
970             parse_requires_private (pkg, p, path);
971         }
972       else if (strcmp (tag, "Requires") == 0)
973         {
974           if (ignore_requires == FALSE)
975             parse_requires (pkg, p, path);
976           else
977             goto cleanup;
978         }
979       else if ((strcmp (tag, "Libs.private") == 0) && 
980                ignore_private_libs == FALSE)
981         parse_libs_private (pkg, p, path);
982       else if (strcmp (tag, "Libs") == 0)
983         parse_libs (pkg, p, path);
984       else if (strcmp (tag, "Cflags") == 0 ||
985                strcmp (tag, "CFlags") == 0)
986         parse_cflags (pkg, p, path);
987       else if (strcmp (tag, "Conflicts") == 0)
988         parse_conflicts (pkg, p, path);
989       else if (strcmp (tag, "URL") == 0)
990         parse_url (pkg, p, path);
991       else
992         {
993           /* we don't error out on unknown keywords because they may
994            * represent additions to the .pc file format from future
995            * versions of pkg-config.  We do make a note of them in the
996            * debug spew though, in order to help catch mistakes in .pc
997            * files. */
998           debug_spew ("Unknown keyword '%s' in '%s'\n",
999                       tag, path);
1000         }
1001     }
1002   else if (*p == '=')
1003     {
1004       /* variable */
1005       char *varname;
1006       char *varval;
1007       
1008       ++p;
1009       while (*p && isspace ((guchar)*p))
1010         ++p;
1011       
1012       if (pkg->vars == NULL)
1013         pkg->vars = g_hash_table_new (g_str_hash, g_str_equal);
1014
1015 #ifdef G_OS_WIN32
1016       if (!dont_define_prefix && strcmp (tag, prefix_variable) == 0)
1017         {
1018           /* This is the prefix variable. Try to guesstimate a value for it
1019            * for this package from the location of the .pc file.
1020            */
1021
1022           gchar *prefix = pkg->pcfiledir;
1023           const int prefix_len = strlen (prefix);
1024           const char *const lib_pkgconfig = "\\lib\\pkgconfig";
1025           const char *const share_pkgconfig = "\\share\\pkgconfig";
1026           const int lib_pkgconfig_len = strlen (lib_pkgconfig);
1027           const int share_pkgconfig_len = strlen (share_pkgconfig);
1028
1029           if ((strlen (prefix) > lib_pkgconfig_len &&
1030                pathnamecmp (prefix + prefix_len - lib_pkgconfig_len, lib_pkgconfig) == 0) ||
1031               (strlen (prefix) > share_pkgconfig_len &&
1032                pathnamecmp (prefix + prefix_len - share_pkgconfig_len, share_pkgconfig) == 0))
1033             {
1034               /* It ends in lib\pkgconfig or share\pkgconfig. Good. */
1035               
1036               gchar *q;
1037               
1038               orig_prefix = g_strdup (p);
1039
1040               prefix = g_strdup (prefix);
1041               if (strlen (prefix) > lib_pkgconfig_len &&
1042                   pathnamecmp (prefix + prefix_len - lib_pkgconfig_len, lib_pkgconfig) == 0)
1043                 prefix[prefix_len - lib_pkgconfig_len] = '\0';
1044               else
1045                 prefix[prefix_len - share_pkgconfig_len] = '\0';
1046               
1047               /* Turn backslashes into slashes or
1048                * poptParseArgvString() will eat them when ${prefix}
1049                * has been expanded in parse_libs().
1050                */
1051               q = prefix;
1052               while (*q)
1053                 {
1054                   if (*q == '\\')
1055                     *q = '/';
1056                   q++;
1057                 }
1058               varname = g_strdup (tag);
1059               debug_spew (" Variable declaration, '%s' overridden with '%s'\n",
1060                           tag, prefix);
1061               g_hash_table_insert (pkg->vars, varname, prefix);
1062               goto cleanup;
1063             }
1064         }
1065       else if (!dont_define_prefix &&
1066                orig_prefix != NULL &&
1067                strncmp (p, orig_prefix, strlen (orig_prefix)) == 0 &&
1068                G_IS_DIR_SEPARATOR (p[strlen (orig_prefix)]))
1069         {
1070           char *oldstr = str;
1071
1072           p = str = g_strconcat (g_hash_table_lookup (pkg->vars, prefix_variable), p + strlen (orig_prefix), NULL);
1073           g_free (oldstr);
1074         }
1075 #endif
1076
1077       if (g_hash_table_lookup (pkg->vars, tag))
1078         {
1079           verbose_error ("Duplicate definition of variable '%s' in '%s'\n",
1080                          tag, path);
1081
1082           exit (1);
1083         }
1084
1085       varname = g_strdup (tag);
1086       varval = trim_and_sub (pkg, p, path);     
1087
1088       debug_spew (" Variable declaration, '%s' has value '%s'\n",
1089                   varname, varval);
1090       g_hash_table_insert (pkg->vars, varname, varval);
1091   
1092     }
1093
1094  cleanup:  
1095   g_free (str);
1096   g_free (tag);
1097 }
1098
1099 Package*
1100 parse_package_file (const char *path, gboolean ignore_requires,
1101                     gboolean ignore_private_libs,
1102                     gboolean ignore_requires_private)
1103 {
1104   FILE *f;
1105   Package *pkg;
1106   GString *str;
1107   gboolean one_line = FALSE;
1108   
1109   f = fopen (path, "r");
1110
1111   if (f == NULL)
1112     {
1113       verbose_error ("Failed to open '%s': %s\n",
1114                      path, strerror (errno));
1115       
1116       return NULL;
1117     }
1118
1119   debug_spew ("Parsing package file '%s'\n", path);
1120   
1121   pkg = g_new0 (Package, 1);
1122
1123   if (path)
1124     {
1125       pkg->pcfiledir = g_dirname (path);
1126     }
1127   else
1128     {
1129       debug_spew ("No pcfiledir determined for package\n");
1130       pkg->pcfiledir = g_strdup ("???????");
1131     }
1132   
1133   str = g_string_new ("");
1134
1135   while (read_one_line (f, str))
1136     {
1137       one_line = TRUE;
1138       
1139       parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs,
1140                   ignore_requires_private);
1141
1142       g_string_truncate (str, 0);
1143     }
1144
1145   if (!one_line)
1146     verbose_error ("Package file '%s' appears to be empty\n",
1147                    path);
1148   g_string_free (str, TRUE);
1149   fclose(f);
1150
1151   /* make ->requires_private include a copy of the public requires too */
1152   pkg->requires_private = g_slist_concat(g_slist_copy (pkg->requires),
1153                                          pkg->requires_private);
1154   
1155   pkg->requires = g_slist_reverse (pkg->requires);
1156   
1157   pkg->requires_private = g_slist_reverse (pkg->requires_private);
1158
1159   pkg->I_cflags = g_slist_reverse (pkg->I_cflags);
1160   pkg->other_cflags = g_slist_reverse (pkg->other_cflags);
1161
1162   pkg->l_libs = g_slist_reverse (pkg->l_libs);
1163   pkg->L_libs = g_slist_reverse (pkg->L_libs);
1164   pkg->other_libs = g_slist_reverse (pkg->other_libs);
1165   
1166   return pkg;
1167 }
1168
1169 static char *
1170 backticks (const char *command)
1171 {
1172   FILE *f;
1173   char buf[4096];
1174   size_t len;
1175   int status;
1176   
1177   f = popen (command, "r");
1178
1179   if (f == NULL)
1180     return NULL;
1181   
1182   len = fread (buf, 1, 4090, f);
1183
1184   if (ferror (f))
1185     {
1186       pclose (f);
1187       return NULL;
1188     }
1189   
1190   buf[len] = '\0';
1191
1192   status = pclose (f);
1193
1194   return g_strdup (buf);
1195 }
1196
1197 static gboolean
1198 try_command (const char *command)
1199 {
1200   int status;
1201   char *munged;
1202
1203 #ifdef G_OS_WIN32
1204   munged = g_strdup_printf ("%s > NUL", command);
1205 #else
1206   munged = g_strdup_printf ("%s > /dev/null 2>&1", command);
1207 #endif
1208   
1209   status = system (munged);
1210
1211   g_free (munged);
1212   
1213 #ifdef G_OS_WIN32
1214   return status == 0;
1215 #else
1216   return WIFEXITED(status) && (WEXITSTATUS(status) == 0);
1217 #endif
1218 }
1219
1220 Package *
1221 get_compat_package (const char *name)
1222 {
1223 #ifdef G_OS_WIN32
1224   /* There has never been any of these legacy *-config scripts on
1225    * Windows as far as I know. No use trying to execute them, will
1226    * only confuse users to see the "blabla is not recognized as an
1227    * internal or external command, operable program or batch file"
1228    * messages.
1229    */
1230   return NULL;
1231 #else
1232
1233   Package *pkg;
1234
1235   if (name_ends_in_uninstalled (name))
1236     debug_spew ("Suspiciously looking for compat package for -uninstalled: %s\n", name);
1237   
1238   debug_spew ("Looking for '%s' using legacy -config scripts\n", name);
1239   
1240   pkg = g_new0 (Package, 1);
1241
1242   pkg->path_position = G_MAXINT;
1243   
1244   if (strcmp (name, "glib") == 0)
1245     {
1246       char *output;
1247
1248       debug_spew ("Calling glib-config\n");
1249       
1250       pkg->version = backticks ("glib-config --version");
1251       if (pkg->version == NULL)
1252         {
1253           g_free (pkg);
1254           return NULL;
1255         }
1256       
1257       pkg->name = g_strdup ("GLib");
1258       pkg->key = g_strdup ("glib");
1259       pkg->description = g_strdup ("C Utility Library");
1260
1261       output = backticks ("glib-config --libs");
1262       parse_libs (pkg, output, "glib-config");
1263       g_free (output);
1264
1265       output = backticks ("glib-config --cflags");
1266       parse_cflags (pkg, output, "glib-config");
1267       g_free (output);
1268
1269       return pkg;
1270     }
1271   else if (strcmp (name, "gtk+") == 0)
1272     {
1273       char *output;
1274
1275       debug_spew ("Calling gtk-config\n");
1276       
1277       pkg->version = backticks ("gtk-config --version");
1278       if (pkg->version == NULL)
1279         {
1280           g_free (pkg);
1281           return NULL;
1282         }
1283       
1284       pkg->name = g_strdup ("GTK+");
1285       pkg->key = g_strdup ("gtk+");
1286       pkg->description = g_strdup ("GIMP Tool Kit");
1287
1288       output = backticks ("gtk-config --libs");
1289       parse_libs (pkg, output, "gtk-config");
1290       g_free (output);
1291
1292       output = backticks ("gtk-config --cflags");
1293       parse_cflags (pkg, output, "gtk-config");
1294       g_free (output);
1295
1296       return pkg;
1297     }
1298   else if (strcmp (name, "libgnomevfs") == 0)
1299     {
1300       char *output;
1301
1302       debug_spew ("Calling gnome-vfs-config\n");
1303       
1304       pkg->version = backticks ("gnome-vfs-config --version");
1305       if (pkg->version == NULL)
1306         {
1307           g_free (pkg);
1308           return NULL;
1309         }
1310       
1311       pkg->name = g_strdup ("GNOME VFS");
1312       pkg->key = g_strdup ("libgnomevfs");
1313       pkg->description = g_strdup ("GNOME Virtual File System");
1314
1315       output = backticks ("gnome-vfs-config --libs");
1316       parse_libs (pkg, output, "gnome-vfs-config");
1317       g_free (output);
1318
1319       output = backticks ("gnome-vfs-config --cflags");
1320       parse_cflags (pkg, output, "gnome-vfs-config");
1321       g_free (output);
1322
1323       return pkg;
1324     }
1325   else if (strcmp (name, "imlib") == 0)
1326     {
1327       char *output;
1328
1329       debug_spew ("Calling imlib-config\n");
1330       
1331       pkg->version = backticks ("imlib-config --version");
1332       if (pkg->version == NULL)
1333         {
1334           g_free (pkg);
1335           return NULL;
1336         }
1337       
1338       pkg->name = g_strdup ("Imlib");
1339       pkg->key = g_strdup ("imlib");
1340       pkg->description = g_strdup ("Imlib image loading library");
1341
1342       output = backticks ("imlib-config --libs-gdk");
1343       parse_libs (pkg, output, "imlib-config");
1344       g_free (output);
1345
1346       output = backticks ("imlib-config --cflags-gdk");
1347       parse_cflags (pkg, output, "imlib-config");
1348       g_free (output);
1349
1350       return pkg;
1351     }
1352   else if (strcmp (name, "orbit-client") == 0)
1353     {
1354       char *output;
1355       char *p;
1356
1357       debug_spew ("Calling orbit-config\n");
1358       
1359       output = backticks ("orbit-config --version");
1360       
1361       if (output == NULL)
1362         {
1363           g_free (pkg);
1364           return NULL;
1365         }
1366
1367       p = output;
1368
1369       while (*p && isspace ((guchar)*p))
1370         ++p;
1371
1372       if (*p == '\0')
1373         {
1374           /* empty output */
1375           g_free (output);
1376           g_free (pkg);
1377           return NULL;
1378         }
1379
1380       /* only heuristic; find a number or . */
1381       while (*p && ! (isdigit ((guchar)*p) || *p == '.'))
1382         ++p;      
1383
1384       pkg->version = g_strdup (p);
1385
1386       g_free (output);
1387       
1388       pkg->name = g_strdup ("ORBit Client");
1389       pkg->key = g_strdup ("orbit-client");
1390       pkg->description = g_strdup ("ORBit Client Libraries");
1391
1392       output = backticks ("orbit-config --libs client");
1393       parse_libs (pkg, output, "orbit-config");
1394       g_free (output);
1395
1396       output = backticks ("orbit-config --cflags client");
1397       parse_cflags (pkg, output, "orbit-config");
1398       g_free (output);
1399
1400       return pkg;
1401     }
1402   else if (strcmp (name, "orbit-server") == 0)
1403     {
1404       char *output;
1405       char *p;
1406
1407       debug_spew ("Calling orbit-config\n");
1408       
1409       output = backticks ("orbit-config --version");
1410       
1411       if (output == NULL)
1412         {
1413           g_free (pkg);
1414           return NULL;
1415         }
1416
1417       p = output;
1418
1419       while (*p && isspace ((guchar)*p))
1420         ++p;
1421
1422       if (*p == '\0')
1423         {
1424           /* empty output */
1425           g_free (output);
1426           g_free (pkg);
1427           return NULL;
1428         }
1429
1430       /* only heuristic; find a number or . */
1431       while (*p && ! (isdigit ((guchar)*p) || *p == '.'))
1432         ++p;      
1433
1434       pkg->version = g_strdup (p);
1435
1436       g_free (output);
1437       
1438       pkg->name = g_strdup ("ORBit Server");
1439       pkg->key = g_strdup ("orbit-server");
1440       pkg->description = g_strdup ("ORBit Server Libraries");
1441
1442       output = backticks ("orbit-config --libs server");
1443       parse_libs (pkg, output, "orbit-config");
1444       g_free (output);
1445
1446       output = backticks ("orbit-config --cflags server");
1447       parse_cflags (pkg, output, "orbit-config");
1448       g_free (output);
1449
1450       return pkg;
1451     }
1452   else
1453     {
1454       /* Check for the module in gnome-config */
1455       char *output;
1456       char *p;
1457       char *command;
1458
1459       debug_spew ("Calling gnome-config\n");
1460       
1461       /* Annoyingly, --modversion doesn't return a failure
1462        * code if the lib is unknown, so we have to use --libs
1463        * for that.
1464        */
1465       
1466       command = g_strdup_printf ("gnome-config --libs %s",
1467                                  name);
1468       
1469       if (!try_command (command))
1470         {
1471           g_free (command);
1472           g_free (pkg);
1473           return NULL;
1474         }
1475       else
1476         g_free (command);
1477       
1478       command = g_strdup_printf ("gnome-config --modversion %s",
1479                                  name);
1480       
1481       output = backticks (command);
1482       g_free (command);
1483       if (output == NULL)
1484         {
1485           g_free (pkg);
1486           return NULL;
1487         }
1488       
1489       /* Unknown modules give "Unknown library `foo'" from gnome-config
1490        * (but on stderr so this is useless, nevermind)
1491        */
1492       if (strstr (output, "Unknown") || *output == '\0')
1493         {
1494           g_free (output);
1495           g_free (pkg);
1496           return NULL;
1497         }
1498
1499       /* gnome-config --modversion gnomeui outputs e.g. "gnome-libs-1.2.4"
1500        * or libglade-0.12
1501        */
1502       p = output;
1503
1504       while (*p && isspace ((guchar)*p))
1505         ++p;
1506
1507       if (*p == '\0')
1508         {
1509           /* empty output */
1510           g_free (output);
1511           g_free (pkg);
1512           return NULL;
1513         }
1514
1515       /* only heuristic; find a number or . */
1516       while (*p && ! (isdigit ((guchar)*p) || *p == '.'))
1517         ++p;      
1518
1519       pkg->version = g_strdup (p);
1520
1521       g_free (output);
1522       
1523       /* Strip newline */
1524       p = pkg->version;
1525       while (*p)
1526         {
1527           if (*p == '\n')
1528             *p = '\0';
1529
1530           ++p;
1531         }
1532       
1533       pkg->name = g_strdup (name);
1534       pkg->key = g_strdup (name);
1535       pkg->description = g_strdup ("No description");
1536
1537       command = g_strdup_printf ("gnome-config --libs %s", name);
1538       output = backticks (command);
1539       g_free (command);
1540       parse_libs (pkg, output, "gnome-config");
1541       g_free (output);
1542
1543       command = g_strdup_printf ("gnome-config --cflags %s", name);
1544       output = backticks (command);
1545       g_free (command);
1546       parse_cflags (pkg, output, "gnome-config");
1547       g_free (output);
1548
1549       return pkg;
1550     }
1551 #endif
1552 }