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