|
1 /* goption.c - Option parser |
|
2 * |
|
3 * Copyright (C) 1999, 2003 Red Hat Software |
|
4 * Copyright (C) 2004 Anders Carlsson <andersca@gnome.org> |
|
5 * Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
6 * |
|
7 * This library is free software; you can redistribute it and/or |
|
8 * modify it under the terms of the GNU Library General Public |
|
9 * License as published by the Free Software Foundation; either |
|
10 * version 2 of the License, or (at your option) any later version. |
|
11 * |
|
12 * This library is distributed in the hope that it will be useful, |
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 * Library General Public License for more details. |
|
16 * |
|
17 * You should have received a copy of the GNU Library General Public |
|
18 * License along with this library; if not, write to the |
|
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
20 * Boston, MA 02111-1307, USA. |
|
21 */ |
|
22 |
|
23 #include "config.h" |
|
24 |
|
25 #include "goption.h" |
|
26 #include "glib.h" |
|
27 #include "glibintl.h" |
|
28 |
|
29 #include "galias.h" |
|
30 |
|
31 #include <string.h> |
|
32 #include <stdlib.h> |
|
33 #include <errno.h> |
|
34 |
|
35 #ifdef __SYMBIAN32__ |
|
36 #include <glib_wsd.h> |
|
37 #endif |
|
38 |
|
39 #define TRANSLATE(group, str) (((group)->translate_func ? (* (group)->translate_func) ((str), (group)->translate_data) : (str))) |
|
40 |
|
41 #define NO_ARG(entry) ((entry)->arg == G_OPTION_ARG_NONE || \ |
|
42 ((entry)->arg == G_OPTION_ARG_CALLBACK && \ |
|
43 ((entry)->flags & G_OPTION_FLAG_NO_ARG))) |
|
44 |
|
45 #define OPTIONAL_ARG(entry) ((entry)->arg == G_OPTION_ARG_CALLBACK && \ |
|
46 (entry)->flags & G_OPTION_FLAG_OPTIONAL_ARG) |
|
47 |
|
48 typedef struct |
|
49 { |
|
50 GOptionArg arg_type; |
|
51 gpointer arg_data; |
|
52 union |
|
53 { |
|
54 gboolean bool; |
|
55 gint integer; |
|
56 gchar *str; |
|
57 gchar **array; |
|
58 } prev; |
|
59 union |
|
60 { |
|
61 gchar *str; |
|
62 struct |
|
63 { |
|
64 gint len; |
|
65 gchar **data; |
|
66 } array; |
|
67 } allocated; |
|
68 } Change; |
|
69 |
|
70 typedef struct |
|
71 { |
|
72 gchar **ptr; |
|
73 gchar *value; |
|
74 } PendingNull; |
|
75 |
|
76 struct _GOptionContext |
|
77 { |
|
78 GList *groups; |
|
79 |
|
80 gchar *parameter_string; |
|
81 |
|
82 gboolean help_enabled; |
|
83 gboolean ignore_unknown; |
|
84 |
|
85 GOptionGroup *main_group; |
|
86 |
|
87 /* We keep a list of change so we can revert them */ |
|
88 GList *changes; |
|
89 |
|
90 /* We also keep track of all argv elements that should be NULLed or |
|
91 * modified. |
|
92 */ |
|
93 GList *pending_nulls; |
|
94 }; |
|
95 |
|
96 struct _GOptionGroup |
|
97 { |
|
98 gchar *name; |
|
99 gchar *description; |
|
100 gchar *help_description; |
|
101 |
|
102 GDestroyNotify destroy_notify; |
|
103 gpointer user_data; |
|
104 |
|
105 GTranslateFunc translate_func; |
|
106 GDestroyNotify translate_notify; |
|
107 gpointer translate_data; |
|
108 |
|
109 GOptionEntry *entries; |
|
110 gint n_entries; |
|
111 |
|
112 GOptionParseFunc pre_parse_func; |
|
113 GOptionParseFunc post_parse_func; |
|
114 GOptionErrorFunc error_func; |
|
115 }; |
|
116 |
|
117 static void free_changes_list (GOptionContext *context, |
|
118 gboolean revert); |
|
119 static void free_pending_nulls (GOptionContext *context, |
|
120 gboolean perform_nulls); |
|
121 |
|
122 #if EMULATOR |
|
123 |
|
124 PLS(q,g_option_error_quark,GQuark) |
|
125 #define q (*FUNCTION_NAME(q,g_option_error_quark)()) |
|
126 |
|
127 #endif /* EMULATOR */ |
|
128 |
|
129 EXPORT_C GQuark |
|
130 g_option_error_quark (void) |
|
131 { |
|
132 #if !(EMULATOR) |
|
133 static GQuark q = 0; |
|
134 #endif /* EMULATOR */ |
|
135 |
|
136 if (q == 0) |
|
137 q = g_quark_from_static_string ("g-option-context-error-quark"); |
|
138 |
|
139 return q; |
|
140 } |
|
141 |
|
142 #if EMULATOR |
|
143 #undef q |
|
144 #endif /* EMULATOR */ |
|
145 |
|
146 /** |
|
147 * g_option_context_new: |
|
148 * @parameter_string: a string which is displayed in |
|
149 * the first line of <option>--help</option> output, after the |
|
150 * usage summary |
|
151 * <literal><replaceable>programname</replaceable> [OPTION...]</literal>. |
|
152 * |
|
153 * Creates a new option context. |
|
154 * |
|
155 * The @parameter_text can serve multiple purposes. It can be used |
|
156 * to add descriptions for "rest" arguments, which are not parsed by |
|
157 * the #GOptionContext, typically something like "FILES" or |
|
158 * "FILE1 FILE2...". (If you are using #G_OPTION_REMAINING for |
|
159 * collecting "rest" arguments, GLib handles this automatically by |
|
160 * using the @arg_description of the corresponding #GOptionEntry in |
|
161 * the usage summary.) |
|
162 * |
|
163 * Another common usage is to give a summary of the program |
|
164 * functionality. This can be a short summary on the same line, |
|
165 * like " - frob the strings", or a longer description in a paragraph |
|
166 * below the usage summary. In this case, @parameter_string should start |
|
167 * with two newlines, to separate the description from the usage summary: |
|
168 * "\n\nA program to frob strings, which will..." |
|
169 * |
|
170 * Returns: a newly created #GOptionContext, which must be |
|
171 * freed with g_option_context_free() after use. |
|
172 * |
|
173 * Since: 2.6 |
|
174 */ |
|
175 EXPORT_C GOptionContext * |
|
176 g_option_context_new (const gchar *parameter_string) |
|
177 |
|
178 { |
|
179 GOptionContext *context; |
|
180 context = g_new0 (GOptionContext, 1); |
|
181 |
|
182 context->parameter_string = g_strdup (parameter_string); |
|
183 context->help_enabled = TRUE; |
|
184 context->ignore_unknown = FALSE; |
|
185 |
|
186 return context; |
|
187 } |
|
188 |
|
189 /** |
|
190 * g_option_context_free: |
|
191 * @context: a #GOptionContext |
|
192 * |
|
193 * Frees context and all the groups which have been |
|
194 * added to it. |
|
195 * |
|
196 * Since: 2.6 |
|
197 */ |
|
198 EXPORT_C void g_option_context_free (GOptionContext *context) |
|
199 { |
|
200 g_return_if_fail (context != NULL); |
|
201 |
|
202 g_list_foreach (context->groups, (GFunc)g_option_group_free, NULL); |
|
203 g_list_free (context->groups); |
|
204 |
|
205 if (context->main_group) |
|
206 g_option_group_free (context->main_group); |
|
207 |
|
208 free_changes_list (context, FALSE); |
|
209 free_pending_nulls (context, FALSE); |
|
210 |
|
211 g_free (context->parameter_string); |
|
212 |
|
213 g_free (context); |
|
214 } |
|
215 |
|
216 |
|
217 /** |
|
218 * g_option_context_set_help_enabled: |
|
219 * @context: a #GOptionContext |
|
220 * @help_enabled: %TRUE to enable <option>--help</option>, %FALSE to disable it |
|
221 * |
|
222 * Enables or disables automatic generation of <option>--help</option> |
|
223 * output. By default, g_option_context_parse() recognizes |
|
224 * <option>--help</option>, <option>-?</option>, <option>--help-all</option> |
|
225 * and <option>--help-</option><replaceable>groupname</replaceable> and creates |
|
226 * suitable output to stdout. |
|
227 * |
|
228 * Since: 2.6 |
|
229 */ |
|
230 EXPORT_C void g_option_context_set_help_enabled (GOptionContext *context, |
|
231 gboolean help_enabled) |
|
232 |
|
233 { |
|
234 g_return_if_fail (context != NULL); |
|
235 |
|
236 context->help_enabled = help_enabled; |
|
237 } |
|
238 |
|
239 /** |
|
240 * g_option_context_get_help_enabled: |
|
241 * @context: a #GOptionContext |
|
242 * |
|
243 * Returns whether automatic <option>--help</option> generation |
|
244 * is turned on for @context. See g_option_context_set_help_enabled(). |
|
245 * |
|
246 * Returns: %TRUE if automatic help generation is turned on. |
|
247 * |
|
248 * Since: 2.6 |
|
249 */ |
|
250 EXPORT_C gboolean |
|
251 g_option_context_get_help_enabled (GOptionContext *context) |
|
252 { |
|
253 g_return_val_if_fail (context != NULL, FALSE); |
|
254 |
|
255 return context->help_enabled; |
|
256 } |
|
257 |
|
258 /** |
|
259 * g_option_context_set_ignore_unknown_options: |
|
260 * @context: a #GOptionContext |
|
261 * @ignore_unknown: %TRUE to ignore unknown options, %FALSE to produce |
|
262 * an error when unknown options are met |
|
263 * |
|
264 * Sets whether to ignore unknown options or not. If an argument is |
|
265 * ignored, it is left in the @argv array after parsing. By default, |
|
266 * g_option_context_parse() treats unknown options as error. |
|
267 * |
|
268 * This setting does not affect non-option arguments (i.e. arguments |
|
269 * which don't start with a dash). But note that GOption cannot reliably |
|
270 * determine whether a non-option belongs to a preceding unknown option. |
|
271 * |
|
272 * Since: 2.6 |
|
273 **/ |
|
274 EXPORT_C void |
|
275 g_option_context_set_ignore_unknown_options (GOptionContext *context, |
|
276 gboolean ignore_unknown) |
|
277 { |
|
278 g_return_if_fail (context != NULL); |
|
279 |
|
280 context->ignore_unknown = ignore_unknown; |
|
281 } |
|
282 |
|
283 /** |
|
284 * g_option_context_get_ignore_unknown_options: |
|
285 * @context: a #GOptionContext |
|
286 * |
|
287 * Returns whether unknown options are ignored or not. See |
|
288 * g_option_context_set_ignore_unknown_options(). |
|
289 * |
|
290 * Returns: %TRUE if unknown options are ignored. |
|
291 * |
|
292 * Since: 2.6 |
|
293 **/ |
|
294 EXPORT_C gboolean |
|
295 g_option_context_get_ignore_unknown_options (GOptionContext *context) |
|
296 { |
|
297 g_return_val_if_fail (context != NULL, FALSE); |
|
298 |
|
299 return context->ignore_unknown; |
|
300 } |
|
301 |
|
302 /** |
|
303 * g_option_context_add_group: |
|
304 * @context: a #GOptionContext |
|
305 * @group: the group to add |
|
306 * |
|
307 * Adds a #GOptionGroup to the @context, so that parsing with @context |
|
308 * will recognize the options in the group. Note that the group will |
|
309 * be freed together with the context when g_option_context_free() is |
|
310 * called, so you must not free the group yourself after adding it |
|
311 * to a context. |
|
312 * |
|
313 * Since: 2.6 |
|
314 **/ |
|
315 EXPORT_C void |
|
316 g_option_context_add_group (GOptionContext *context, |
|
317 GOptionGroup *group) |
|
318 { |
|
319 GList *list; |
|
320 |
|
321 g_return_if_fail (context != NULL); |
|
322 g_return_if_fail (group != NULL); |
|
323 g_return_if_fail (group->name != NULL); |
|
324 g_return_if_fail (group->description != NULL); |
|
325 g_return_if_fail (group->help_description != NULL); |
|
326 |
|
327 for (list = context->groups; list; list = list->next) |
|
328 { |
|
329 GOptionGroup *g = (GOptionGroup *)list->data; |
|
330 |
|
331 if ((group->name == NULL && g->name == NULL) || |
|
332 (group->name && g->name && strcmp (group->name, g->name) == 0)) |
|
333 g_warning ("A group named \"%s\" is already part of this GOptionContext", |
|
334 group->name); |
|
335 } |
|
336 |
|
337 context->groups = g_list_append (context->groups, group); |
|
338 } |
|
339 |
|
340 /** |
|
341 * g_option_context_set_main_group: |
|
342 * @context: a #GOptionContext |
|
343 * @group: the group to set as main group |
|
344 * |
|
345 * Sets a #GOptionGroup as main group of the @context. |
|
346 * This has the same effect as calling g_option_context_add_group(), |
|
347 * the only difference is that the options in the main group are |
|
348 * treated differently when generating <option>--help</option> output. |
|
349 * |
|
350 * Since: 2.6 |
|
351 **/ |
|
352 EXPORT_C void |
|
353 g_option_context_set_main_group (GOptionContext *context, |
|
354 GOptionGroup *group) |
|
355 { |
|
356 g_return_if_fail (context != NULL); |
|
357 g_return_if_fail (group != NULL); |
|
358 |
|
359 if (context->main_group) |
|
360 { |
|
361 g_warning ("This GOptionContext already has a main group"); |
|
362 |
|
363 return; |
|
364 } |
|
365 |
|
366 context->main_group = group; |
|
367 } |
|
368 |
|
369 /** |
|
370 * g_option_context_get_main_group: |
|
371 * @context: a #GOptionContext |
|
372 * |
|
373 * Returns a pointer to the main group of @context. |
|
374 * |
|
375 * Return value: the main group of @context, or %NULL if @context doesn't |
|
376 * have a main group. Note that group belongs to @context and should |
|
377 * not be modified or freed. |
|
378 * |
|
379 * Since: 2.6 |
|
380 **/ |
|
381 EXPORT_C GOptionGroup * |
|
382 g_option_context_get_main_group (GOptionContext *context) |
|
383 { |
|
384 g_return_val_if_fail (context != NULL, NULL); |
|
385 |
|
386 return context->main_group; |
|
387 } |
|
388 |
|
389 /** |
|
390 * g_option_context_add_main_entries: |
|
391 * @context: a #GOptionContext |
|
392 * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s |
|
393 * @translation_domain: a translation domain to use for translating |
|
394 * the <option>--help</option> output for the options in @entries |
|
395 * with gettext(), or %NULL |
|
396 * |
|
397 * A convenience function which creates a main group if it doesn't |
|
398 * exist, adds the @entries to it and sets the translation domain. |
|
399 * |
|
400 * Since: 2.6 |
|
401 **/ |
|
402 EXPORT_C void |
|
403 g_option_context_add_main_entries (GOptionContext *context, |
|
404 const GOptionEntry *entries, |
|
405 const gchar *translation_domain) |
|
406 { |
|
407 g_return_if_fail (entries != NULL); |
|
408 |
|
409 if (!context->main_group) |
|
410 context->main_group = g_option_group_new (NULL, NULL, NULL, NULL, NULL); |
|
411 |
|
412 g_option_group_add_entries (context->main_group, entries); |
|
413 g_option_group_set_translation_domain (context->main_group, translation_domain); |
|
414 } |
|
415 |
|
416 static gint |
|
417 calculate_max_length (GOptionGroup *group) |
|
418 { |
|
419 GOptionEntry *entry; |
|
420 gint i, len, max_length; |
|
421 |
|
422 max_length = 0; |
|
423 |
|
424 for (i = 0; i < group->n_entries; i++) |
|
425 { |
|
426 entry = &group->entries[i]; |
|
427 |
|
428 if (entry->flags & G_OPTION_FLAG_HIDDEN) |
|
429 continue; |
|
430 |
|
431 len = g_utf8_strlen (entry->long_name, -1); |
|
432 |
|
433 if (entry->short_name) |
|
434 len += 4; |
|
435 |
|
436 if (!NO_ARG (entry) && entry->arg_description) |
|
437 len += 1 + g_utf8_strlen (TRANSLATE (group, entry->arg_description), -1); |
|
438 |
|
439 max_length = MAX (max_length, len); |
|
440 } |
|
441 |
|
442 return max_length; |
|
443 } |
|
444 |
|
445 static void |
|
446 print_entry (GOptionGroup *group, |
|
447 gint max_length, |
|
448 const GOptionEntry *entry) |
|
449 { |
|
450 GString *str; |
|
451 |
|
452 if (entry->flags & G_OPTION_FLAG_HIDDEN) |
|
453 return; |
|
454 |
|
455 if (entry->long_name[0] == 0) |
|
456 return; |
|
457 |
|
458 str = g_string_new (NULL); |
|
459 |
|
460 if (entry->short_name) |
|
461 g_string_append_printf (str, " -%c, --%s", entry->short_name, entry->long_name); |
|
462 else |
|
463 g_string_append_printf (str, " --%s", entry->long_name); |
|
464 |
|
465 if (entry->arg_description) |
|
466 g_string_append_printf (str, "=%s", TRANSLATE (group, entry->arg_description)); |
|
467 |
|
468 g_print ("%-*s %s\n", max_length + 4, str->str, |
|
469 entry->description ? TRANSLATE (group, entry->description) : ""); |
|
470 g_string_free (str, TRUE); |
|
471 } |
|
472 |
|
473 static void |
|
474 print_help (GOptionContext *context, |
|
475 gboolean main_help, |
|
476 GOptionGroup *group) |
|
477 { |
|
478 GList *list; |
|
479 gint max_length, len; |
|
480 gint i; |
|
481 GOptionEntry *entry; |
|
482 GHashTable *shadow_map; |
|
483 gboolean seen[256]; |
|
484 const gchar *rest_description; |
|
485 |
|
486 rest_description = NULL; |
|
487 if (context->main_group) |
|
488 { |
|
489 for (i = 0; i < context->main_group->n_entries; i++) |
|
490 { |
|
491 entry = &context->main_group->entries[i]; |
|
492 if (entry->long_name[0] == 0) |
|
493 { |
|
494 rest_description = entry->arg_description; |
|
495 break; |
|
496 } |
|
497 } |
|
498 } |
|
499 |
|
500 g_print ("%s\n %s %s%s%s%s%s\n\n", |
|
501 _("Usage:"), g_get_prgname(), _("[OPTION...]"), |
|
502 rest_description ? " " : "", |
|
503 rest_description ? rest_description : "", |
|
504 context->parameter_string ? " " : "", |
|
505 context->parameter_string ? context->parameter_string : ""); |
|
506 |
|
507 memset (seen, 0, sizeof (gboolean) * 256); |
|
508 shadow_map = g_hash_table_new (g_str_hash, g_str_equal); |
|
509 |
|
510 if (context->main_group) |
|
511 { |
|
512 for (i = 0; i < context->main_group->n_entries; i++) |
|
513 { |
|
514 entry = &context->main_group->entries[i]; |
|
515 g_hash_table_insert (shadow_map, |
|
516 (gpointer)entry->long_name, |
|
517 entry); |
|
518 |
|
519 if (seen[(guchar)entry->short_name]) |
|
520 entry->short_name = 0; |
|
521 else |
|
522 seen[(guchar)entry->short_name] = TRUE; |
|
523 } |
|
524 } |
|
525 |
|
526 list = context->groups; |
|
527 while (list != NULL) |
|
528 { |
|
529 GOptionGroup *group = list->data; |
|
530 for (i = 0; i < group->n_entries; i++) |
|
531 { |
|
532 entry = &group->entries[i]; |
|
533 if (g_hash_table_lookup (shadow_map, entry->long_name) && |
|
534 !(entry->flags && G_OPTION_FLAG_NOALIAS)) |
|
535 entry->long_name = g_strdup_printf ("%s-%s", group->name, entry->long_name); |
|
536 else |
|
537 g_hash_table_insert (shadow_map, (gpointer)entry->long_name, entry); |
|
538 |
|
539 if (seen[(guchar)entry->short_name] && |
|
540 !(entry->flags && G_OPTION_FLAG_NOALIAS)) |
|
541 entry->short_name = 0; |
|
542 else |
|
543 seen[(guchar)entry->short_name] = TRUE; |
|
544 } |
|
545 list = list->next; |
|
546 } |
|
547 |
|
548 g_hash_table_destroy (shadow_map); |
|
549 |
|
550 list = context->groups; |
|
551 |
|
552 max_length = g_utf8_strlen ("-?, --help", -1); |
|
553 |
|
554 if (list) |
|
555 { |
|
556 len = g_utf8_strlen ("--help-all", -1); |
|
557 max_length = MAX (max_length, len); |
|
558 } |
|
559 |
|
560 if (context->main_group) |
|
561 { |
|
562 len = calculate_max_length (context->main_group); |
|
563 max_length = MAX (max_length, len); |
|
564 } |
|
565 |
|
566 while (list != NULL) |
|
567 { |
|
568 GOptionGroup *group = list->data; |
|
569 |
|
570 /* First, we check the --help-<groupname> options */ |
|
571 len = g_utf8_strlen ("--help-", -1) + g_utf8_strlen (group->name, -1); |
|
572 max_length = MAX (max_length, len); |
|
573 |
|
574 /* Then we go through the entries */ |
|
575 len = calculate_max_length (group); |
|
576 max_length = MAX (max_length, len); |
|
577 |
|
578 list = list->next; |
|
579 } |
|
580 |
|
581 /* Add a bit of padding */ |
|
582 max_length += 4; |
|
583 |
|
584 if (!group) |
|
585 { |
|
586 list = context->groups; |
|
587 |
|
588 g_print ("%s\n -%c, --%-*s %s\n", |
|
589 _("Help Options:"), '?', max_length - 4, "help", |
|
590 _("Show help options")); |
|
591 |
|
592 /* We only want --help-all when there are groups */ |
|
593 if (list) |
|
594 g_print (" --%-*s %s\n", max_length, "help-all", |
|
595 _("Show all help options")); |
|
596 |
|
597 while (list) |
|
598 { |
|
599 GOptionGroup *group = list->data; |
|
600 |
|
601 g_print (" --help-%-*s %s\n", max_length - 5, group->name, |
|
602 TRANSLATE (group, group->help_description)); |
|
603 |
|
604 list = list->next; |
|
605 } |
|
606 |
|
607 g_print ("\n"); |
|
608 } |
|
609 |
|
610 if (group) |
|
611 { |
|
612 /* Print a certain group */ |
|
613 |
|
614 g_print ("%s\n", TRANSLATE (group, group->description)); |
|
615 for (i = 0; i < group->n_entries; i++) |
|
616 print_entry (group, max_length, &group->entries[i]); |
|
617 g_print ("\n"); |
|
618 } |
|
619 else if (!main_help) |
|
620 { |
|
621 /* Print all groups */ |
|
622 |
|
623 list = context->groups; |
|
624 |
|
625 while (list) |
|
626 { |
|
627 GOptionGroup *group = list->data; |
|
628 |
|
629 g_print ("%s\n", group->description); |
|
630 |
|
631 for (i = 0; i < group->n_entries; i++) |
|
632 if (!(group->entries[i].flags & G_OPTION_FLAG_IN_MAIN)) |
|
633 print_entry (group, max_length, &group->entries[i]); |
|
634 |
|
635 g_print ("\n"); |
|
636 list = list->next; |
|
637 } |
|
638 } |
|
639 |
|
640 /* Print application options if --help or --help-all has been specified */ |
|
641 if (main_help || !group) |
|
642 { |
|
643 list = context->groups; |
|
644 |
|
645 g_print ("%s\n", _("Application Options:")); |
|
646 |
|
647 if (context->main_group) |
|
648 for (i = 0; i < context->main_group->n_entries; i++) |
|
649 print_entry (context->main_group, max_length, |
|
650 &context->main_group->entries[i]); |
|
651 |
|
652 while (list != NULL) |
|
653 { |
|
654 GOptionGroup *group = list->data; |
|
655 |
|
656 /* Print main entries from other groups */ |
|
657 for (i = 0; i < group->n_entries; i++) |
|
658 if (group->entries[i].flags & G_OPTION_FLAG_IN_MAIN) |
|
659 print_entry (group, max_length, &group->entries[i]); |
|
660 |
|
661 list = list->next; |
|
662 } |
|
663 |
|
664 g_print ("\n"); |
|
665 } |
|
666 |
|
667 exit (0); |
|
668 } |
|
669 |
|
670 static gboolean |
|
671 parse_int (const gchar *arg_name, |
|
672 const gchar *arg, |
|
673 gint *result, |
|
674 GError **error) |
|
675 { |
|
676 gchar *end; |
|
677 glong tmp; |
|
678 |
|
679 errno = 0; |
|
680 tmp = strtol (arg, &end, 0); |
|
681 |
|
682 if (*arg == '\0' || *end != '\0') |
|
683 { |
|
684 g_set_error (error, |
|
685 G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, |
|
686 _("Cannot parse integer value '%s' for %s"), |
|
687 arg, arg_name); |
|
688 return FALSE; |
|
689 } |
|
690 |
|
691 *result = tmp; |
|
692 if (*result != tmp || errno == ERANGE) |
|
693 { |
|
694 g_set_error (error, |
|
695 G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, |
|
696 _("Integer value '%s' for %s out of range"), |
|
697 arg, arg_name); |
|
698 return FALSE; |
|
699 } |
|
700 |
|
701 return TRUE; |
|
702 } |
|
703 |
|
704 static Change * |
|
705 get_change (GOptionContext *context, |
|
706 GOptionArg arg_type, |
|
707 gpointer arg_data) |
|
708 { |
|
709 GList *list; |
|
710 Change *change = NULL; |
|
711 |
|
712 for (list = context->changes; list != NULL; list = list->next) |
|
713 { |
|
714 change = list->data; |
|
715 |
|
716 if (change->arg_data == arg_data) |
|
717 goto found; |
|
718 } |
|
719 change = g_new0 (Change, 1); |
|
720 change->arg_type = arg_type; |
|
721 change->arg_data = arg_data; |
|
722 |
|
723 context->changes = g_list_prepend (context->changes, change); |
|
724 |
|
725 found: |
|
726 |
|
727 return change; |
|
728 } |
|
729 |
|
730 static void |
|
731 add_pending_null (GOptionContext *context, |
|
732 gchar **ptr, |
|
733 gchar *value) |
|
734 { |
|
735 PendingNull *n; |
|
736 n = g_new0 (PendingNull, 1); |
|
737 n->ptr = ptr; |
|
738 n->value = value; |
|
739 |
|
740 context->pending_nulls = g_list_prepend (context->pending_nulls, n); |
|
741 } |
|
742 |
|
743 static gboolean |
|
744 parse_arg (GOptionContext *context, |
|
745 GOptionGroup *group, |
|
746 GOptionEntry *entry, |
|
747 const gchar *value, |
|
748 const gchar *option_name, |
|
749 GError **error) |
|
750 |
|
751 { |
|
752 Change *change; |
|
753 |
|
754 switch (entry->arg) |
|
755 { |
|
756 case G_OPTION_ARG_NONE: |
|
757 { |
|
758 change = get_change (context, G_OPTION_ARG_NONE, |
|
759 entry->arg_data); |
|
760 |
|
761 *(gboolean *)entry->arg_data = !(entry->flags & G_OPTION_FLAG_REVERSE); |
|
762 break; |
|
763 } |
|
764 case G_OPTION_ARG_STRING: |
|
765 { |
|
766 gchar *data; |
|
767 |
|
768 data = g_locale_to_utf8 (value, -1, NULL, NULL, error); |
|
769 |
|
770 if (!data) |
|
771 return FALSE; |
|
772 |
|
773 change = get_change (context, G_OPTION_ARG_STRING, |
|
774 entry->arg_data); |
|
775 g_free (change->allocated.str); |
|
776 |
|
777 change->prev.str = *(gchar **)entry->arg_data; |
|
778 change->allocated.str = data; |
|
779 |
|
780 *(gchar **)entry->arg_data = data; |
|
781 break; |
|
782 } |
|
783 case G_OPTION_ARG_STRING_ARRAY: |
|
784 { |
|
785 gchar *data; |
|
786 |
|
787 data = g_locale_to_utf8 (value, -1, NULL, NULL, error); |
|
788 |
|
789 if (!data) |
|
790 return FALSE; |
|
791 |
|
792 change = get_change (context, G_OPTION_ARG_STRING_ARRAY, |
|
793 entry->arg_data); |
|
794 |
|
795 if (change->allocated.array.len == 0) |
|
796 { |
|
797 change->prev.array = *(gchar ***)entry->arg_data; |
|
798 change->allocated.array.data = g_new (gchar *, 2); |
|
799 } |
|
800 else |
|
801 change->allocated.array.data = |
|
802 g_renew (gchar *, change->allocated.array.data, |
|
803 change->allocated.array.len + 2); |
|
804 |
|
805 |
|
806 change->allocated.array.data[change->allocated.array.len] = data; |
|
807 change->allocated.array.data[change->allocated.array.len + 1] = NULL; |
|
808 |
|
809 change->allocated.array.len ++; |
|
810 |
|
811 *(gchar ***)entry->arg_data = change->allocated.array.data; |
|
812 |
|
813 break; |
|
814 } |
|
815 |
|
816 case G_OPTION_ARG_FILENAME: |
|
817 { |
|
818 gchar *data; |
|
819 |
|
820 #ifdef G_OS_WIN32 |
|
821 data = g_locale_to_utf8 (value, -1, NULL, NULL, error); |
|
822 |
|
823 if (!data) |
|
824 return FALSE; |
|
825 #else |
|
826 data = g_strdup (value); |
|
827 #endif |
|
828 change = get_change (context, G_OPTION_ARG_FILENAME, |
|
829 entry->arg_data); |
|
830 g_free (change->allocated.str); |
|
831 |
|
832 change->prev.str = *(gchar **)entry->arg_data; |
|
833 change->allocated.str = data; |
|
834 |
|
835 *(gchar **)entry->arg_data = data; |
|
836 break; |
|
837 } |
|
838 |
|
839 case G_OPTION_ARG_FILENAME_ARRAY: |
|
840 { |
|
841 gchar *data; |
|
842 |
|
843 #ifdef G_OS_WIN32 |
|
844 data = g_locale_to_utf8 (value, -1, NULL, NULL, error); |
|
845 |
|
846 if (!data) |
|
847 return FALSE; |
|
848 #else |
|
849 data = g_strdup (value); |
|
850 #endif |
|
851 change = get_change (context, G_OPTION_ARG_STRING_ARRAY, |
|
852 entry->arg_data); |
|
853 |
|
854 if (change->allocated.array.len == 0) |
|
855 { |
|
856 change->prev.array = *(gchar ***)entry->arg_data; |
|
857 change->allocated.array.data = g_new (gchar *, 2); |
|
858 |
|
859 } |
|
860 else |
|
861 change->allocated.array.data = |
|
862 g_renew (gchar *, change->allocated.array.data, |
|
863 change->allocated.array.len + 2); |
|
864 |
|
865 change->allocated.array.data[change->allocated.array.len] = data; |
|
866 change->allocated.array.data[change->allocated.array.len + 1] = NULL; |
|
867 |
|
868 change->allocated.array.len ++; |
|
869 |
|
870 *(gchar ***)entry->arg_data = change->allocated.array.data; |
|
871 |
|
872 break; |
|
873 } |
|
874 |
|
875 case G_OPTION_ARG_INT: |
|
876 { |
|
877 gint data; |
|
878 |
|
879 if (!parse_int (option_name, value, |
|
880 &data, |
|
881 error)) |
|
882 return FALSE; |
|
883 |
|
884 change = get_change (context, G_OPTION_ARG_INT, |
|
885 entry->arg_data); |
|
886 change->prev.integer = *(gint *)entry->arg_data; |
|
887 *(gint *)entry->arg_data = data; |
|
888 break; |
|
889 } |
|
890 case G_OPTION_ARG_CALLBACK: |
|
891 { |
|
892 gchar *data; |
|
893 gboolean retval; |
|
894 |
|
895 if (!value && entry->flags & G_OPTION_FLAG_OPTIONAL_ARG) |
|
896 data = NULL; |
|
897 else if (entry->flags & G_OPTION_FLAG_NO_ARG) |
|
898 data = NULL; |
|
899 else if (entry->flags & G_OPTION_FLAG_FILENAME) |
|
900 { |
|
901 #ifdef G_OS_WIN32 |
|
902 data = g_locale_to_utf8 (value, -1, NULL, NULL, error); |
|
903 #else |
|
904 data = g_strdup (value); |
|
905 #endif |
|
906 } |
|
907 else |
|
908 data = g_locale_to_utf8 (value, -1, NULL, NULL, error); |
|
909 |
|
910 if (!(entry->flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG)) && |
|
911 !data) |
|
912 return FALSE; |
|
913 |
|
914 retval = (* (GOptionArgFunc) entry->arg_data) (option_name, data, group->user_data, error); |
|
915 |
|
916 g_free (data); |
|
917 |
|
918 return retval; |
|
919 |
|
920 break; |
|
921 } |
|
922 default: |
|
923 g_assert_not_reached (); |
|
924 } |
|
925 |
|
926 return TRUE; |
|
927 } |
|
928 |
|
929 static gboolean |
|
930 parse_short_option (GOptionContext *context, |
|
931 GOptionGroup *group, |
|
932 gint index, |
|
933 gint *new_index, |
|
934 gchar arg, |
|
935 gint *argc, |
|
936 gchar ***argv, |
|
937 GError **error, |
|
938 gboolean *parsed) |
|
939 { |
|
940 gint j; |
|
941 |
|
942 for (j = 0; j < group->n_entries; j++) |
|
943 { |
|
944 if (arg == group->entries[j].short_name) |
|
945 { |
|
946 gchar *option_name; |
|
947 gchar *value = NULL; |
|
948 |
|
949 option_name = g_strdup_printf ("-%c", group->entries[j].short_name); |
|
950 |
|
951 if (NO_ARG (&group->entries[j])) |
|
952 value = NULL; |
|
953 else |
|
954 { |
|
955 if (*new_index > index) |
|
956 { |
|
957 g_set_error (error, |
|
958 G_OPTION_ERROR, G_OPTION_ERROR_FAILED, |
|
959 _("Error parsing option %s"), option_name); |
|
960 g_free (option_name); |
|
961 return FALSE; |
|
962 } |
|
963 |
|
964 if (index < *argc - 1) |
|
965 { |
|
966 if (!OPTIONAL_ARG (&group->entries[j])) |
|
967 { |
|
968 value = (*argv)[index + 1]; |
|
969 add_pending_null (context, &((*argv)[index + 1]), NULL); |
|
970 *new_index = index+1; |
|
971 } |
|
972 else |
|
973 { |
|
974 if ((*argv)[index + 1][0] == '-') |
|
975 value = NULL; |
|
976 else |
|
977 { |
|
978 value = (*argv)[index + 1]; |
|
979 add_pending_null (context, &((*argv)[index + 1]), NULL); |
|
980 *new_index = index + 1; |
|
981 } |
|
982 } |
|
983 } |
|
984 else if (index >= *argc - 1 && OPTIONAL_ARG (&group->entries[j])) |
|
985 value = NULL; |
|
986 else |
|
987 { |
|
988 g_set_error (error, |
|
989 G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, |
|
990 _("Missing argument for %s"), option_name); |
|
991 g_free (option_name); |
|
992 return FALSE; |
|
993 } |
|
994 } |
|
995 |
|
996 if (!parse_arg (context, group, &group->entries[j], |
|
997 value, option_name, error)) |
|
998 { |
|
999 g_free (option_name); |
|
1000 return FALSE; |
|
1001 } |
|
1002 |
|
1003 g_free (option_name); |
|
1004 *parsed = TRUE; |
|
1005 } |
|
1006 } |
|
1007 |
|
1008 return TRUE; |
|
1009 } |
|
1010 |
|
1011 static gboolean |
|
1012 parse_long_option (GOptionContext *context, |
|
1013 GOptionGroup *group, |
|
1014 gint *index, |
|
1015 gchar *arg, |
|
1016 gboolean aliased, |
|
1017 gint *argc, |
|
1018 gchar ***argv, |
|
1019 GError **error, |
|
1020 gboolean *parsed) |
|
1021 { |
|
1022 gint j; |
|
1023 |
|
1024 for (j = 0; j < group->n_entries; j++) |
|
1025 { |
|
1026 if (*index >= *argc) |
|
1027 return TRUE; |
|
1028 |
|
1029 if (aliased && (group->entries[j].flags & G_OPTION_FLAG_NOALIAS)) |
|
1030 continue; |
|
1031 |
|
1032 if (NO_ARG (&group->entries[j]) && |
|
1033 strcmp (arg, group->entries[j].long_name) == 0) |
|
1034 { |
|
1035 gchar *option_name; |
|
1036 |
|
1037 option_name = g_strconcat ("--", group->entries[j].long_name, NULL); |
|
1038 parse_arg (context, group, &group->entries[j], |
|
1039 NULL, option_name, error); |
|
1040 g_free(option_name); |
|
1041 |
|
1042 add_pending_null (context, &((*argv)[*index]), NULL); |
|
1043 *parsed = TRUE; |
|
1044 } |
|
1045 else |
|
1046 { |
|
1047 gint len = strlen (group->entries[j].long_name); |
|
1048 |
|
1049 if (strncmp (arg, group->entries[j].long_name, len) == 0 && |
|
1050 (arg[len] == '=' || arg[len] == 0)) |
|
1051 { |
|
1052 gchar *value = NULL; |
|
1053 gchar *option_name; |
|
1054 |
|
1055 add_pending_null (context, &((*argv)[*index]), NULL); |
|
1056 option_name = g_strconcat ("--", group->entries[j].long_name, NULL); |
|
1057 |
|
1058 if (arg[len] == '=') |
|
1059 value = arg + len + 1; |
|
1060 else if (*index < *argc - 1) |
|
1061 { |
|
1062 if (!(group->entries[j].flags & G_OPTION_FLAG_OPTIONAL_ARG)) |
|
1063 { |
|
1064 value = (*argv)[*index + 1]; |
|
1065 add_pending_null (context, &((*argv)[*index + 1]), NULL); |
|
1066 (*index)++; |
|
1067 } |
|
1068 else |
|
1069 { |
|
1070 if ((*argv)[*index + 1][0] == '-') |
|
1071 { |
|
1072 gboolean retval; |
|
1073 retval = parse_arg (context, group, &group->entries[j], |
|
1074 NULL, option_name, error); |
|
1075 *parsed = TRUE; |
|
1076 g_free (option_name); |
|
1077 return retval; |
|
1078 } |
|
1079 else |
|
1080 { |
|
1081 value = (*argv)[*index + 1]; |
|
1082 add_pending_null (context, &((*argv)[*index + 1]), NULL); |
|
1083 (*index)++; |
|
1084 } |
|
1085 } |
|
1086 } |
|
1087 else if (*index >= *argc - 1 && |
|
1088 group->entries[j].flags & G_OPTION_FLAG_OPTIONAL_ARG) |
|
1089 { |
|
1090 gboolean retval; |
|
1091 retval = parse_arg (context, group, &group->entries[j], |
|
1092 NULL, option_name, error); |
|
1093 *parsed = TRUE; |
|
1094 g_free (option_name); |
|
1095 return retval; |
|
1096 } |
|
1097 else |
|
1098 { |
|
1099 g_set_error (error, |
|
1100 G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, |
|
1101 _("Missing argument for %s"), option_name); |
|
1102 g_free (option_name); |
|
1103 return FALSE; |
|
1104 } |
|
1105 |
|
1106 if (!parse_arg (context, group, &group->entries[j], |
|
1107 value, option_name, error)) |
|
1108 { |
|
1109 g_free (option_name); |
|
1110 return FALSE; |
|
1111 } |
|
1112 |
|
1113 g_free (option_name); |
|
1114 *parsed = TRUE; |
|
1115 } |
|
1116 } |
|
1117 } |
|
1118 |
|
1119 return TRUE; |
|
1120 } |
|
1121 |
|
1122 static gboolean |
|
1123 parse_remaining_arg (GOptionContext *context, |
|
1124 GOptionGroup *group, |
|
1125 gint *index, |
|
1126 gint *argc, |
|
1127 gchar ***argv, |
|
1128 GError **error, |
|
1129 gboolean *parsed) |
|
1130 { |
|
1131 gint j; |
|
1132 |
|
1133 for (j = 0; j < group->n_entries; j++) |
|
1134 { |
|
1135 if (*index >= *argc) |
|
1136 return TRUE; |
|
1137 |
|
1138 if (group->entries[j].long_name[0]) |
|
1139 continue; |
|
1140 |
|
1141 g_return_val_if_fail (group->entries[j].arg == G_OPTION_ARG_STRING_ARRAY || |
|
1142 group->entries[j].arg == G_OPTION_ARG_FILENAME_ARRAY, FALSE); |
|
1143 |
|
1144 add_pending_null (context, &((*argv)[*index]), NULL); |
|
1145 |
|
1146 if (!parse_arg (context, group, &group->entries[j], (*argv)[*index], "", error)) |
|
1147 return FALSE; |
|
1148 |
|
1149 *parsed = TRUE; |
|
1150 return TRUE; |
|
1151 } |
|
1152 |
|
1153 return TRUE; |
|
1154 } |
|
1155 |
|
1156 static void |
|
1157 free_changes_list (GOptionContext *context, |
|
1158 gboolean revert) |
|
1159 { |
|
1160 GList *list; |
|
1161 |
|
1162 for (list = context->changes; list != NULL; list = list->next) |
|
1163 { |
|
1164 Change *change = list->data; |
|
1165 |
|
1166 if (revert) |
|
1167 { |
|
1168 switch (change->arg_type) |
|
1169 { |
|
1170 case G_OPTION_ARG_NONE: |
|
1171 *(gboolean *)change->arg_data = change->prev.bool; |
|
1172 break; |
|
1173 case G_OPTION_ARG_INT: |
|
1174 *(gint *)change->arg_data = change->prev.integer; |
|
1175 break; |
|
1176 case G_OPTION_ARG_STRING: |
|
1177 case G_OPTION_ARG_FILENAME: |
|
1178 g_free (change->allocated.str); |
|
1179 *(gchar **)change->arg_data = change->prev.str; |
|
1180 break; |
|
1181 case G_OPTION_ARG_STRING_ARRAY: |
|
1182 case G_OPTION_ARG_FILENAME_ARRAY: |
|
1183 g_strfreev (change->allocated.array.data); |
|
1184 *(gchar ***)change->arg_data = change->prev.array; |
|
1185 break; |
|
1186 default: |
|
1187 g_assert_not_reached (); |
|
1188 } |
|
1189 } |
|
1190 |
|
1191 g_free (change); |
|
1192 } |
|
1193 |
|
1194 g_list_free (context->changes); |
|
1195 context->changes = NULL; |
|
1196 } |
|
1197 |
|
1198 static void |
|
1199 free_pending_nulls (GOptionContext *context, |
|
1200 gboolean perform_nulls) |
|
1201 { |
|
1202 GList *list; |
|
1203 |
|
1204 for (list = context->pending_nulls; list != NULL; list = list->next) |
|
1205 { |
|
1206 PendingNull *n = list->data; |
|
1207 |
|
1208 if (perform_nulls) |
|
1209 { |
|
1210 if (n->value) |
|
1211 { |
|
1212 /* Copy back the short options */ |
|
1213 *(n->ptr)[0] = '-'; |
|
1214 strcpy (*n->ptr + 1, n->value); |
|
1215 } |
|
1216 else |
|
1217 *n->ptr = NULL; |
|
1218 } |
|
1219 |
|
1220 g_free (n->value); |
|
1221 g_free (n); |
|
1222 } |
|
1223 |
|
1224 g_list_free (context->pending_nulls); |
|
1225 context->pending_nulls = NULL; |
|
1226 } |
|
1227 |
|
1228 /** |
|
1229 * g_option_context_parse: |
|
1230 * @context: a #GOptionContext |
|
1231 * @argc: a pointer to the number of command line arguments. |
|
1232 * @argv: a pointer to the array of command line arguments. |
|
1233 * @error: a return location for errors |
|
1234 * |
|
1235 * Parses the command line arguments, recognizing options |
|
1236 * which have been added to @context. A side-effect of |
|
1237 * calling this function is that g_set_prgname() will be |
|
1238 * called. |
|
1239 * |
|
1240 * If the parsing is successful, any parsed arguments are |
|
1241 * removed from the array and @argc and @argv are updated |
|
1242 * accordingly. A '--' option is stripped from @argv |
|
1243 * unless there are unparsed options before and after it, |
|
1244 * or some of the options after it start with '-'. In case |
|
1245 * of an error, @argc and @argv are left unmodified. |
|
1246 * |
|
1247 * If automatic <option>--help</option> support is enabled |
|
1248 * (see g_option_context_set_help_enabled()), and the |
|
1249 * @argv array contains one of the recognized help options, |
|
1250 * this function will produce help output to stdout and |
|
1251 * call <literal>exit (0)</literal>. |
|
1252 * |
|
1253 * Return value: %TRUE if the parsing was successful, |
|
1254 * %FALSE if an error occurred |
|
1255 * |
|
1256 * Since: 2.6 |
|
1257 **/ |
|
1258 EXPORT_C gboolean |
|
1259 g_option_context_parse (GOptionContext *context, |
|
1260 gint *argc, |
|
1261 gchar ***argv, |
|
1262 GError **error) |
|
1263 { |
|
1264 gint i, j, k; |
|
1265 GList *list; |
|
1266 |
|
1267 /* Set program name */ |
|
1268 if (!g_get_prgname()) |
|
1269 { |
|
1270 if (argc && argv && *argc) |
|
1271 { |
|
1272 gchar *prgname; |
|
1273 |
|
1274 prgname = g_path_get_basename ((*argv)[0]); |
|
1275 g_set_prgname (prgname); |
|
1276 g_free (prgname); |
|
1277 } |
|
1278 else |
|
1279 g_set_prgname ("<unknown>"); |
|
1280 } |
|
1281 |
|
1282 /* Call pre-parse hooks */ |
|
1283 list = context->groups; |
|
1284 while (list) |
|
1285 { |
|
1286 GOptionGroup *group = list->data; |
|
1287 |
|
1288 if (group->pre_parse_func) |
|
1289 { |
|
1290 if (!(* group->pre_parse_func) (context, group, |
|
1291 group->user_data, error)) |
|
1292 goto fail; |
|
1293 } |
|
1294 |
|
1295 list = list->next; |
|
1296 } |
|
1297 |
|
1298 if (context->main_group && context->main_group->pre_parse_func) |
|
1299 { |
|
1300 if (!(* context->main_group->pre_parse_func) (context, context->main_group, |
|
1301 context->main_group->user_data, error)) |
|
1302 goto fail; |
|
1303 } |
|
1304 |
|
1305 if (argc && argv) |
|
1306 { |
|
1307 gboolean stop_parsing = FALSE; |
|
1308 gboolean has_unknown = FALSE; |
|
1309 gint separator_pos = 0; |
|
1310 |
|
1311 for (i = 1; i < *argc; i++) |
|
1312 { |
|
1313 gchar *arg, *dash; |
|
1314 gboolean parsed = FALSE; |
|
1315 |
|
1316 if ((*argv)[i][0] == '-' && (*argv)[i][1] != '\0' && !stop_parsing) |
|
1317 { |
|
1318 if ((*argv)[i][1] == '-') |
|
1319 { |
|
1320 /* -- option */ |
|
1321 |
|
1322 arg = (*argv)[i] + 2; |
|
1323 |
|
1324 /* '--' terminates list of arguments */ |
|
1325 if (*arg == 0) |
|
1326 { |
|
1327 separator_pos = i; |
|
1328 stop_parsing = TRUE; |
|
1329 continue; |
|
1330 } |
|
1331 |
|
1332 /* Handle help options */ |
|
1333 if (context->help_enabled) |
|
1334 { |
|
1335 if (strcmp (arg, "help") == 0) |
|
1336 print_help (context, TRUE, NULL); |
|
1337 else if (strcmp (arg, "help-all") == 0) |
|
1338 print_help (context, FALSE, NULL); |
|
1339 else if (strncmp (arg, "help-", 5) == 0) |
|
1340 { |
|
1341 GList *list; |
|
1342 |
|
1343 list = context->groups; |
|
1344 |
|
1345 while (list) |
|
1346 { |
|
1347 GOptionGroup *group = list->data; |
|
1348 |
|
1349 if (strcmp (arg + 5, group->name) == 0) |
|
1350 print_help (context, FALSE, group); |
|
1351 |
|
1352 list = list->next; |
|
1353 } |
|
1354 } |
|
1355 } |
|
1356 |
|
1357 if (context->main_group && |
|
1358 !parse_long_option (context, context->main_group, &i, arg, |
|
1359 FALSE, argc, argv, error, &parsed)) |
|
1360 goto fail; |
|
1361 |
|
1362 if (parsed) |
|
1363 continue; |
|
1364 |
|
1365 /* Try the groups */ |
|
1366 list = context->groups; |
|
1367 while (list) |
|
1368 { |
|
1369 GOptionGroup *group = list->data; |
|
1370 |
|
1371 if (!parse_long_option (context, group, &i, arg, |
|
1372 FALSE, argc, argv, error, &parsed)) |
|
1373 goto fail; |
|
1374 |
|
1375 if (parsed) |
|
1376 break; |
|
1377 |
|
1378 list = list->next; |
|
1379 } |
|
1380 |
|
1381 if (parsed) |
|
1382 continue; |
|
1383 |
|
1384 /* Now look for --<group>-<option> */ |
|
1385 dash = strchr (arg, '-'); |
|
1386 if (dash) |
|
1387 { |
|
1388 /* Try the groups */ |
|
1389 list = context->groups; |
|
1390 while (list) |
|
1391 { |
|
1392 GOptionGroup *group = list->data; |
|
1393 |
|
1394 if (strncmp (group->name, arg, dash - arg) == 0) |
|
1395 { |
|
1396 if (!parse_long_option (context, group, &i, dash + 1, |
|
1397 TRUE, argc, argv, error, &parsed)) |
|
1398 goto fail; |
|
1399 |
|
1400 if (parsed) |
|
1401 break; |
|
1402 } |
|
1403 |
|
1404 list = list->next; |
|
1405 } |
|
1406 } |
|
1407 |
|
1408 if (context->ignore_unknown) |
|
1409 continue; |
|
1410 } |
|
1411 else |
|
1412 { /* short option */ |
|
1413 gint j, new_i = i, arg_length; |
|
1414 gboolean *nulled_out = NULL; |
|
1415 arg = (*argv)[i] + 1; |
|
1416 arg_length = strlen (arg); |
|
1417 |
|
1418 #ifndef __SYMBIAN32__ |
|
1419 |
|
1420 nulled_out = g_newa (gboolean, arg_length); |
|
1421 memset (nulled_out, 0, arg_length * sizeof (gboolean)); |
|
1422 |
|
1423 #else |
|
1424 |
|
1425 nulled_out = g_new0 (gboolean, arg_length); |
|
1426 |
|
1427 #endif /* __SYMBIAN32__*/ |
|
1428 |
|
1429 for (j = 0; j < arg_length; j++) |
|
1430 { |
|
1431 if (context->help_enabled && arg[j] == '?') |
|
1432 print_help (context, TRUE, NULL); |
|
1433 parsed = FALSE; |
|
1434 if (context->main_group && |
|
1435 !parse_short_option (context, context->main_group, |
|
1436 i, &new_i, arg[j], |
|
1437 argc, argv, error, &parsed)) |
|
1438 goto fail; |
|
1439 if (!parsed) |
|
1440 { |
|
1441 /* Try the groups */ |
|
1442 list = context->groups; |
|
1443 while (list) |
|
1444 { |
|
1445 GOptionGroup *group = list->data; |
|
1446 if (!parse_short_option (context, group, i, &new_i, arg[j], |
|
1447 argc, argv, error, &parsed)) |
|
1448 goto fail; |
|
1449 if (parsed) |
|
1450 break; |
|
1451 list = list->next; |
|
1452 } |
|
1453 } |
|
1454 |
|
1455 if (context->ignore_unknown && parsed) |
|
1456 nulled_out[j] = TRUE; |
|
1457 else if (context->ignore_unknown) |
|
1458 continue; |
|
1459 else if (!parsed) |
|
1460 break; |
|
1461 /* !context->ignore_unknown && parsed */ |
|
1462 } |
|
1463 if (context->ignore_unknown) |
|
1464 { |
|
1465 gchar *new_arg = NULL; |
|
1466 gint arg_index = 0; |
|
1467 for (j = 0; j < arg_length; j++) |
|
1468 { |
|
1469 if (!nulled_out[j]) |
|
1470 { |
|
1471 if (!new_arg) |
|
1472 new_arg = g_malloc (arg_length + 1); |
|
1473 new_arg[arg_index++] = arg[j]; |
|
1474 } |
|
1475 } |
|
1476 if (new_arg) |
|
1477 new_arg[arg_index] = '\0'; |
|
1478 add_pending_null (context, &((*argv)[i]), new_arg); |
|
1479 } |
|
1480 else if (parsed) |
|
1481 { |
|
1482 add_pending_null (context, &((*argv)[i]), NULL); |
|
1483 i = new_i; |
|
1484 } |
|
1485 #ifdef __SYMBIAN32__ |
|
1486 g_free(nulled_out); |
|
1487 #endif /* __SYMBIAN32__ */ |
|
1488 } |
|
1489 |
|
1490 if (!parsed) |
|
1491 has_unknown = TRUE; |
|
1492 |
|
1493 if (!parsed && !context->ignore_unknown) |
|
1494 { |
|
1495 g_set_error (error, |
|
1496 G_OPTION_ERROR, G_OPTION_ERROR_UNKNOWN_OPTION, |
|
1497 _("Unknown option %s"), (*argv)[i]); |
|
1498 goto fail; |
|
1499 } |
|
1500 } |
|
1501 else |
|
1502 { |
|
1503 /* Collect remaining args */ |
|
1504 if (context->main_group && |
|
1505 !parse_remaining_arg (context, context->main_group, &i, |
|
1506 argc, argv, error, &parsed)) |
|
1507 goto fail; |
|
1508 |
|
1509 if (!parsed && (has_unknown || (*argv)[i][0] == '-')) |
|
1510 separator_pos = 0; |
|
1511 } |
|
1512 } |
|
1513 |
|
1514 if (separator_pos > 0) |
|
1515 add_pending_null (context, &((*argv)[separator_pos]), NULL); |
|
1516 |
|
1517 } |
|
1518 |
|
1519 /* Call post-parse hooks */ |
|
1520 list = context->groups; |
|
1521 while (list) |
|
1522 { |
|
1523 GOptionGroup *group = list->data; |
|
1524 |
|
1525 if (group->post_parse_func) |
|
1526 { |
|
1527 if (!(* group->post_parse_func) (context, group, |
|
1528 group->user_data, error)) |
|
1529 goto fail; |
|
1530 } |
|
1531 |
|
1532 list = list->next; |
|
1533 } |
|
1534 |
|
1535 if (context->main_group && context->main_group->post_parse_func) |
|
1536 { |
|
1537 if (!(* context->main_group->post_parse_func) (context, context->main_group, |
|
1538 context->main_group->user_data, error)) |
|
1539 goto fail; |
|
1540 } |
|
1541 |
|
1542 if (argc && argv) |
|
1543 { |
|
1544 free_pending_nulls (context, TRUE); |
|
1545 |
|
1546 for (i = 1; i < *argc; i++) |
|
1547 { |
|
1548 for (k = i; k < *argc; k++) |
|
1549 if ((*argv)[k] != NULL) |
|
1550 break; |
|
1551 |
|
1552 if (k > i) |
|
1553 { |
|
1554 k -= i; |
|
1555 for (j = i + k; j < *argc; j++) |
|
1556 { |
|
1557 (*argv)[j-k] = (*argv)[j]; |
|
1558 (*argv)[j] = NULL; |
|
1559 } |
|
1560 *argc -= k; |
|
1561 } |
|
1562 } |
|
1563 } |
|
1564 |
|
1565 return TRUE; |
|
1566 |
|
1567 fail: |
|
1568 |
|
1569 /* Call error hooks */ |
|
1570 list = context->groups; |
|
1571 while (list) |
|
1572 { |
|
1573 GOptionGroup *group = list->data; |
|
1574 |
|
1575 if (group->error_func) |
|
1576 (* group->error_func) (context, group, |
|
1577 group->user_data, error); |
|
1578 |
|
1579 list = list->next; |
|
1580 } |
|
1581 |
|
1582 if (context->main_group && context->main_group->error_func) |
|
1583 (* context->main_group->error_func) (context, context->main_group, |
|
1584 context->main_group->user_data, error); |
|
1585 |
|
1586 free_changes_list (context, TRUE); |
|
1587 free_pending_nulls (context, FALSE); |
|
1588 |
|
1589 return FALSE; |
|
1590 } |
|
1591 |
|
1592 /** |
|
1593 * g_option_group_new: |
|
1594 * @name: the name for the option group, this is used to provide |
|
1595 * help for the options in this group with <option>--help-</option>@name |
|
1596 * @description: a description for this group to be shown in |
|
1597 * <option>--help</option>. This string is translated using the translation |
|
1598 * domain or translation function of the group |
|
1599 * @help_description: a description for the <option>--help-</option>@name option. |
|
1600 * This string is translated using the translation domain or translation function |
|
1601 * of the group |
|
1602 * @user_data: user data that will be passed to the pre- and post-parse hooks, |
|
1603 * the error hook and to callbacks of %G_OPTION_ARG_CALLBACK options, or %NULL |
|
1604 * @destroy: a function that will be called to free @user_data, or %NULL |
|
1605 * |
|
1606 * Creates a new #GOptionGroup. |
|
1607 * |
|
1608 * Return value: a newly created option group. It should be added |
|
1609 * to a #GOptionContext or freed with g_option_group_free(). |
|
1610 * |
|
1611 * Since: 2.6 |
|
1612 **/ |
|
1613 EXPORT_C GOptionGroup * |
|
1614 g_option_group_new (const gchar *name, |
|
1615 const gchar *description, |
|
1616 const gchar *help_description, |
|
1617 gpointer user_data, |
|
1618 GDestroyNotify destroy) |
|
1619 |
|
1620 { |
|
1621 GOptionGroup *group; |
|
1622 group = g_new0 (GOptionGroup, 1); |
|
1623 group->name = g_strdup (name); |
|
1624 group->description = g_strdup (description); |
|
1625 group->help_description = g_strdup (help_description); |
|
1626 group->user_data = user_data; |
|
1627 group->destroy_notify = destroy; |
|
1628 |
|
1629 return group; |
|
1630 } |
|
1631 |
|
1632 |
|
1633 /** |
|
1634 * g_option_group_free: |
|
1635 * @group: a #GOptionGroup |
|
1636 * |
|
1637 * Frees a #GOptionGroup. Note that you must <emphasis>not</emphasis> |
|
1638 * free groups which have been added to a #GOptionContext. |
|
1639 * |
|
1640 * Since: 2.6 |
|
1641 **/ |
|
1642 EXPORT_C void |
|
1643 g_option_group_free (GOptionGroup *group) |
|
1644 { |
|
1645 g_return_if_fail (group != NULL); |
|
1646 |
|
1647 g_free (group->name); |
|
1648 g_free (group->description); |
|
1649 g_free (group->help_description); |
|
1650 |
|
1651 g_free (group->entries); |
|
1652 |
|
1653 if (group->destroy_notify) |
|
1654 (* group->destroy_notify) (group->user_data); |
|
1655 |
|
1656 if (group->translate_notify) |
|
1657 (* group->translate_notify) (group->translate_data); |
|
1658 |
|
1659 g_free (group); |
|
1660 } |
|
1661 |
|
1662 |
|
1663 /** |
|
1664 * g_option_group_add_entries: |
|
1665 * @group: a #GOptionGroup |
|
1666 * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s |
|
1667 * |
|
1668 * Adds the options specified in @entries to @group. |
|
1669 * |
|
1670 * Since: 2.6 |
|
1671 **/ |
|
1672 EXPORT_C void |
|
1673 g_option_group_add_entries (GOptionGroup *group, |
|
1674 const GOptionEntry *entries) |
|
1675 { |
|
1676 gint i, n_entries; |
|
1677 |
|
1678 g_return_if_fail (entries != NULL); |
|
1679 |
|
1680 for (n_entries = 0; entries[n_entries].long_name != NULL; n_entries++) ; |
|
1681 group->entries = g_renew (GOptionEntry, group->entries, group->n_entries + n_entries); |
|
1682 |
|
1683 |
|
1684 memcpy (group->entries + group->n_entries, entries, sizeof (GOptionEntry) * n_entries); |
|
1685 |
|
1686 for (i = group->n_entries; i < group->n_entries + n_entries; i++) |
|
1687 { |
|
1688 gchar c = group->entries[i].short_name; |
|
1689 |
|
1690 if (c) |
|
1691 { |
|
1692 if (c == '-' || !g_ascii_isprint (c)) |
|
1693 { |
|
1694 g_warning (G_STRLOC": ignoring invalid short option '%c' (%d)", c, c); |
|
1695 group->entries[i].short_name = 0; |
|
1696 } |
|
1697 } |
|
1698 } |
|
1699 |
|
1700 group->n_entries += n_entries; |
|
1701 } |
|
1702 |
|
1703 /** |
|
1704 * g_option_group_set_parse_hooks: |
|
1705 * @group: a #GOptionGroup |
|
1706 * @pre_parse_func: a function to call before parsing, or %NULL |
|
1707 * @post_parse_func: a function to call after parsing, or %NULL |
|
1708 * |
|
1709 * Associates two functions with @group which will be called |
|
1710 * from g_option_context_parse() before the first option is parsed |
|
1711 * and after the last option has been parsed, respectively. |
|
1712 * |
|
1713 * Note that the user data to be passed to @pre_parse_func and |
|
1714 * @post_parse_func can be specified when constructing the group |
|
1715 * with g_option_group_new(). |
|
1716 * |
|
1717 * Since: 2.6 |
|
1718 **/ |
|
1719 EXPORT_C void |
|
1720 g_option_group_set_parse_hooks (GOptionGroup *group, |
|
1721 GOptionParseFunc pre_parse_func, |
|
1722 GOptionParseFunc post_parse_func) |
|
1723 { |
|
1724 g_return_if_fail (group != NULL); |
|
1725 |
|
1726 group->pre_parse_func = pre_parse_func; |
|
1727 group->post_parse_func = post_parse_func; |
|
1728 } |
|
1729 |
|
1730 /** |
|
1731 * g_option_group_set_error_hook: |
|
1732 * @group: a #GOptionGroup |
|
1733 * @error_func: a function to call when an error occurs |
|
1734 * |
|
1735 * Associates a function with @group which will be called |
|
1736 * from g_option_context_parse() when an error occurs. |
|
1737 * |
|
1738 * Note that the user data to be passed to @pre_parse_func and |
|
1739 * @post_parse_func can be specified when constructing the group |
|
1740 * with g_option_group_new(). |
|
1741 * |
|
1742 * Since: 2.6 |
|
1743 **/ |
|
1744 EXPORT_C void |
|
1745 g_option_group_set_error_hook (GOptionGroup *group, |
|
1746 GOptionErrorFunc error_func) |
|
1747 { |
|
1748 g_return_if_fail (group != NULL); |
|
1749 |
|
1750 group->error_func = error_func; |
|
1751 } |
|
1752 |
|
1753 |
|
1754 /** |
|
1755 * g_option_group_set_translate_func: |
|
1756 * @group: a #GOptionGroup |
|
1757 * @func: the #GTranslateFunc, or %NULL |
|
1758 * @data: user data to pass to @func, or %NULL |
|
1759 * @destroy_notify: a function which gets called to free @data, or %NULL |
|
1760 * |
|
1761 * Sets the function which is used to translate user-visible |
|
1762 * strings, for <option>--help</option> output. Different |
|
1763 * groups can use different #GTranslateFunc<!-- -->s. If @func |
|
1764 * is %NULL, strings are not translated. |
|
1765 * |
|
1766 * If you are using gettext(), you only need to set the translation |
|
1767 * domain, see g_option_group_set_translation_domain(). |
|
1768 * |
|
1769 * Since: 2.6 |
|
1770 **/ |
|
1771 EXPORT_C void |
|
1772 g_option_group_set_translate_func (GOptionGroup *group, |
|
1773 GTranslateFunc func, |
|
1774 gpointer data, |
|
1775 GDestroyNotify destroy_notify) |
|
1776 { |
|
1777 g_return_if_fail (group != NULL); |
|
1778 |
|
1779 if (group->translate_notify) |
|
1780 group->translate_notify (group->translate_data); |
|
1781 |
|
1782 group->translate_func = func; |
|
1783 group->translate_data = data; |
|
1784 group->translate_notify = destroy_notify; |
|
1785 } |
|
1786 |
|
1787 static gchar * |
|
1788 dgettext_swapped (const gchar *msgid, |
|
1789 const gchar *domainname) |
|
1790 { |
|
1791 return FIX_CASTING(char *)dgettext (domainname, msgid); |
|
1792 } |
|
1793 |
|
1794 /** |
|
1795 * g_option_group_set_translation_domain: |
|
1796 * @group: a #GOptionGroup |
|
1797 * @domain: the domain to use |
|
1798 * |
|
1799 * A convenience function to use gettext() for translating |
|
1800 * user-visible strings. |
|
1801 * |
|
1802 * Since: 2.6 |
|
1803 **/ |
|
1804 EXPORT_C void |
|
1805 g_option_group_set_translation_domain (GOptionGroup *group, |
|
1806 const gchar *domain) |
|
1807 { |
|
1808 g_return_if_fail (group != NULL); |
|
1809 |
|
1810 g_option_group_set_translate_func (group, |
|
1811 (GTranslateFunc)dgettext_swapped, |
|
1812 g_strdup (domain), |
|
1813 g_free); |
|
1814 } |
|
1815 |
|
1816 #define __G_OPTION_C__ |
|
1817 #include "galiasdef.c" |