Branch data Line data Source code
1 : : /* goption.c - Option parser
2 : : *
3 : : * Copyright (C) 1999, 2003 Red Hat Software
4 : : * Copyright (C) 2004 Anders Carlsson <andersca@gnome.org>
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General Public License
19 : : * along with this library; if not, see <http://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include <string.h>
25 : : #include <stdlib.h>
26 : : #include <stdio.h>
27 : : #include <errno.h>
28 : :
29 : : #if defined __OpenBSD__
30 : : #include <unistd.h>
31 : : #include <sys/sysctl.h>
32 : : #endif
33 : :
34 : : #include "goption.h"
35 : :
36 : : #include "gprintf.h"
37 : : #include "glibintl.h"
38 : : #include "gutilsprivate.h"
39 : :
40 : : #if defined G_OS_WIN32
41 : : #include <windows.h>
42 : : #endif
43 : :
44 : : #define TRANSLATE(group, str) (((group)->translate_func ? (* (group)->translate_func) ((str), (group)->translate_data) : (str)))
45 : :
46 : : #define NO_ARG(entry) ((entry)->arg == G_OPTION_ARG_NONE || \
47 : : ((entry)->arg == G_OPTION_ARG_CALLBACK && \
48 : : ((entry)->flags & G_OPTION_FLAG_NO_ARG)))
49 : :
50 : : #define OPTIONAL_ARG(entry) ((entry)->arg == G_OPTION_ARG_CALLBACK && \
51 : : (entry)->flags & G_OPTION_FLAG_OPTIONAL_ARG)
52 : :
53 : : typedef struct
54 : : {
55 : : GOptionArg arg_type;
56 : : gpointer arg_data;
57 : : union
58 : : {
59 : : gboolean boolean;
60 : : gint integer;
61 : : gchar *str;
62 : : gchar **array;
63 : : gdouble dbl;
64 : : gint64 int64;
65 : : } prev;
66 : : union
67 : : {
68 : : gchar *str;
69 : : struct
70 : : {
71 : : gint len;
72 : : gchar **data;
73 : : } array;
74 : : } allocated;
75 : : } Change;
76 : :
77 : : typedef struct
78 : : {
79 : : gchar **ptr;
80 : : gchar *value;
81 : : } PendingNull;
82 : :
83 : : struct _GOptionContext
84 : : {
85 : : GList *groups;
86 : :
87 : : gchar *parameter_string; /* (nullable) */
88 : : gchar *summary;
89 : : gchar *description;
90 : :
91 : : GTranslateFunc translate_func;
92 : : GDestroyNotify translate_notify;
93 : : gpointer translate_data;
94 : :
95 : : guint help_enabled : 1;
96 : : guint ignore_unknown : 1;
97 : : guint strv_mode : 1;
98 : : guint strict_posix : 1;
99 : :
100 : : GOptionGroup *main_group;
101 : :
102 : : /* We keep a list of change so we can revert them */
103 : : GList *changes;
104 : :
105 : : /* We also keep track of all argv elements
106 : : * that should be NULLed or modified.
107 : : */
108 : : GList *pending_nulls;
109 : : };
110 : :
111 : : struct _GOptionGroup
112 : : {
113 : : gchar *name;
114 : : gchar *description;
115 : : gchar *help_description;
116 : :
117 : : gint ref_count;
118 : :
119 : : GDestroyNotify destroy_notify;
120 : : gpointer user_data;
121 : :
122 : : GTranslateFunc translate_func;
123 : : GDestroyNotify translate_notify;
124 : : gpointer translate_data;
125 : :
126 : : GOptionEntry *entries;
127 : : gsize n_entries;
128 : :
129 : : GOptionParseFunc pre_parse_func;
130 : : GOptionParseFunc post_parse_func;
131 : : GOptionErrorFunc error_func;
132 : : };
133 : :
134 : : static void free_changes_list (GOptionContext *context,
135 : : gboolean revert);
136 : : static void free_pending_nulls (GOptionContext *context,
137 : : gboolean perform_nulls);
138 : :
139 : :
140 : : static int
141 : 1344 : _g_unichar_get_width (gunichar c)
142 : : {
143 : 1344 : if (G_UNLIKELY (g_unichar_iszerowidth (c)))
144 : 0 : return 0;
145 : :
146 : : /* we ignore the fact that we should call g_unichar_iswide_cjk() under
147 : : * some locales (legacy East Asian ones) */
148 : 1344 : if (g_unichar_iswide (c))
149 : 0 : return 2;
150 : :
151 : 1344 : return 1;
152 : : }
153 : :
154 : : static glong
155 : 115 : _g_utf8_strwidth (const gchar *p)
156 : : {
157 : 115 : glong len = 0;
158 : 115 : g_return_val_if_fail (p != NULL, 0);
159 : :
160 : 1459 : while (*p)
161 : : {
162 : 1344 : len += _g_unichar_get_width (g_utf8_get_char (p));
163 : 1344 : p = g_utf8_next_char (p);
164 : : }
165 : :
166 : 115 : return len;
167 : : }
168 : :
169 : 43 : G_DEFINE_QUARK (g-option-context-error-quark, g_option_error)
170 : :
171 : : /**
172 : : * g_option_context_new: (constructor)
173 : : * @parameter_string: (nullable): a string which is displayed in
174 : : * the first line of `--help` output, after the usage summary
175 : : * `programname [OPTION...]`
176 : : *
177 : : * Creates a new option context.
178 : : *
179 : : * The @parameter_string can serve multiple purposes. It can be used
180 : : * to add descriptions for "rest" arguments, which are not parsed by
181 : : * the #GOptionContext, typically something like "FILES" or
182 : : * "FILE1 FILE2...". If you are using %G_OPTION_REMAINING for
183 : : * collecting "rest" arguments, GLib handles this automatically by
184 : : * using the @arg_description of the corresponding #GOptionEntry in
185 : : * the usage summary.
186 : : *
187 : : * Another usage is to give a short summary of the program
188 : : * functionality, like " - frob the strings", which will be displayed
189 : : * in the same line as the usage. For a longer description of the
190 : : * program functionality that should be displayed as a paragraph
191 : : * below the usage line, use g_option_context_set_summary().
192 : : *
193 : : * Note that the @parameter_string is translated using the
194 : : * function set with g_option_context_set_translate_func(), so
195 : : * it should normally be passed untranslated.
196 : : *
197 : : * Returns: (transfer full): a newly created #GOptionContext, which must be
198 : : * freed with g_option_context_free() after use.
199 : : *
200 : : * Since: 2.6
201 : : */
202 : : GOptionContext *
203 : 356 : g_option_context_new (const gchar *parameter_string)
204 : :
205 : : {
206 : : GOptionContext *context;
207 : :
208 : 356 : context = g_new0 (GOptionContext, 1);
209 : :
210 : : /* Clear the empty string to NULL, otherwise we end up calling gettext(""),
211 : : * which returns the translation header. */
212 : 356 : if (parameter_string != NULL && *parameter_string == '\0')
213 : 18 : parameter_string = NULL;
214 : :
215 : 356 : context->parameter_string = g_strdup (parameter_string);
216 : 356 : context->strict_posix = FALSE;
217 : 356 : context->help_enabled = TRUE;
218 : 356 : context->ignore_unknown = FALSE;
219 : :
220 : 356 : return context;
221 : : }
222 : :
223 : : /**
224 : : * g_option_context_free:
225 : : * @context: (transfer full): a #GOptionContext
226 : : *
227 : : * Frees context and all the groups which have been
228 : : * added to it.
229 : : *
230 : : * Please note that parsed arguments need to be freed separately (see
231 : : * #GOptionEntry).
232 : : *
233 : : * Since: 2.6
234 : : */
235 : 344 : void g_option_context_free (GOptionContext *context)
236 : : {
237 : 344 : g_return_if_fail (context != NULL);
238 : :
239 : 344 : g_list_free_full (context->groups, (GDestroyNotify) g_option_group_unref);
240 : :
241 : 344 : if (context->main_group)
242 : 299 : g_option_group_unref (context->main_group);
243 : :
244 : 344 : free_changes_list (context, FALSE);
245 : 344 : free_pending_nulls (context, FALSE);
246 : :
247 : 344 : g_free (context->parameter_string);
248 : 344 : g_free (context->summary);
249 : 344 : g_free (context->description);
250 : :
251 : 344 : if (context->translate_notify)
252 : 95 : (* context->translate_notify) (context->translate_data);
253 : :
254 : 344 : g_free (context);
255 : : }
256 : :
257 : :
258 : : /**
259 : : * g_option_context_set_help_enabled:
260 : : * @context: a #GOptionContext
261 : : * @help_enabled: %TRUE to enable `--help`, %FALSE to disable it
262 : : *
263 : : * Enables or disables automatic generation of `--help` output.
264 : : * By default, g_option_context_parse() recognizes `--help`, `-h`,
265 : : * `-?`, `--help-all` and `--help-groupname` and creates suitable
266 : : * output to stdout.
267 : : *
268 : : * Since: 2.6
269 : : */
270 : 16 : void g_option_context_set_help_enabled (GOptionContext *context,
271 : : gboolean help_enabled)
272 : :
273 : : {
274 : 16 : g_return_if_fail (context != NULL);
275 : :
276 : 16 : context->help_enabled = help_enabled;
277 : : }
278 : :
279 : : /**
280 : : * g_option_context_get_help_enabled:
281 : : * @context: a #GOptionContext
282 : : *
283 : : * Returns whether automatic `--help` generation
284 : : * is turned on for @context. See g_option_context_set_help_enabled().
285 : : *
286 : : * Returns: %TRUE if automatic help generation is turned on.
287 : : *
288 : : * Since: 2.6
289 : : */
290 : : gboolean
291 : 2 : g_option_context_get_help_enabled (GOptionContext *context)
292 : : {
293 : 2 : g_return_val_if_fail (context != NULL, FALSE);
294 : :
295 : 2 : return context->help_enabled;
296 : : }
297 : :
298 : : /**
299 : : * g_option_context_set_ignore_unknown_options:
300 : : * @context: a #GOptionContext
301 : : * @ignore_unknown: %TRUE to ignore unknown options, %FALSE to produce
302 : : * an error when unknown options are met
303 : : *
304 : : * Sets whether to ignore unknown options or not. If an argument is
305 : : * ignored, it is left in the @argv array after parsing. By default,
306 : : * g_option_context_parse() treats unknown options as error.
307 : : *
308 : : * This setting does not affect non-option arguments (i.e. arguments
309 : : * which don't start with a dash). But note that GOption cannot reliably
310 : : * determine whether a non-option belongs to a preceding unknown option.
311 : : *
312 : : * Since: 2.6
313 : : **/
314 : : void
315 : 12 : g_option_context_set_ignore_unknown_options (GOptionContext *context,
316 : : gboolean ignore_unknown)
317 : : {
318 : 12 : g_return_if_fail (context != NULL);
319 : :
320 : 12 : context->ignore_unknown = ignore_unknown;
321 : : }
322 : :
323 : : /**
324 : : * g_option_context_get_ignore_unknown_options:
325 : : * @context: a #GOptionContext
326 : : *
327 : : * Returns whether unknown options are ignored or not. See
328 : : * g_option_context_set_ignore_unknown_options().
329 : : *
330 : : * Returns: %TRUE if unknown options are ignored.
331 : : *
332 : : * Since: 2.6
333 : : **/
334 : : gboolean
335 : 2 : g_option_context_get_ignore_unknown_options (GOptionContext *context)
336 : : {
337 : 2 : g_return_val_if_fail (context != NULL, FALSE);
338 : :
339 : 2 : return context->ignore_unknown;
340 : : }
341 : :
342 : : /**
343 : : * g_option_context_set_strict_posix:
344 : : * @context: a #GOptionContext
345 : : * @strict_posix: the new value
346 : : *
347 : : * Sets strict POSIX mode.
348 : : *
349 : : * By default, this mode is disabled.
350 : : *
351 : : * In strict POSIX mode, the first non-argument parameter encountered
352 : : * (eg: filename) terminates argument processing. Remaining arguments
353 : : * are treated as non-options and are not attempted to be parsed.
354 : : *
355 : : * If strict POSIX mode is disabled then parsing is done in the GNU way
356 : : * where option arguments can be freely mixed with non-options.
357 : : *
358 : : * As an example, consider "ls foo -l". With GNU style parsing, this
359 : : * will list "foo" in long mode. In strict POSIX style, this will list
360 : : * the files named "foo" and "-l".
361 : : *
362 : : * It may be useful to force strict POSIX mode when creating "verb
363 : : * style" command line tools. For example, the "gsettings" command line
364 : : * tool supports the global option "--schemadir" as well as many
365 : : * subcommands ("get", "set", etc.) which each have their own set of
366 : : * arguments. Using strict POSIX mode will allow parsing the global
367 : : * options up to the verb name while leaving the remaining options to be
368 : : * parsed by the relevant subcommand (which can be determined by
369 : : * examining the verb name, which should be present in argv[1] after
370 : : * parsing).
371 : : *
372 : : * Since: 2.44
373 : : **/
374 : : void
375 : 4 : g_option_context_set_strict_posix (GOptionContext *context,
376 : : gboolean strict_posix)
377 : : {
378 : 4 : g_return_if_fail (context != NULL);
379 : :
380 : 4 : context->strict_posix = strict_posix;
381 : : }
382 : :
383 : : /**
384 : : * g_option_context_get_strict_posix:
385 : : * @context: a #GOptionContext
386 : : *
387 : : * Returns whether strict POSIX code is enabled.
388 : : *
389 : : * See g_option_context_set_strict_posix() for more information.
390 : : *
391 : : * Returns: %TRUE if strict POSIX is enabled, %FALSE otherwise.
392 : : *
393 : : * Since: 2.44
394 : : **/
395 : : gboolean
396 : 0 : g_option_context_get_strict_posix (GOptionContext *context)
397 : : {
398 : 0 : g_return_val_if_fail (context != NULL, FALSE);
399 : :
400 : 0 : return context->strict_posix;
401 : : }
402 : :
403 : : /**
404 : : * g_option_context_add_group:
405 : : * @context: a #GOptionContext
406 : : * @group: (transfer full): the group to add
407 : : *
408 : : * Adds a #GOptionGroup to the @context, so that parsing with @context
409 : : * will recognize the options in the group. Note that this will take
410 : : * ownership of the @group and thus the @group should not be freed.
411 : : *
412 : : * Since: 2.6
413 : : **/
414 : : void
415 : 57 : g_option_context_add_group (GOptionContext *context,
416 : : GOptionGroup *group)
417 : : {
418 : : GList *list;
419 : :
420 : 57 : g_return_if_fail (context != NULL);
421 : 57 : g_return_if_fail (group != NULL);
422 : 57 : g_return_if_fail (group->name != NULL);
423 : 57 : g_return_if_fail (group->description != NULL);
424 : 57 : g_return_if_fail (group->help_description != NULL);
425 : :
426 : 58 : for (list = context->groups; list; list = list->next)
427 : : {
428 : 1 : GOptionGroup *g = (GOptionGroup *)list->data;
429 : :
430 : 1 : if ((group->name == NULL && g->name == NULL) ||
431 : 1 : (group->name && g->name && strcmp (group->name, g->name) == 0))
432 : 0 : g_warning ("A group named \"%s\" is already part of this GOptionContext",
433 : : group->name);
434 : : }
435 : :
436 : 57 : context->groups = g_list_append (context->groups, group);
437 : : }
438 : :
439 : : /**
440 : : * g_option_context_set_main_group:
441 : : * @context: a #GOptionContext
442 : : * @group: (transfer full): the group to set as main group
443 : : *
444 : : * Sets a #GOptionGroup as main group of the @context.
445 : : * This has the same effect as calling g_option_context_add_group(),
446 : : * the only difference is that the options in the main group are
447 : : * treated differently when generating `--help` output.
448 : : *
449 : : * Since: 2.6
450 : : **/
451 : : void
452 : 6 : g_option_context_set_main_group (GOptionContext *context,
453 : : GOptionGroup *group)
454 : : {
455 : 6 : g_return_if_fail (context != NULL);
456 : 6 : g_return_if_fail (group != NULL);
457 : :
458 : 6 : if (context->main_group)
459 : : {
460 : 0 : g_warning ("This GOptionContext already has a main group");
461 : :
462 : 0 : return;
463 : : }
464 : :
465 : 6 : context->main_group = group;
466 : : }
467 : :
468 : : /**
469 : : * g_option_context_get_main_group:
470 : : * @context: a #GOptionContext
471 : : *
472 : : * Returns a pointer to the main group of @context.
473 : : *
474 : : * Returns: (transfer none): the main group of @context, or %NULL if
475 : : * @context doesn't have a main group. Note that group belongs to
476 : : * @context and should not be modified or freed.
477 : : *
478 : : * Since: 2.6
479 : : **/
480 : : GOptionGroup *
481 : 7 : g_option_context_get_main_group (GOptionContext *context)
482 : : {
483 : 7 : g_return_val_if_fail (context != NULL, NULL);
484 : :
485 : 7 : return context->main_group;
486 : : }
487 : :
488 : : /**
489 : : * g_option_context_add_main_entries:
490 : : * @context: a #GOptionContext
491 : : * @entries: (array zero-terminated=1): a %NULL-terminated array of #GOptionEntrys
492 : : * @translation_domain: (nullable): a translation domain to use for translating
493 : : * the `--help` output for the options in @entries
494 : : * with gettext(), or %NULL
495 : : *
496 : : * A convenience function which creates a main group if it doesn't
497 : : * exist, adds the @entries to it and sets the translation domain.
498 : : *
499 : : * Since: 2.6
500 : : **/
501 : : void
502 : 301 : g_option_context_add_main_entries (GOptionContext *context,
503 : : const GOptionEntry *entries,
504 : : const gchar *translation_domain)
505 : : {
506 : 301 : g_return_if_fail (context != NULL);
507 : 301 : g_return_if_fail (entries != NULL);
508 : :
509 : 301 : if (!context->main_group)
510 : 300 : context->main_group = g_option_group_new (NULL, NULL, NULL, NULL, NULL);
511 : :
512 : 301 : g_option_group_add_entries (context->main_group, entries);
513 : 301 : g_option_group_set_translation_domain (context->main_group, translation_domain);
514 : : }
515 : :
516 : : static size_t
517 : 21 : calculate_max_length (GOptionGroup *group,
518 : : GHashTable *aliases)
519 : : {
520 : : GOptionEntry *entry;
521 : : gsize i, len, max_length;
522 : : const gchar *long_name;
523 : :
524 : 21 : max_length = 0;
525 : :
526 : 57 : for (i = 0; i < group->n_entries; i++)
527 : : {
528 : 36 : entry = &group->entries[i];
529 : :
530 : 36 : if (entry->flags & G_OPTION_FLAG_HIDDEN)
531 : 2 : continue;
532 : :
533 : 34 : long_name = g_hash_table_lookup (aliases, &entry->long_name);
534 : 34 : if (!long_name)
535 : 32 : long_name = entry->long_name;
536 : 34 : len = _g_utf8_strwidth (long_name);
537 : :
538 : 34 : if (entry->short_name)
539 : 11 : len += 4;
540 : :
541 : 34 : if (!NO_ARG (entry) && entry->arg_description)
542 : 13 : len += 1 + _g_utf8_strwidth (TRANSLATE (group, entry->arg_description));
543 : :
544 : : /* " (deprecated)" */
545 : 34 : if (entry->flags & G_OPTION_FLAG_DEPRECATED)
546 : 1 : len += 3 + _g_utf8_strwidth (_("deprecated"));
547 : :
548 : 34 : max_length = MAX (max_length, len);
549 : : }
550 : :
551 : 21 : return max_length;
552 : : }
553 : :
554 : : static void
555 : 32 : print_entry (GOptionGroup *group,
556 : : size_t max_length,
557 : : const GOptionEntry *entry,
558 : : GString *string,
559 : : GHashTable *aliases)
560 : : {
561 : : GString *str;
562 : : const gchar *long_name;
563 : :
564 : 32 : if (entry->flags & G_OPTION_FLAG_HIDDEN)
565 : 2 : return;
566 : :
567 : 30 : if (entry->long_name[0] == 0)
568 : 3 : return;
569 : :
570 : 27 : long_name = g_hash_table_lookup (aliases, &entry->long_name);
571 : 27 : if (!long_name)
572 : 25 : long_name = entry->long_name;
573 : :
574 : 27 : str = g_string_new (NULL);
575 : :
576 : 27 : if (entry->short_name)
577 : 9 : g_string_append_printf (str, " -%c, --%s", entry->short_name, long_name);
578 : : else
579 : 18 : g_string_append_printf (str, " --%s", long_name);
580 : :
581 : 27 : if (entry->arg_description)
582 : 9 : g_string_append_printf (str, "=%s", TRANSLATE (group, entry->arg_description));
583 : :
584 : 27 : if (entry->flags & G_OPTION_FLAG_DEPRECATED)
585 : : {
586 : 1 : const char *deprecated = _("deprecated");
587 : 1 : g_string_append_printf (str, " (%s)", deprecated);
588 : : }
589 : :
590 : 27 : g_string_append_printf (string, "%s%*s %s\n", str->str,
591 : 27 : (int) (max_length + 4 - _g_utf8_strwidth (str->str)), "",
592 : 27 : entry->description ? TRANSLATE (group, entry->description) : "");
593 : :
594 : 27 : g_string_free (str, TRUE);
595 : : }
596 : :
597 : : static gboolean
598 : 42 : group_has_visible_entries (GOptionContext *context,
599 : : GOptionGroup *group,
600 : : gboolean main_entries)
601 : : {
602 : 42 : GOptionFlags reject_filter = G_OPTION_FLAG_HIDDEN;
603 : : GOptionEntry *entry;
604 : : size_t i, l;
605 : 42 : gboolean main_group = group == context->main_group;
606 : :
607 : 42 : if (!main_entries)
608 : 20 : reject_filter |= G_OPTION_FLAG_IN_MAIN;
609 : :
610 : 50 : for (i = 0, l = (group ? group->n_entries : 0); i < l; i++)
611 : : {
612 : 39 : entry = &group->entries[i];
613 : :
614 : 39 : if (main_entries && !main_group && !(entry->flags & G_OPTION_FLAG_IN_MAIN))
615 : 7 : continue;
616 : 32 : if (entry->long_name[0] == 0) /* ignore rest entry */
617 : 1 : continue;
618 : 31 : if (!(entry->flags & reject_filter))
619 : 31 : return TRUE;
620 : : }
621 : :
622 : 11 : return FALSE;
623 : : }
624 : :
625 : : static gboolean
626 : 5 : group_list_has_visible_entries (GOptionContext *context,
627 : : GList *group_list,
628 : : gboolean main_entries)
629 : : {
630 : 7 : while (group_list)
631 : : {
632 : 2 : if (group_has_visible_entries (context, group_list->data, main_entries))
633 : 0 : return TRUE;
634 : :
635 : 2 : group_list = group_list->next;
636 : : }
637 : :
638 : 5 : return FALSE;
639 : : }
640 : :
641 : : static gboolean
642 : 30 : context_has_h_entry (GOptionContext *context)
643 : : {
644 : : gsize i;
645 : : GList *list;
646 : :
647 : 30 : if (context->main_group)
648 : : {
649 : 77 : for (i = 0; i < context->main_group->n_entries; i++)
650 : : {
651 : 51 : if (context->main_group->entries[i].short_name == 'h')
652 : 0 : return TRUE;
653 : : }
654 : : }
655 : :
656 : 38 : for (list = context->groups; list != NULL; list = g_list_next (list))
657 : : {
658 : : GOptionGroup *group;
659 : :
660 : 8 : group = (GOptionGroup*)list->data;
661 : 21 : for (i = 0; i < group->n_entries; i++)
662 : : {
663 : 13 : if (group->entries[i].short_name == 'h')
664 : 0 : return TRUE;
665 : : }
666 : : }
667 : 30 : return FALSE;
668 : : }
669 : :
670 : : /**
671 : : * g_option_context_get_help:
672 : : * @context: a #GOptionContext
673 : : * @main_help: if %TRUE, only include the main group
674 : : * @group: (nullable): the #GOptionGroup to create help for, or %NULL
675 : : *
676 : : * Returns a formatted, translated help text for the given context.
677 : : * To obtain the text produced by `--help`, call
678 : : * `g_option_context_get_help (context, TRUE, NULL)`.
679 : : * To obtain the text produced by `--help-all`, call
680 : : * `g_option_context_get_help (context, FALSE, NULL)`.
681 : : * To obtain the help text for an option group, call
682 : : * `g_option_context_get_help (context, FALSE, group)`.
683 : : *
684 : : * Returns: A newly allocated string containing the help text
685 : : *
686 : : * Since: 2.14
687 : : */
688 : : gchar *
689 : 19 : g_option_context_get_help (GOptionContext *context,
690 : : gboolean main_help,
691 : : GOptionGroup *group)
692 : : {
693 : : GList *list;
694 : 19 : size_t max_length = 0, len;
695 : : gsize i;
696 : : GOptionEntry *entry;
697 : : GHashTable *shadow_map;
698 : : GHashTable *aliases;
699 : : gboolean seen[256];
700 : : const gchar *rest_description;
701 : : GString *string;
702 : : guchar token;
703 : :
704 : 19 : g_return_val_if_fail (context != NULL, NULL);
705 : :
706 : 19 : string = g_string_sized_new (1024);
707 : :
708 : 19 : rest_description = NULL;
709 : 19 : if (context->main_group)
710 : : {
711 : :
712 : 36 : for (i = 0; i < context->main_group->n_entries; i++)
713 : : {
714 : 26 : entry = &context->main_group->entries[i];
715 : 26 : if (entry->long_name[0] == 0)
716 : : {
717 : 4 : rest_description = TRANSLATE (context->main_group, entry->arg_description);
718 : 4 : break;
719 : : }
720 : : }
721 : : }
722 : :
723 : 19 : g_string_append_printf (string, "%s\n %s", _("Usage:"), g_get_prgname ());
724 : 19 : if (context->help_enabled ||
725 : 3 : (context->main_group && context->main_group->n_entries > 0) ||
726 : 0 : context->groups != NULL)
727 : 19 : g_string_append_printf (string, " %s", _("[OPTION…]"));
728 : :
729 : 19 : if (rest_description)
730 : : {
731 : 8 : g_string_append (string, " ");
732 : : g_string_append (string, rest_description);
733 : : }
734 : :
735 : 19 : if (context->parameter_string)
736 : : {
737 : 8 : g_string_append (string, " ");
738 : 8 : g_string_append (string, TRANSLATE (context, context->parameter_string));
739 : : }
740 : :
741 : 19 : g_string_append (string, "\n\n");
742 : :
743 : 19 : if (context->summary)
744 : : {
745 : 6 : g_string_append (string, TRANSLATE (context, context->summary));
746 : 12 : g_string_append (string, "\n\n");
747 : : }
748 : :
749 : 19 : memset (seen, 0, sizeof (gboolean) * 256);
750 : 19 : shadow_map = g_hash_table_new (g_str_hash, g_str_equal);
751 : 19 : aliases = g_hash_table_new_full (NULL, NULL, NULL, g_free);
752 : :
753 : 19 : if (context->main_group)
754 : : {
755 : 40 : for (i = 0; i < context->main_group->n_entries; i++)
756 : : {
757 : 26 : entry = &context->main_group->entries[i];
758 : 26 : g_hash_table_insert (shadow_map,
759 : 26 : (gpointer)entry->long_name,
760 : : entry);
761 : :
762 : 26 : if (seen[(guchar)entry->short_name])
763 : 7 : entry->short_name = 0;
764 : : else
765 : 19 : seen[(guchar)entry->short_name] = TRUE;
766 : : }
767 : : }
768 : :
769 : 19 : list = context->groups;
770 : 30 : while (list != NULL)
771 : : {
772 : 11 : GOptionGroup *g = list->data;
773 : 26 : for (i = 0; i < g->n_entries; i++)
774 : : {
775 : 15 : entry = &g->entries[i];
776 : 15 : if (g_hash_table_lookup (shadow_map, entry->long_name) &&
777 : 4 : !(entry->flags & G_OPTION_FLAG_NOALIAS))
778 : : {
779 : 2 : g_hash_table_insert (aliases, &entry->long_name,
780 : 2 : g_strdup_printf ("%s-%s", g->name, entry->long_name));
781 : : }
782 : : else
783 : 13 : g_hash_table_insert (shadow_map, (gpointer)entry->long_name, entry);
784 : :
785 : 15 : if (seen[(guchar)entry->short_name] &&
786 : 9 : !(entry->flags & G_OPTION_FLAG_NOALIAS))
787 : 5 : entry->short_name = 0;
788 : : else
789 : 10 : seen[(guchar)entry->short_name] = TRUE;
790 : : }
791 : 11 : list = list->next;
792 : : }
793 : :
794 : 19 : g_hash_table_destroy (shadow_map);
795 : :
796 : 19 : list = context->groups;
797 : :
798 : 19 : if (context->help_enabled)
799 : : {
800 : 16 : max_length = _g_utf8_strwidth ("-?, --help");
801 : :
802 : 16 : if (list)
803 : : {
804 : 8 : len = _g_utf8_strwidth ("--help-all");
805 : 8 : max_length = MAX (max_length, len);
806 : : }
807 : : }
808 : :
809 : 19 : if (context->main_group)
810 : : {
811 : 14 : len = calculate_max_length (context->main_group, aliases);
812 : 14 : max_length = MAX (max_length, len);
813 : : }
814 : :
815 : 30 : while (list != NULL)
816 : : {
817 : 11 : GOptionGroup *g = list->data;
818 : :
819 : 11 : if (!group || group == g)
820 : : {
821 : 11 : if (context->help_enabled)
822 : : {
823 : : /* First, we check the --help-<groupname> options */
824 : 8 : len = _g_utf8_strwidth ("--help-") + _g_utf8_strwidth (g->name);
825 : 8 : max_length = MAX (max_length, len);
826 : : }
827 : :
828 : : /* Then we go through the entries */
829 : 11 : if (group_has_visible_entries (context, g, main_help))
830 : : {
831 : 7 : len = calculate_max_length (g, aliases);
832 : 7 : max_length = MAX (max_length, len);
833 : : }
834 : : }
835 : :
836 : 11 : list = list->next;
837 : : }
838 : :
839 : : /* Add a bit of padding */
840 : 19 : max_length += 4;
841 : :
842 : 19 : g_assert (max_length <= G_MAXINT);
843 : :
844 : 19 : if (!group && context->help_enabled)
845 : : {
846 : 14 : list = context->groups;
847 : :
848 : 14 : token = context_has_h_entry (context) ? '?' : 'h';
849 : :
850 : 28 : g_string_append_printf (string, "%s\n -%c, --%-*s %s\n",
851 : 14 : _("Help Options:"), token, (int) max_length - 4, "help",
852 : : _("Show help options"));
853 : :
854 : : /* We only want --help-all when there are groups */
855 : 14 : if (list)
856 : 6 : g_string_append_printf (string, " --%-*s %s\n",
857 : : (int) max_length, "help-all",
858 : : _("Show all help options"));
859 : :
860 : 20 : while (list)
861 : : {
862 : 6 : GOptionGroup *g = list->data;
863 : :
864 : 6 : if (group_has_visible_entries (context, g, FALSE))
865 : 5 : g_string_append_printf (string, " --help-%-*s %s\n",
866 : 6 : (int) max_length - 5, g->name,
867 : 6 : TRANSLATE (g, g->help_description));
868 : :
869 : 6 : list = list->next;
870 : : }
871 : :
872 : 28 : g_string_append (string, "\n");
873 : : }
874 : :
875 : 19 : if (group)
876 : : {
877 : : /* Print a certain group */
878 : :
879 : 3 : if (group_has_visible_entries (context, group, FALSE))
880 : : {
881 : 3 : g_string_append (string, TRANSLATE (group, group->description));
882 : 3 : g_string_append (string, "\n");
883 : 7 : for (i = 0; i < group->n_entries; i++)
884 : 4 : print_entry (group, max_length, &group->entries[i], string, aliases);
885 : 6 : g_string_append (string, "\n");
886 : : }
887 : : }
888 : 16 : else if (!main_help)
889 : : {
890 : : /* Print all groups */
891 : :
892 : 9 : list = context->groups;
893 : :
894 : 13 : while (list)
895 : : {
896 : 4 : GOptionGroup *g = list->data;
897 : :
898 : 4 : if (group_has_visible_entries (context, g, FALSE))
899 : : {
900 : 4 : g_string_append (string, g->description);
901 : 4 : g_string_append (string, "\n");
902 : 10 : for (i = 0; i < g->n_entries; i++)
903 : 6 : if (!(g->entries[i].flags & G_OPTION_FLAG_IN_MAIN))
904 : 6 : print_entry (g, max_length, &g->entries[i], string, aliases);
905 : :
906 : 8 : g_string_append (string, "\n");
907 : : }
908 : :
909 : 4 : list = list->next;
910 : : }
911 : : }
912 : :
913 : : /* Print application options if --help or --help-all has been specified */
914 : 35 : if ((main_help || !group) &&
915 : 21 : (group_has_visible_entries (context, context->main_group, TRUE) ||
916 : 5 : group_list_has_visible_entries (context, context->groups, TRUE)))
917 : : {
918 : 11 : list = context->groups;
919 : :
920 : 11 : if (context->help_enabled || list)
921 : 22 : g_string_append (string, _("Application Options:"));
922 : : else
923 : 0 : g_string_append (string, _("Options:"));
924 : 11 : g_string_append (string, "\n");
925 : 11 : if (context->main_group)
926 : 33 : for (i = 0; i < context->main_group->n_entries; i++)
927 : 22 : print_entry (context->main_group, max_length,
928 : 22 : &context->main_group->entries[i], string, aliases);
929 : :
930 : 17 : while (list != NULL)
931 : : {
932 : 6 : GOptionGroup *g = list->data;
933 : :
934 : : /* Print main entries from other groups */
935 : 15 : for (i = 0; i < g->n_entries; i++)
936 : 9 : if (g->entries[i].flags & G_OPTION_FLAG_IN_MAIN)
937 : 0 : print_entry (g, max_length, &g->entries[i], string, aliases);
938 : :
939 : 6 : list = list->next;
940 : : }
941 : :
942 : 22 : g_string_append (string, "\n");
943 : : }
944 : :
945 : 19 : if (context->description)
946 : : {
947 : 6 : g_string_append (string, TRANSLATE (context, context->description));
948 : 12 : g_string_append (string, "\n");
949 : : }
950 : :
951 : 19 : g_hash_table_destroy (aliases);
952 : :
953 : 19 : return g_string_free (string, FALSE);
954 : : }
955 : :
956 : : G_NORETURN
957 : : static void
958 : 12 : print_help (GOptionContext *context,
959 : : gboolean main_help,
960 : : GOptionGroup *group)
961 : : {
962 : : gchar *help;
963 : :
964 : 12 : help = g_option_context_get_help (context, main_help, group);
965 : 12 : g_print ("%s", help);
966 : 12 : g_free (help);
967 : :
968 : 12 : exit (0);
969 : : }
970 : :
971 : : static gboolean
972 : 8 : parse_int (const gchar *arg_name,
973 : : const gchar *arg,
974 : : gint *result,
975 : : GError **error)
976 : : {
977 : : gchar *end;
978 : : glong tmp;
979 : :
980 : 8 : errno = 0;
981 : 8 : tmp = strtol (arg, &end, 0);
982 : :
983 : 8 : if (*arg == '\0' || *end != '\0')
984 : : {
985 : 1 : g_set_error (error,
986 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
987 : : _("Cannot parse integer value “%s” for %s"),
988 : : arg, arg_name);
989 : 1 : return FALSE;
990 : : }
991 : :
992 : 7 : *result = (int) tmp;
993 : 7 : if (*result != tmp || errno == ERANGE)
994 : : {
995 : 1 : g_set_error (error,
996 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
997 : : _("Integer value “%s” for %s out of range"),
998 : : arg, arg_name);
999 : 1 : return FALSE;
1000 : : }
1001 : :
1002 : 6 : return TRUE;
1003 : : }
1004 : :
1005 : :
1006 : : static gboolean
1007 : 8 : parse_double (const gchar *arg_name,
1008 : : const gchar *arg,
1009 : : gdouble *result,
1010 : : GError **error)
1011 : : {
1012 : : gchar *end;
1013 : : gdouble tmp;
1014 : :
1015 : 8 : errno = 0;
1016 : 8 : tmp = g_strtod (arg, &end);
1017 : :
1018 : 8 : if (*arg == '\0' || *end != '\0')
1019 : : {
1020 : 1 : g_set_error (error,
1021 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1022 : : _("Cannot parse double value “%s” for %s"),
1023 : : arg, arg_name);
1024 : 1 : return FALSE;
1025 : : }
1026 : 7 : if (errno == ERANGE)
1027 : : {
1028 : 1 : g_set_error (error,
1029 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1030 : : _("Double value “%s” for %s out of range"),
1031 : : arg, arg_name);
1032 : 1 : return FALSE;
1033 : : }
1034 : :
1035 : 6 : *result = tmp;
1036 : :
1037 : 6 : return TRUE;
1038 : : }
1039 : :
1040 : :
1041 : : static gboolean
1042 : 5 : parse_int64 (const gchar *arg_name,
1043 : : const gchar *arg,
1044 : : gint64 *result,
1045 : : GError **error)
1046 : : {
1047 : : gchar *end;
1048 : : gint64 tmp;
1049 : :
1050 : 5 : errno = 0;
1051 : 5 : tmp = g_ascii_strtoll (arg, &end, 0);
1052 : :
1053 : 5 : if (*arg == '\0' || *end != '\0')
1054 : : {
1055 : 1 : g_set_error (error,
1056 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1057 : : _("Cannot parse integer value “%s” for %s"),
1058 : : arg, arg_name);
1059 : 1 : return FALSE;
1060 : : }
1061 : 4 : if (errno == ERANGE)
1062 : : {
1063 : 1 : g_set_error (error,
1064 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1065 : : _("Integer value “%s” for %s out of range"),
1066 : : arg, arg_name);
1067 : 1 : return FALSE;
1068 : : }
1069 : :
1070 : 3 : *result = tmp;
1071 : :
1072 : 3 : return TRUE;
1073 : : }
1074 : :
1075 : :
1076 : : static Change *
1077 : 511 : get_change (GOptionContext *context,
1078 : : GOptionArg arg_type,
1079 : : gpointer arg_data)
1080 : : {
1081 : : GList *list;
1082 : 511 : Change *change = NULL;
1083 : :
1084 : 1028 : for (list = context->changes; list != NULL; list = list->next)
1085 : : {
1086 : 560 : change = list->data;
1087 : :
1088 : 560 : if (change->arg_data == arg_data)
1089 : 43 : goto found;
1090 : : }
1091 : :
1092 : 468 : change = g_new0 (Change, 1);
1093 : 468 : change->arg_type = arg_type;
1094 : 468 : change->arg_data = arg_data;
1095 : :
1096 : 468 : context->changes = g_list_prepend (context->changes, change);
1097 : :
1098 : 511 : found:
1099 : :
1100 : 511 : return change;
1101 : : }
1102 : :
1103 : : static void
1104 : 695 : add_pending_null (GOptionContext *context,
1105 : : gchar **ptr,
1106 : : gchar *value)
1107 : : {
1108 : : PendingNull *n;
1109 : :
1110 : 695 : n = g_new0 (PendingNull, 1);
1111 : 695 : n->ptr = ptr;
1112 : 695 : n->value = value;
1113 : :
1114 : 695 : context->pending_nulls = g_list_prepend (context->pending_nulls, n);
1115 : 695 : }
1116 : :
1117 : : static gboolean
1118 : 536 : parse_arg (GOptionContext *context,
1119 : : GOptionGroup *group,
1120 : : GOptionEntry *entry,
1121 : : const gchar *value,
1122 : : const gchar *option_name,
1123 : : GError **error)
1124 : :
1125 : : {
1126 : : Change *change;
1127 : :
1128 : 536 : g_assert (value || OPTIONAL_ARG (entry) || NO_ARG (entry));
1129 : :
1130 : 536 : switch (entry->arg)
1131 : : {
1132 : 242 : case G_OPTION_ARG_NONE:
1133 : : {
1134 : 242 : (void) get_change (context, G_OPTION_ARG_NONE,
1135 : : entry->arg_data);
1136 : :
1137 : 242 : *(gboolean *)entry->arg_data = !(entry->flags & G_OPTION_FLAG_REVERSE);
1138 : 242 : break;
1139 : : }
1140 : 38 : case G_OPTION_ARG_STRING:
1141 : : {
1142 : : gchar *data;
1143 : :
1144 : : #ifdef G_OS_WIN32
1145 : : if (!context->strv_mode)
1146 : : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1147 : : else
1148 : : data = g_strdup (value);
1149 : : #else
1150 : 38 : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1151 : : #endif
1152 : :
1153 : 38 : if (!data)
1154 : 0 : return FALSE;
1155 : :
1156 : 38 : change = get_change (context, G_OPTION_ARG_STRING,
1157 : : entry->arg_data);
1158 : :
1159 : 38 : if (!change->allocated.str)
1160 : 36 : change->prev.str = *(gchar **)entry->arg_data;
1161 : : else
1162 : 2 : g_free (change->allocated.str);
1163 : :
1164 : 38 : change->allocated.str = data;
1165 : :
1166 : 38 : *(gchar **)entry->arg_data = data;
1167 : 38 : break;
1168 : : }
1169 : 16 : case G_OPTION_ARG_STRING_ARRAY:
1170 : : {
1171 : : gchar *data;
1172 : :
1173 : : #ifdef G_OS_WIN32
1174 : : if (!context->strv_mode)
1175 : : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1176 : : else
1177 : : data = g_strdup (value);
1178 : : #else
1179 : 16 : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1180 : : #endif
1181 : :
1182 : 16 : if (!data)
1183 : 0 : return FALSE;
1184 : :
1185 : 16 : change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
1186 : : entry->arg_data);
1187 : :
1188 : 16 : if (change->allocated.array.len == 0)
1189 : : {
1190 : 13 : change->prev.array = *(gchar ***)entry->arg_data;
1191 : 13 : change->allocated.array.data = g_new (gchar *, 2);
1192 : : }
1193 : : else
1194 : 3 : change->allocated.array.data =
1195 : 3 : g_renew (gchar *, change->allocated.array.data,
1196 : : change->allocated.array.len + 2);
1197 : :
1198 : 16 : change->allocated.array.data[change->allocated.array.len] = data;
1199 : 16 : change->allocated.array.data[change->allocated.array.len + 1] = NULL;
1200 : :
1201 : 16 : change->allocated.array.len ++;
1202 : :
1203 : 16 : *(gchar ***)entry->arg_data = change->allocated.array.data;
1204 : :
1205 : 16 : break;
1206 : : }
1207 : :
1208 : 30 : case G_OPTION_ARG_FILENAME:
1209 : : {
1210 : : gchar *data;
1211 : :
1212 : : #ifdef G_OS_WIN32
1213 : : if (!context->strv_mode)
1214 : : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1215 : : else
1216 : : data = g_strdup (value);
1217 : :
1218 : : if (!data)
1219 : : return FALSE;
1220 : : #else
1221 : 30 : data = g_strdup (value);
1222 : : #endif
1223 : 30 : change = get_change (context, G_OPTION_ARG_FILENAME,
1224 : : entry->arg_data);
1225 : :
1226 : 30 : if (!change->allocated.str)
1227 : 30 : change->prev.str = *(gchar **)entry->arg_data;
1228 : : else
1229 : 0 : g_free (change->allocated.str);
1230 : :
1231 : 30 : change->allocated.str = data;
1232 : :
1233 : 30 : *(gchar **)entry->arg_data = data;
1234 : 30 : break;
1235 : : }
1236 : :
1237 : 170 : case G_OPTION_ARG_FILENAME_ARRAY:
1238 : : {
1239 : : gchar *data;
1240 : :
1241 : : #ifdef G_OS_WIN32
1242 : : if (!context->strv_mode)
1243 : : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1244 : : else
1245 : : data = g_strdup (value);
1246 : :
1247 : : if (!data)
1248 : : return FALSE;
1249 : : #else
1250 : 170 : data = g_strdup (value);
1251 : : #endif
1252 : 170 : change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
1253 : : entry->arg_data);
1254 : :
1255 : 170 : if (change->allocated.array.len == 0)
1256 : : {
1257 : 140 : change->prev.array = *(gchar ***)entry->arg_data;
1258 : 140 : change->allocated.array.data = g_new (gchar *, 2);
1259 : : }
1260 : : else
1261 : 30 : change->allocated.array.data =
1262 : 30 : g_renew (gchar *, change->allocated.array.data,
1263 : : change->allocated.array.len + 2);
1264 : :
1265 : 170 : change->allocated.array.data[change->allocated.array.len] = data;
1266 : 170 : change->allocated.array.data[change->allocated.array.len + 1] = NULL;
1267 : :
1268 : 170 : change->allocated.array.len ++;
1269 : :
1270 : 170 : *(gchar ***)entry->arg_data = change->allocated.array.data;
1271 : :
1272 : 170 : break;
1273 : : }
1274 : :
1275 : 8 : case G_OPTION_ARG_INT:
1276 : : {
1277 : : gint data;
1278 : :
1279 : 8 : if (!parse_int (option_name, value,
1280 : : &data,
1281 : : error))
1282 : 2 : return FALSE;
1283 : :
1284 : 6 : change = get_change (context, G_OPTION_ARG_INT,
1285 : : entry->arg_data);
1286 : 6 : change->prev.integer = *(gint *)entry->arg_data;
1287 : 6 : *(gint *)entry->arg_data = data;
1288 : 6 : break;
1289 : : }
1290 : 19 : case G_OPTION_ARG_CALLBACK:
1291 : : {
1292 : : gchar *data;
1293 : : gboolean retval;
1294 : :
1295 : 19 : if (!value && entry->flags & G_OPTION_FLAG_OPTIONAL_ARG)
1296 : 7 : data = NULL;
1297 : 12 : else if (entry->flags & G_OPTION_FLAG_NO_ARG)
1298 : 3 : data = NULL;
1299 : 9 : else if (entry->flags & G_OPTION_FLAG_FILENAME)
1300 : : {
1301 : : #ifdef G_OS_WIN32
1302 : : if (!context->strv_mode)
1303 : : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1304 : : else
1305 : : data = g_strdup (value);
1306 : : #else
1307 : 0 : data = g_strdup (value);
1308 : : #endif
1309 : : }
1310 : : else
1311 : 9 : data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1312 : :
1313 : 19 : if (!(entry->flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG)) &&
1314 : : !data)
1315 : 0 : return FALSE;
1316 : :
1317 : 19 : retval = (* (GOptionArgFunc) entry->arg_data) (option_name, data, group->user_data, error);
1318 : :
1319 : 19 : if (!retval && error != NULL && *error == NULL)
1320 : 0 : g_set_error (error,
1321 : : G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
1322 : : _("Error parsing option %s"), option_name);
1323 : :
1324 : 19 : g_free (data);
1325 : :
1326 : 19 : return retval;
1327 : :
1328 : : break;
1329 : : }
1330 : 8 : case G_OPTION_ARG_DOUBLE:
1331 : : {
1332 : : gdouble data;
1333 : :
1334 : 8 : if (!parse_double (option_name, value,
1335 : : &data,
1336 : : error))
1337 : : {
1338 : 2 : return FALSE;
1339 : : }
1340 : :
1341 : 6 : change = get_change (context, G_OPTION_ARG_DOUBLE,
1342 : : entry->arg_data);
1343 : 6 : change->prev.dbl = *(gdouble *)entry->arg_data;
1344 : 6 : *(gdouble *)entry->arg_data = data;
1345 : 6 : break;
1346 : : }
1347 : 5 : case G_OPTION_ARG_INT64:
1348 : : {
1349 : : gint64 data;
1350 : :
1351 : 5 : if (!parse_int64 (option_name, value,
1352 : : &data,
1353 : : error))
1354 : : {
1355 : 2 : return FALSE;
1356 : : }
1357 : :
1358 : 3 : change = get_change (context, G_OPTION_ARG_INT64,
1359 : : entry->arg_data);
1360 : 3 : change->prev.int64 = *(gint64 *)entry->arg_data;
1361 : 3 : *(gint64 *)entry->arg_data = data;
1362 : 3 : break;
1363 : : }
1364 : 0 : default:
1365 : : g_assert_not_reached ();
1366 : : }
1367 : :
1368 : 511 : return TRUE;
1369 : : }
1370 : :
1371 : : static gboolean
1372 : 25 : parse_short_option (GOptionContext *context,
1373 : : GOptionGroup *group,
1374 : : gint idx,
1375 : : gint *new_idx,
1376 : : gchar arg,
1377 : : gint *argc,
1378 : : gchar ***argv,
1379 : : GError **error,
1380 : : gboolean *parsed)
1381 : : {
1382 : : gsize j;
1383 : :
1384 : 75 : for (j = 0; j < group->n_entries; j++)
1385 : : {
1386 : 51 : if (arg == group->entries[j].short_name)
1387 : : {
1388 : : gchar *option_name;
1389 : 18 : gchar *value = NULL;
1390 : :
1391 : 18 : option_name = g_strdup_printf ("-%c", group->entries[j].short_name);
1392 : :
1393 : 18 : if (NO_ARG (&group->entries[j]))
1394 : 8 : value = NULL;
1395 : : else
1396 : : {
1397 : 10 : if (*new_idx > idx)
1398 : : {
1399 : 0 : g_set_error (error,
1400 : : G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
1401 : : _("Error parsing option %s"), option_name);
1402 : 0 : g_free (option_name);
1403 : 0 : return FALSE;
1404 : : }
1405 : :
1406 : 10 : if (idx < *argc - 1)
1407 : : {
1408 : 7 : if (OPTIONAL_ARG (&group->entries[j]) && ((*argv)[idx + 1][0] == '-'))
1409 : 1 : value = NULL;
1410 : : else
1411 : : {
1412 : 6 : value = (*argv)[idx + 1];
1413 : 6 : add_pending_null (context, &((*argv)[idx + 1]), NULL);
1414 : 6 : *new_idx = idx + 1;
1415 : : }
1416 : : }
1417 : 3 : else if (idx >= *argc - 1 && OPTIONAL_ARG (&group->entries[j]))
1418 : 2 : value = NULL;
1419 : : else
1420 : : {
1421 : 1 : g_set_error (error,
1422 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1423 : : _("Missing argument for %s"), option_name);
1424 : 1 : g_free (option_name);
1425 : 1 : return FALSE;
1426 : : }
1427 : : }
1428 : :
1429 : 17 : if (!parse_arg (context, group, &group->entries[j],
1430 : : value, option_name, error))
1431 : : {
1432 : 0 : g_free (option_name);
1433 : 0 : return FALSE;
1434 : : }
1435 : :
1436 : 17 : g_free (option_name);
1437 : 17 : *parsed = TRUE;
1438 : : }
1439 : : }
1440 : :
1441 : 24 : return TRUE;
1442 : : }
1443 : :
1444 : : static gboolean
1445 : 478 : parse_long_option (GOptionContext *context,
1446 : : GOptionGroup *group,
1447 : : gint *idx,
1448 : : gchar *arg,
1449 : : gboolean aliased,
1450 : : gint *argc,
1451 : : gchar ***argv,
1452 : : GError **error,
1453 : : gboolean *parsed)
1454 : : {
1455 : : gsize j;
1456 : :
1457 : 2764 : for (j = 0; j < group->n_entries; j++)
1458 : : {
1459 : 2537 : if (*idx >= *argc)
1460 : 0 : return TRUE;
1461 : :
1462 : 2537 : if (aliased && (group->entries[j].flags & G_OPTION_FLAG_NOALIAS))
1463 : 0 : continue;
1464 : :
1465 : 2537 : if (NO_ARG (&group->entries[j]) &&
1466 : 1534 : strcmp (arg, group->entries[j].long_name) == 0)
1467 : : {
1468 : : gchar *option_name;
1469 : : gboolean retval;
1470 : :
1471 : 237 : option_name = g_strconcat ("--", group->entries[j].long_name, NULL);
1472 : 237 : retval = parse_arg (context, group, &group->entries[j],
1473 : : NULL, option_name, error);
1474 : 237 : g_free (option_name);
1475 : :
1476 : 237 : add_pending_null (context, &((*argv)[*idx]), NULL);
1477 : 237 : *parsed = TRUE;
1478 : :
1479 : 237 : return retval;
1480 : : }
1481 : : else
1482 : : {
1483 : 2300 : size_t len = strlen (group->entries[j].long_name);
1484 : :
1485 : 2300 : if (strncmp (arg, group->entries[j].long_name, len) == 0 &&
1486 : 300 : (arg[len] == '=' || arg[len] == 0))
1487 : : {
1488 : 232 : gchar *value = NULL;
1489 : : gchar *option_name;
1490 : :
1491 : 232 : add_pending_null (context, &((*argv)[*idx]), NULL);
1492 : 232 : option_name = g_strconcat ("--", group->entries[j].long_name, NULL);
1493 : :
1494 : 232 : if (arg[len] == '=')
1495 : 83 : value = arg + len + 1;
1496 : 149 : else if (*idx < *argc - 1)
1497 : : {
1498 : 145 : if (!OPTIONAL_ARG (&group->entries[j]))
1499 : : {
1500 : 141 : value = (*argv)[*idx + 1];
1501 : 141 : add_pending_null (context, &((*argv)[*idx + 1]), NULL);
1502 : 141 : (*idx)++;
1503 : : }
1504 : : else
1505 : : {
1506 : 4 : if ((*argv)[*idx + 1][0] == '-')
1507 : : {
1508 : : gboolean retval;
1509 : 2 : retval = parse_arg (context, group, &group->entries[j],
1510 : : NULL, option_name, error);
1511 : 2 : *parsed = TRUE;
1512 : 2 : g_free (option_name);
1513 : 2 : return retval;
1514 : : }
1515 : : else
1516 : : {
1517 : 2 : value = (*argv)[*idx + 1];
1518 : 2 : add_pending_null (context, &((*argv)[*idx + 1]), NULL);
1519 : 2 : (*idx)++;
1520 : : }
1521 : : }
1522 : : }
1523 : 4 : else if (*idx >= *argc - 1 && OPTIONAL_ARG (&group->entries[j]))
1524 : : {
1525 : : gboolean retval;
1526 : 2 : retval = parse_arg (context, group, &group->entries[j],
1527 : : NULL, option_name, error);
1528 : 2 : *parsed = TRUE;
1529 : 2 : g_free (option_name);
1530 : 2 : return retval;
1531 : : }
1532 : : else
1533 : : {
1534 : 2 : g_set_error (error,
1535 : : G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1536 : : _("Missing argument for %s"), option_name);
1537 : 2 : g_free (option_name);
1538 : 2 : return FALSE;
1539 : : }
1540 : :
1541 : 226 : if (!parse_arg (context, group, &group->entries[j],
1542 : : value, option_name, error))
1543 : : {
1544 : 8 : g_free (option_name);
1545 : 8 : return FALSE;
1546 : : }
1547 : :
1548 : 218 : g_free (option_name);
1549 : 218 : *parsed = TRUE;
1550 : : }
1551 : : }
1552 : : }
1553 : :
1554 : 227 : return TRUE;
1555 : : }
1556 : :
1557 : : static gboolean
1558 : 1191 : parse_remaining_arg (GOptionContext *context,
1559 : : GOptionGroup *group,
1560 : : gint *idx,
1561 : : gint *argc,
1562 : : gchar ***argv,
1563 : : GError **error,
1564 : : gboolean *parsed)
1565 : : {
1566 : : gsize j;
1567 : :
1568 : 7589 : for (j = 0; j < group->n_entries; j++)
1569 : : {
1570 : 6450 : if (*idx >= *argc)
1571 : 0 : return TRUE;
1572 : :
1573 : 6450 : if (group->entries[j].long_name[0])
1574 : 6398 : continue;
1575 : :
1576 : 52 : g_return_val_if_fail (group->entries[j].arg == G_OPTION_ARG_CALLBACK ||
1577 : : group->entries[j].arg == G_OPTION_ARG_STRING_ARRAY ||
1578 : : group->entries[j].arg == G_OPTION_ARG_FILENAME_ARRAY, FALSE);
1579 : :
1580 : 52 : add_pending_null (context, &((*argv)[*idx]), NULL);
1581 : :
1582 : 52 : if (!parse_arg (context, group, &group->entries[j], (*argv)[*idx], "", error))
1583 : 0 : return FALSE;
1584 : :
1585 : 52 : *parsed = TRUE;
1586 : 52 : return TRUE;
1587 : : }
1588 : :
1589 : 1139 : return TRUE;
1590 : : }
1591 : :
1592 : : static void
1593 : 365 : free_changes_list (GOptionContext *context,
1594 : : gboolean revert)
1595 : : {
1596 : : GList *list;
1597 : :
1598 : 833 : for (list = context->changes; list != NULL; list = list->next)
1599 : : {
1600 : 468 : Change *change = list->data;
1601 : :
1602 : 468 : if (revert)
1603 : : {
1604 : 4 : switch (change->arg_type)
1605 : : {
1606 : 1 : case G_OPTION_ARG_NONE:
1607 : 1 : *(gboolean *)change->arg_data = change->prev.boolean;
1608 : 1 : break;
1609 : 1 : case G_OPTION_ARG_INT:
1610 : 1 : *(gint *)change->arg_data = change->prev.integer;
1611 : 1 : break;
1612 : 2 : case G_OPTION_ARG_STRING:
1613 : : case G_OPTION_ARG_FILENAME:
1614 : 2 : g_free (change->allocated.str);
1615 : 2 : *(gchar **)change->arg_data = change->prev.str;
1616 : 2 : break;
1617 : 0 : case G_OPTION_ARG_STRING_ARRAY:
1618 : : case G_OPTION_ARG_FILENAME_ARRAY:
1619 : 0 : g_strfreev (change->allocated.array.data);
1620 : 0 : *(gchar ***)change->arg_data = change->prev.array;
1621 : 0 : break;
1622 : 0 : case G_OPTION_ARG_DOUBLE:
1623 : 0 : *(gdouble *)change->arg_data = change->prev.dbl;
1624 : 0 : break;
1625 : 0 : case G_OPTION_ARG_INT64:
1626 : 0 : *(gint64 *)change->arg_data = change->prev.int64;
1627 : 0 : break;
1628 : 0 : default:
1629 : : g_assert_not_reached ();
1630 : : }
1631 : : }
1632 : :
1633 : 468 : g_free (change);
1634 : : }
1635 : :
1636 : 365 : g_list_free (context->changes);
1637 : 365 : context->changes = NULL;
1638 : 365 : }
1639 : :
1640 : : static void
1641 : 684 : free_pending_nulls (GOptionContext *context,
1642 : : gboolean perform_nulls)
1643 : : {
1644 : : GList *list;
1645 : :
1646 : 1379 : for (list = context->pending_nulls; list != NULL; list = list->next)
1647 : : {
1648 : 695 : PendingNull *n = list->data;
1649 : :
1650 : 695 : if (perform_nulls)
1651 : : {
1652 : 668 : if (n->value)
1653 : : {
1654 : : /* Copy back the short options */
1655 : 2 : *(n->ptr)[0] = '-';
1656 : 2 : strcpy (*n->ptr + 1, n->value);
1657 : : }
1658 : : else
1659 : : {
1660 : 666 : if (context->strv_mode)
1661 : 13 : g_free (*n->ptr);
1662 : :
1663 : 666 : *n->ptr = NULL;
1664 : : }
1665 : : }
1666 : :
1667 : 695 : g_free (n->value);
1668 : 695 : g_free (n);
1669 : : }
1670 : :
1671 : 684 : g_list_free (context->pending_nulls);
1672 : 684 : context->pending_nulls = NULL;
1673 : 684 : }
1674 : :
1675 : : /* Use a platform-specific mechanism to look up the first argument to
1676 : : * the current process.
1677 : : * Note if you implement this for other platforms, also add it to
1678 : : * tests/option-argv0.c
1679 : : */
1680 : : static char *
1681 : 1 : platform_get_argv0 (void)
1682 : : {
1683 : : #ifdef HAVE_PROC_SELF_CMDLINE
1684 : : char *cmdline;
1685 : : char *base_arg0;
1686 : : gsize len;
1687 : :
1688 : 1 : if (!g_file_get_contents ("/proc/self/cmdline",
1689 : : &cmdline,
1690 : : &len,
1691 : : NULL))
1692 : 0 : return NULL;
1693 : :
1694 : : /* g_file_get_contents() guarantees to put a NUL immediately after the
1695 : : * file's contents (at cmdline[len] here), even if the file itself was
1696 : : * not NUL-terminated. */
1697 : 1 : g_assert (memchr (cmdline, 0, len + 1));
1698 : :
1699 : : /* We could just return cmdline, but I think it's better
1700 : : * to hold on to a smaller malloc block; the arguments
1701 : : * could be large.
1702 : : */
1703 : 1 : base_arg0 = g_path_get_basename (cmdline);
1704 : 1 : g_free (cmdline);
1705 : 1 : return base_arg0;
1706 : : #elif defined __OpenBSD__
1707 : : char **cmdline;
1708 : : char *base_arg0;
1709 : : gsize len;
1710 : :
1711 : : int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
1712 : :
1713 : : if (sysctl (mib, G_N_ELEMENTS (mib), NULL, &len, NULL, 0) == -1)
1714 : : return NULL;
1715 : :
1716 : : cmdline = g_malloc0 (len);
1717 : :
1718 : : if (sysctl (mib, G_N_ELEMENTS (mib), cmdline, &len, NULL, 0) == -1)
1719 : : {
1720 : : g_free (cmdline);
1721 : : return NULL;
1722 : : }
1723 : :
1724 : : /* We could just return cmdline, but I think it's better
1725 : : * to hold on to a smaller malloc block; the arguments
1726 : : * could be large.
1727 : : */
1728 : : base_arg0 = g_path_get_basename (*cmdline);
1729 : : g_free (cmdline);
1730 : : return base_arg0;
1731 : : #elif defined G_OS_WIN32
1732 : : const wchar_t *cmdline;
1733 : : wchar_t **wargv;
1734 : : int wargc;
1735 : : gchar *utf8_buf = NULL;
1736 : : char *base_arg0 = NULL;
1737 : :
1738 : : /* Pretend it's const, since we're not allowed to free it */
1739 : : cmdline = (const wchar_t *) GetCommandLineW ();
1740 : : if (G_UNLIKELY (cmdline == NULL))
1741 : : return NULL;
1742 : :
1743 : : /* Skip leading whitespace. CommandLineToArgvW() is documented
1744 : : * to behave weirdly with that. The character codes below
1745 : : * correspond to the *only* unicode characters that are
1746 : : * considered to be spaces by CommandLineToArgvW(). The rest
1747 : : * (such as 0xa0 - NO-BREAK SPACE) are treated as
1748 : : * normal characters.
1749 : : */
1750 : : while (cmdline[0] == 0x09 ||
1751 : : cmdline[0] == 0x0a ||
1752 : : cmdline[0] == 0x0c ||
1753 : : cmdline[0] == 0x0d ||
1754 : : cmdline[0] == 0x20)
1755 : : cmdline++;
1756 : :
1757 : : wargv = CommandLineToArgvW (cmdline, &wargc);
1758 : : if (G_UNLIKELY (wargv == NULL))
1759 : : return NULL;
1760 : :
1761 : : if (wargc > 0)
1762 : : utf8_buf = g_utf16_to_utf8 (wargv[0], -1, NULL, NULL, NULL);
1763 : :
1764 : : LocalFree (wargv);
1765 : :
1766 : : if (G_UNLIKELY (utf8_buf == NULL))
1767 : : return NULL;
1768 : :
1769 : : /* We could just return cmdline, but I think it's better
1770 : : * to hold on to a smaller malloc block; the arguments
1771 : : * could be large.
1772 : : */
1773 : : base_arg0 = g_path_get_basename (utf8_buf);
1774 : : g_free (utf8_buf);
1775 : : return base_arg0;
1776 : : #endif
1777 : :
1778 : : return NULL;
1779 : : }
1780 : :
1781 : : /**
1782 : : * g_option_context_parse:
1783 : : * @context: a #GOptionContext
1784 : : * @argc: (inout) (optional): a pointer to the number of command line arguments
1785 : : * @argv: (inout) (array length=argc) (optional): a pointer to the array of command line arguments
1786 : : * @error: a return location for errors
1787 : : *
1788 : : * Parses the command line arguments, recognizing options
1789 : : * which have been added to @context. A side-effect of
1790 : : * calling this function is that g_set_prgname() will be
1791 : : * called.
1792 : : *
1793 : : * If the parsing is successful, any parsed arguments are
1794 : : * removed from the array and @argc and @argv are updated
1795 : : * accordingly. A '--' option is stripped from @argv
1796 : : * unless there are unparsed options before and after it,
1797 : : * or some of the options after it start with '-'. In case
1798 : : * of an error, @argc and @argv are left unmodified.
1799 : : *
1800 : : * If automatic `--help` support is enabled
1801 : : * (see g_option_context_set_help_enabled()), and the
1802 : : * @argv array contains one of the recognized help options,
1803 : : * this function will produce help output to stdout and
1804 : : * call `exit (0)`.
1805 : : *
1806 : : * Note that function depends on the
1807 : : * [current locale](running.html#locale) for automatic
1808 : : * character set conversion of string and filename arguments.
1809 : : *
1810 : : * Returns: %TRUE if the parsing was successful,
1811 : : * %FALSE if an error occurred
1812 : : *
1813 : : * Since: 2.6
1814 : : **/
1815 : : gboolean
1816 : 355 : g_option_context_parse (GOptionContext *context,
1817 : : gint *argc,
1818 : : gchar ***argv,
1819 : : GError **error)
1820 : : {
1821 : : gint i, k;
1822 : : GList *list;
1823 : :
1824 : 355 : g_return_val_if_fail (context != NULL, FALSE);
1825 : :
1826 : : /* Set program name */
1827 : 355 : if (!g_get_prgname())
1828 : : {
1829 : : gchar *prgname;
1830 : :
1831 : 228 : if (argc && argv && *argc)
1832 : 227 : prgname = g_path_get_basename ((*argv)[0]);
1833 : : else
1834 : 1 : prgname = platform_get_argv0 ();
1835 : :
1836 : 228 : g_set_prgname_once (prgname ? prgname : "<unknown>");
1837 : :
1838 : 228 : g_free (prgname);
1839 : : }
1840 : :
1841 : : /* Call pre-parse hooks */
1842 : 355 : list = context->groups;
1843 : 406 : while (list)
1844 : : {
1845 : 51 : GOptionGroup *group = list->data;
1846 : :
1847 : 51 : if (group->pre_parse_func)
1848 : : {
1849 : 0 : if (!(* group->pre_parse_func) (context, group,
1850 : : group->user_data, error))
1851 : 0 : goto fail;
1852 : : }
1853 : :
1854 : 51 : list = list->next;
1855 : : }
1856 : :
1857 : 355 : if (context->main_group && context->main_group->pre_parse_func)
1858 : : {
1859 : 3 : if (!(* context->main_group->pre_parse_func) (context, context->main_group,
1860 : 3 : context->main_group->user_data, error))
1861 : 0 : goto fail;
1862 : : }
1863 : :
1864 : 355 : if (argc && argv)
1865 : : {
1866 : 352 : gboolean stop_parsing = FALSE;
1867 : 352 : gboolean has_unknown = FALSE;
1868 : 352 : gint separator_pos = 0;
1869 : :
1870 : 2031 : for (i = 1; i < *argc; i++)
1871 : : {
1872 : : gchar *arg, *dash;
1873 : 1709 : gboolean parsed = FALSE;
1874 : :
1875 : 1709 : if ((*argv)[i][0] == '-' && (*argv)[i][1] != '\0' && !stop_parsing)
1876 : : {
1877 : 516 : if ((*argv)[i][1] == '-')
1878 : : {
1879 : : /* -- option */
1880 : :
1881 : 500 : arg = (*argv)[i] + 2;
1882 : :
1883 : : /* '--' terminates list of arguments */
1884 : 500 : if (*arg == 0)
1885 : : {
1886 : 13 : separator_pos = i;
1887 : 13 : stop_parsing = TRUE;
1888 : 471 : continue;
1889 : : }
1890 : :
1891 : : /* Handle help options */
1892 : 487 : if (context->help_enabled)
1893 : : {
1894 : 486 : if (strcmp (arg, "help") == 0)
1895 : 6 : print_help (context, TRUE, NULL);
1896 : 480 : else if (strcmp (arg, "help-all") == 0)
1897 : 4 : print_help (context, FALSE, NULL);
1898 : 476 : else if (strncmp (arg, "help-", 5) == 0)
1899 : : {
1900 : 4 : list = context->groups;
1901 : :
1902 : 4 : while (list)
1903 : : {
1904 : 2 : GOptionGroup *group = list->data;
1905 : :
1906 : 2 : if (strcmp (arg + 5, group->name) == 0)
1907 : 2 : print_help (context, FALSE, group);
1908 : :
1909 : 0 : list = list->next;
1910 : : }
1911 : : }
1912 : : }
1913 : :
1914 : 947 : if (context->main_group &&
1915 : 472 : !parse_long_option (context, context->main_group, &i, arg,
1916 : : FALSE, argc, argv, error, &parsed))
1917 : 18 : goto fail;
1918 : :
1919 : 463 : if (parsed)
1920 : 453 : continue;
1921 : :
1922 : : /* Try the groups */
1923 : 10 : list = context->groups;
1924 : 12 : while (list)
1925 : : {
1926 : 5 : GOptionGroup *group = list->data;
1927 : :
1928 : 5 : if (!parse_long_option (context, group, &i, arg,
1929 : : FALSE, argc, argv, error, &parsed))
1930 : 0 : goto fail;
1931 : :
1932 : 5 : if (parsed)
1933 : 3 : break;
1934 : :
1935 : 2 : list = list->next;
1936 : : }
1937 : :
1938 : 10 : if (parsed)
1939 : 3 : continue;
1940 : :
1941 : : /* Now look for --<group>-<option> */
1942 : 7 : dash = strchr (arg, '-');
1943 : 7 : if (dash && arg < dash)
1944 : : {
1945 : : /* Try the groups */
1946 : 3 : list = context->groups;
1947 : 3 : while (list)
1948 : : {
1949 : 1 : GOptionGroup *group = list->data;
1950 : :
1951 : 1 : if (strncmp (group->name, arg, dash - arg) == 0)
1952 : : {
1953 : 1 : if (!parse_long_option (context, group, &i, dash + 1,
1954 : : TRUE, argc, argv, error, &parsed))
1955 : 0 : goto fail;
1956 : :
1957 : 1 : if (parsed)
1958 : 1 : break;
1959 : : }
1960 : :
1961 : 0 : list = list->next;
1962 : : }
1963 : : }
1964 : :
1965 : 7 : if (context->ignore_unknown)
1966 : 2 : continue;
1967 : : }
1968 : : else
1969 : : { /* short option */
1970 : 16 : gint new_i = i;
1971 : : size_t arg_length;
1972 : 16 : gboolean *nulled_out = NULL;
1973 : 16 : gboolean has_h_entry = context_has_h_entry (context);
1974 : 16 : arg = (*argv)[i] + 1;
1975 : 16 : arg_length = strlen (arg);
1976 : 16 : nulled_out = g_newa0 (gboolean, arg_length);
1977 : 38 : for (size_t j = 0; j < arg_length; j++)
1978 : : {
1979 : 24 : if (context->help_enabled && (arg[j] == '?' ||
1980 : 24 : (arg[j] == 'h' && !has_h_entry)))
1981 : 0 : print_help (context, TRUE, NULL);
1982 : 24 : parsed = FALSE;
1983 : 48 : if (context->main_group &&
1984 : 24 : !parse_short_option (context, context->main_group,
1985 : 24 : i, &new_i, arg[j],
1986 : : argc, argv, error, &parsed))
1987 : 1 : goto fail;
1988 : 23 : if (!parsed)
1989 : : {
1990 : : /* Try the groups */
1991 : 7 : list = context->groups;
1992 : 7 : while (list)
1993 : : {
1994 : 1 : GOptionGroup *group = list->data;
1995 : 1 : if (!parse_short_option (context, group, i, &new_i, arg[j],
1996 : : argc, argv, error, &parsed))
1997 : 0 : goto fail;
1998 : 1 : if (parsed)
1999 : 1 : break;
2000 : 0 : list = list->next;
2001 : : }
2002 : : }
2003 : :
2004 : 23 : if (context->ignore_unknown && parsed)
2005 : 6 : nulled_out[j] = TRUE;
2006 : 17 : else if (context->ignore_unknown)
2007 : 5 : continue;
2008 : 12 : else if (!parsed)
2009 : 1 : break;
2010 : : /* !context->ignore_unknown && parsed */
2011 : : }
2012 : 15 : if (context->ignore_unknown)
2013 : : {
2014 : 5 : gchar *new_arg = NULL;
2015 : 5 : gint arg_index = 0;
2016 : 16 : for (size_t j = 0; j < arg_length; j++)
2017 : : {
2018 : 11 : if (!nulled_out[j])
2019 : : {
2020 : 5 : if (!new_arg)
2021 : 2 : new_arg = g_malloc (arg_length + 1);
2022 : 5 : new_arg[arg_index++] = arg[j];
2023 : : }
2024 : : }
2025 : 5 : if (new_arg)
2026 : 2 : new_arg[arg_index] = '\0';
2027 : 5 : add_pending_null (context, &((*argv)[i]), new_arg);
2028 : 5 : i = new_i;
2029 : : }
2030 : 10 : else if (parsed)
2031 : : {
2032 : 9 : add_pending_null (context, &((*argv)[i]), NULL);
2033 : 9 : i = new_i;
2034 : : }
2035 : : }
2036 : :
2037 : 20 : if (!parsed)
2038 : 6 : has_unknown = TRUE;
2039 : :
2040 : 20 : if (!parsed && !context->ignore_unknown)
2041 : : {
2042 : 5 : g_set_error (error,
2043 : : G_OPTION_ERROR, G_OPTION_ERROR_UNKNOWN_OPTION,
2044 : 5 : _("Unknown option %s"), (*argv)[i]);
2045 : 5 : goto fail;
2046 : : }
2047 : : }
2048 : : else
2049 : : {
2050 : 1193 : if (context->strict_posix)
2051 : 6 : stop_parsing = TRUE;
2052 : :
2053 : : /* Collect remaining args */
2054 : 2384 : if (context->main_group &&
2055 : 1191 : !parse_remaining_arg (context, context->main_group, &i,
2056 : : argc, argv, error, &parsed))
2057 : 0 : goto fail;
2058 : :
2059 : 1193 : if (!parsed && (has_unknown || (*argv)[i][0] == '-'))
2060 : 6 : separator_pos = 0;
2061 : : }
2062 : : }
2063 : :
2064 : 322 : if (separator_pos > 0)
2065 : 11 : add_pending_null (context, &((*argv)[separator_pos]), NULL);
2066 : :
2067 : : }
2068 : :
2069 : : /* Call post-parse hooks */
2070 : 325 : list = context->groups;
2071 : 368 : while (list)
2072 : : {
2073 : 43 : GOptionGroup *group = list->data;
2074 : :
2075 : 43 : if (group->post_parse_func)
2076 : : {
2077 : 0 : if (!(* group->post_parse_func) (context, group,
2078 : : group->user_data, error))
2079 : 0 : goto fail;
2080 : : }
2081 : :
2082 : 43 : list = list->next;
2083 : : }
2084 : :
2085 : 325 : if (context->main_group && context->main_group->post_parse_func)
2086 : : {
2087 : 3 : if (!(* context->main_group->post_parse_func) (context, context->main_group,
2088 : 3 : context->main_group->user_data, error))
2089 : 3 : goto fail;
2090 : : }
2091 : :
2092 : 322 : if (argc && argv)
2093 : : {
2094 : 319 : free_pending_nulls (context, TRUE);
2095 : :
2096 : 1628 : for (i = 1; i < *argc; i++)
2097 : : {
2098 : 1975 : for (k = i; k < *argc; k++)
2099 : 1813 : if ((*argv)[k] != NULL)
2100 : 1147 : break;
2101 : :
2102 : 1309 : if (k > i)
2103 : : {
2104 : 192 : k -= i;
2105 : 1230 : for (int j = i + k; j < *argc; j++)
2106 : : {
2107 : 1038 : (*argv)[j-k] = (*argv)[j];
2108 : 1038 : (*argv)[j] = NULL;
2109 : : }
2110 : 192 : *argc -= k;
2111 : : }
2112 : : }
2113 : : }
2114 : :
2115 : 322 : return TRUE;
2116 : :
2117 : 21 : fail:
2118 : :
2119 : : /* Call error hooks */
2120 : 21 : list = context->groups;
2121 : 22 : while (list)
2122 : : {
2123 : 1 : GOptionGroup *group = list->data;
2124 : :
2125 : 1 : if (group->error_func)
2126 : 0 : (* group->error_func) (context, group,
2127 : : group->user_data, error);
2128 : :
2129 : 1 : list = list->next;
2130 : : }
2131 : :
2132 : 21 : if (context->main_group && context->main_group->error_func)
2133 : 1 : (* context->main_group->error_func) (context, context->main_group,
2134 : 1 : context->main_group->user_data, error);
2135 : :
2136 : 21 : free_changes_list (context, TRUE);
2137 : 21 : free_pending_nulls (context, FALSE);
2138 : :
2139 : 21 : return FALSE;
2140 : : }
2141 : :
2142 : : /**
2143 : : * g_option_group_new:
2144 : : * @name: the name for the option group, this is used to provide
2145 : : * help for the options in this group with `--help-`@name
2146 : : * @description: a description for this group to be shown in
2147 : : * `--help`. This string is translated using the translation
2148 : : * domain or translation function of the group
2149 : : * @help_description: a description for the `--help-`@name option.
2150 : : * This string is translated using the translation domain or translation function
2151 : : * of the group
2152 : : * @user_data: (nullable): user data that will be passed to the pre- and post-parse hooks,
2153 : : * the error hook and to callbacks of %G_OPTION_ARG_CALLBACK options, or %NULL
2154 : : * @destroy: (nullable): a function that will be called to free @user_data, or %NULL
2155 : : *
2156 : : * Creates a new #GOptionGroup.
2157 : : *
2158 : : * @description is typically used to provide a title for the group. If so, it
2159 : : * is recommended that it’s written in title case, and has a trailing colon so
2160 : : * that it matches the style of built-in GLib group titles such as
2161 : : * ‘Application Options:’.
2162 : : *
2163 : : * Returns: a newly created option group. It should be added
2164 : : * to a #GOptionContext or freed with g_option_group_unref().
2165 : : *
2166 : : * Since: 2.6
2167 : : **/
2168 : : GOptionGroup *
2169 : 364 : g_option_group_new (const gchar *name,
2170 : : const gchar *description,
2171 : : const gchar *help_description,
2172 : : gpointer user_data,
2173 : : GDestroyNotify destroy)
2174 : :
2175 : : {
2176 : : GOptionGroup *group;
2177 : :
2178 : 364 : group = g_new0 (GOptionGroup, 1);
2179 : 364 : group->ref_count = 1;
2180 : 364 : group->name = g_strdup (name);
2181 : 364 : group->description = g_strdup (description);
2182 : 364 : group->help_description = g_strdup (help_description);
2183 : 364 : group->user_data = user_data;
2184 : 364 : group->destroy_notify = destroy;
2185 : :
2186 : 364 : return group;
2187 : : }
2188 : :
2189 : :
2190 : : /**
2191 : : * g_option_group_free:
2192 : : * @group: a #GOptionGroup
2193 : : *
2194 : : * Frees a #GOptionGroup. Note that you must not free groups
2195 : : * which have been added to a #GOptionContext.
2196 : : *
2197 : : * Since: 2.6
2198 : : *
2199 : : * Deprecated: 2.44: Use g_option_group_unref() instead.
2200 : : */
2201 : : void
2202 : 0 : g_option_group_free (GOptionGroup *group)
2203 : : {
2204 : 0 : g_option_group_unref (group);
2205 : 0 : }
2206 : :
2207 : : /**
2208 : : * g_option_group_ref:
2209 : : * @group: a #GOptionGroup
2210 : : *
2211 : : * Increments the reference count of @group by one.
2212 : : *
2213 : : * Returns: a #GOptionGroup
2214 : : *
2215 : : * Since: 2.44
2216 : : */
2217 : : GOptionGroup *
2218 : 0 : g_option_group_ref (GOptionGroup *group)
2219 : : {
2220 : 0 : g_return_val_if_fail (group != NULL, NULL);
2221 : :
2222 : 0 : group->ref_count++;
2223 : :
2224 : 0 : return group;
2225 : : }
2226 : :
2227 : : /**
2228 : : * g_option_group_unref:
2229 : : * @group: a #GOptionGroup
2230 : : *
2231 : : * Decrements the reference count of @group by one.
2232 : : * If the reference count drops to 0, the @group will be freed.
2233 : : * and all memory allocated by the @group is released.
2234 : : *
2235 : : * Since: 2.44
2236 : : */
2237 : : void
2238 : 350 : g_option_group_unref (GOptionGroup *group)
2239 : : {
2240 : 350 : g_return_if_fail (group != NULL);
2241 : :
2242 : 350 : if (--group->ref_count == 0)
2243 : : {
2244 : 350 : g_free (group->name);
2245 : 350 : g_free (group->description);
2246 : 350 : g_free (group->help_description);
2247 : :
2248 : 350 : g_free (group->entries);
2249 : :
2250 : 350 : if (group->destroy_notify)
2251 : 1 : (* group->destroy_notify) (group->user_data);
2252 : :
2253 : 350 : if (group->translate_notify)
2254 : 339 : (* group->translate_notify) (group->translate_data);
2255 : :
2256 : 350 : g_free (group);
2257 : : }
2258 : : }
2259 : :
2260 : : /**
2261 : : * g_option_group_add_entries:
2262 : : * @group: a #GOptionGroup
2263 : : * @entries: (array zero-terminated=1): a %NULL-terminated array of #GOptionEntrys
2264 : : *
2265 : : * Adds the options specified in @entries to @group.
2266 : : *
2267 : : * Since: 2.6
2268 : : **/
2269 : : void
2270 : 367 : g_option_group_add_entries (GOptionGroup *group,
2271 : : const GOptionEntry *entries)
2272 : : {
2273 : : gsize i, n_entries;
2274 : :
2275 : 367 : g_return_if_fail (group != NULL);
2276 : 367 : g_return_if_fail (entries != NULL);
2277 : :
2278 : 1542 : for (n_entries = 0; entries[n_entries].long_name != NULL; n_entries++) ;
2279 : :
2280 : 367 : g_return_if_fail (n_entries <= G_MAXSIZE - group->n_entries);
2281 : :
2282 : 367 : group->entries = g_renew (GOptionEntry, group->entries, group->n_entries + n_entries);
2283 : :
2284 : : /* group->entries could be NULL in the trivial case where we add no
2285 : : * entries to no entries */
2286 : 367 : if (n_entries != 0)
2287 : 280 : memcpy (group->entries + group->n_entries, entries, sizeof (GOptionEntry) * n_entries);
2288 : :
2289 : 1542 : for (i = group->n_entries; i < group->n_entries + n_entries; i++)
2290 : : {
2291 : 1175 : gchar c = group->entries[i].short_name;
2292 : :
2293 : 1175 : if (c == '-' || (c != 0 && !g_ascii_isprint (c)))
2294 : : {
2295 : 0 : g_warning (G_STRLOC ": ignoring invalid short option '%c' (%d) in entry %s:%s",
2296 : : c, c, group->name, group->entries[i].long_name);
2297 : 0 : group->entries[i].short_name = '\0';
2298 : : }
2299 : :
2300 : 1175 : if (group->entries[i].arg != G_OPTION_ARG_NONE &&
2301 : 493 : (group->entries[i].flags & G_OPTION_FLAG_REVERSE) != 0)
2302 : : {
2303 : 1 : g_warning (G_STRLOC ": ignoring reverse flag on option of arg-type %d in entry %s:%s",
2304 : : group->entries[i].arg, group->name, group->entries[i].long_name);
2305 : :
2306 : 1 : group->entries[i].flags &= ~G_OPTION_FLAG_REVERSE;
2307 : : }
2308 : :
2309 : 1175 : if (group->entries[i].arg != G_OPTION_ARG_CALLBACK &&
2310 : 1151 : (group->entries[i].flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG|G_OPTION_FLAG_FILENAME)) != 0)
2311 : : {
2312 : 1 : g_warning (G_STRLOC ": ignoring no-arg, optional-arg or filename flags (%d) on option of arg-type %d in entry %s:%s",
2313 : : group->entries[i].flags, group->entries[i].arg, group->name, group->entries[i].long_name);
2314 : :
2315 : 1 : group->entries[i].flags &= ~(G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG|G_OPTION_FLAG_FILENAME);
2316 : : }
2317 : : }
2318 : :
2319 : 367 : group->n_entries += n_entries;
2320 : : }
2321 : :
2322 : : /**
2323 : : * g_option_group_set_parse_hooks:
2324 : : * @group: a #GOptionGroup
2325 : : * @pre_parse_func: (nullable): a function to call before parsing, or %NULL
2326 : : * @post_parse_func: (nullable): a function to call after parsing, or %NULL
2327 : : *
2328 : : * Associates two functions with @group which will be called
2329 : : * from g_option_context_parse() before the first option is parsed
2330 : : * and after the last option has been parsed, respectively.
2331 : : *
2332 : : * Note that the user data to be passed to @pre_parse_func and
2333 : : * @post_parse_func can be specified when constructing the group
2334 : : * with g_option_group_new().
2335 : : *
2336 : : * Since: 2.6
2337 : : **/
2338 : : void
2339 : 3 : g_option_group_set_parse_hooks (GOptionGroup *group,
2340 : : GOptionParseFunc pre_parse_func,
2341 : : GOptionParseFunc post_parse_func)
2342 : : {
2343 : 3 : g_return_if_fail (group != NULL);
2344 : :
2345 : 3 : group->pre_parse_func = pre_parse_func;
2346 : 3 : group->post_parse_func = post_parse_func;
2347 : : }
2348 : :
2349 : : /**
2350 : : * g_option_group_set_error_hook:
2351 : : * @group: a #GOptionGroup
2352 : : * @error_func: a function to call when an error occurs
2353 : : *
2354 : : * Associates a function with @group which will be called
2355 : : * from g_option_context_parse() when an error occurs.
2356 : : *
2357 : : * Note that the user data to be passed to @error_func can be
2358 : : * specified when constructing the group with g_option_group_new().
2359 : : *
2360 : : * Since: 2.6
2361 : : **/
2362 : : void
2363 : 1 : g_option_group_set_error_hook (GOptionGroup *group,
2364 : : GOptionErrorFunc error_func)
2365 : : {
2366 : 1 : g_return_if_fail (group != NULL);
2367 : :
2368 : 1 : group->error_func = error_func;
2369 : : }
2370 : :
2371 : :
2372 : : /**
2373 : : * g_option_group_set_translate_func:
2374 : : * @group: a #GOptionGroup
2375 : : * @func: (nullable): the #GTranslateFunc, or %NULL
2376 : : * @data: (nullable): user data to pass to @func, or %NULL
2377 : : * @destroy_notify: (nullable): a function which gets called to free @data, or %NULL
2378 : : *
2379 : : * Sets the function which is used to translate user-visible strings,
2380 : : * for `--help` output. Different groups can use different
2381 : : * #GTranslateFuncs. If @func is %NULL, strings are not translated.
2382 : : *
2383 : : * If you are using gettext(), you only need to set the translation
2384 : : * domain, see g_option_group_set_translation_domain().
2385 : : *
2386 : : * Since: 2.6
2387 : : **/
2388 : : void
2389 : 348 : g_option_group_set_translate_func (GOptionGroup *group,
2390 : : GTranslateFunc func,
2391 : : gpointer data,
2392 : : GDestroyNotify destroy_notify)
2393 : : {
2394 : 348 : g_return_if_fail (group != NULL);
2395 : :
2396 : 348 : if (group->translate_notify)
2397 : 1 : group->translate_notify (group->translate_data);
2398 : :
2399 : 348 : group->translate_func = func;
2400 : 348 : group->translate_data = data;
2401 : 348 : group->translate_notify = destroy_notify;
2402 : : }
2403 : :
2404 : : static const gchar *
2405 : 37 : dgettext_swapped (const gchar *msgid,
2406 : : const gchar *domainname)
2407 : : {
2408 : 37 : return g_dgettext (domainname, msgid);
2409 : : }
2410 : :
2411 : : /**
2412 : : * g_option_group_set_translation_domain:
2413 : : * @group: a #GOptionGroup
2414 : : * @domain: the domain to use
2415 : : *
2416 : : * A convenience function to use gettext() for translating
2417 : : * user-visible strings.
2418 : : *
2419 : : * Since: 2.6
2420 : : **/
2421 : : void
2422 : 348 : g_option_group_set_translation_domain (GOptionGroup *group,
2423 : : const gchar *domain)
2424 : : {
2425 : 348 : g_return_if_fail (group != NULL);
2426 : :
2427 : 348 : g_option_group_set_translate_func (group,
2428 : : (GTranslateFunc)dgettext_swapped,
2429 : 348 : g_strdup (domain),
2430 : : g_free);
2431 : : }
2432 : :
2433 : : /**
2434 : : * g_option_context_set_translate_func:
2435 : : * @context: a #GOptionContext
2436 : : * @func: (nullable): the #GTranslateFunc, or %NULL
2437 : : * @data: (nullable): user data to pass to @func, or %NULL
2438 : : * @destroy_notify: (nullable): a function which gets called to free @data, or %NULL
2439 : : *
2440 : : * Sets the function which is used to translate the contexts
2441 : : * user-visible strings, for `--help` output. If @func is %NULL,
2442 : : * strings are not translated.
2443 : : *
2444 : : * Note that option groups have their own translation functions,
2445 : : * this function only affects the @parameter_string (see g_option_context_new()),
2446 : : * the summary (see g_option_context_set_summary()) and the description
2447 : : * (see g_option_context_set_description()).
2448 : : *
2449 : : * If you are using gettext(), you only need to set the translation
2450 : : * domain, see g_option_context_set_translation_domain().
2451 : : *
2452 : : * Since: 2.12
2453 : : **/
2454 : : void
2455 : 95 : g_option_context_set_translate_func (GOptionContext *context,
2456 : : GTranslateFunc func,
2457 : : gpointer data,
2458 : : GDestroyNotify destroy_notify)
2459 : : {
2460 : 95 : g_return_if_fail (context != NULL);
2461 : :
2462 : 95 : if (context->translate_notify)
2463 : 0 : context->translate_notify (context->translate_data);
2464 : :
2465 : 95 : context->translate_func = func;
2466 : 95 : context->translate_data = data;
2467 : 95 : context->translate_notify = destroy_notify;
2468 : : }
2469 : :
2470 : : /**
2471 : : * g_option_context_set_translation_domain:
2472 : : * @context: a #GOptionContext
2473 : : * @domain: the domain to use
2474 : : *
2475 : : * A convenience function to use gettext() for translating
2476 : : * user-visible strings.
2477 : : *
2478 : : * Since: 2.12
2479 : : **/
2480 : : void
2481 : 94 : g_option_context_set_translation_domain (GOptionContext *context,
2482 : : const gchar *domain)
2483 : : {
2484 : 94 : g_return_if_fail (context != NULL);
2485 : :
2486 : 94 : g_option_context_set_translate_func (context,
2487 : : (GTranslateFunc)dgettext_swapped,
2488 : 94 : g_strdup (domain),
2489 : : g_free);
2490 : : }
2491 : :
2492 : : /**
2493 : : * g_option_context_set_summary:
2494 : : * @context: a #GOptionContext
2495 : : * @summary: (nullable): a string to be shown in `--help` output
2496 : : * before the list of options, or %NULL
2497 : : *
2498 : : * Adds a string to be displayed in `--help` output before the list
2499 : : * of options. This is typically a summary of the program functionality.
2500 : : *
2501 : : * Note that the summary is translated (see
2502 : : * g_option_context_set_translate_func() and
2503 : : * g_option_context_set_translation_domain()).
2504 : : *
2505 : : * Since: 2.12
2506 : : */
2507 : : void
2508 : 169 : g_option_context_set_summary (GOptionContext *context,
2509 : : const gchar *summary)
2510 : : {
2511 : 169 : g_return_if_fail (context != NULL);
2512 : :
2513 : 169 : g_free (context->summary);
2514 : 169 : context->summary = g_strdup (summary);
2515 : : }
2516 : :
2517 : :
2518 : : /**
2519 : : * g_option_context_get_summary:
2520 : : * @context: a #GOptionContext
2521 : : *
2522 : : * Returns the summary. See g_option_context_set_summary().
2523 : : *
2524 : : * Returns: the summary
2525 : : *
2526 : : * Since: 2.12
2527 : : */
2528 : : const gchar *
2529 : 2 : g_option_context_get_summary (GOptionContext *context)
2530 : : {
2531 : 2 : g_return_val_if_fail (context != NULL, NULL);
2532 : :
2533 : 2 : return context->summary;
2534 : : }
2535 : :
2536 : : /**
2537 : : * g_option_context_set_description:
2538 : : * @context: a #GOptionContext
2539 : : * @description: (nullable): a string to be shown in `--help` output
2540 : : * after the list of options, or %NULL
2541 : : *
2542 : : * Adds a string to be displayed in `--help` output after the list
2543 : : * of options. This text often includes a bug reporting address.
2544 : : *
2545 : : * Note that the summary is translated (see
2546 : : * g_option_context_set_translate_func()).
2547 : : *
2548 : : * Since: 2.12
2549 : : */
2550 : : void
2551 : 51 : g_option_context_set_description (GOptionContext *context,
2552 : : const gchar *description)
2553 : : {
2554 : 51 : g_return_if_fail (context != NULL);
2555 : :
2556 : 51 : g_free (context->description);
2557 : 51 : context->description = g_strdup (description);
2558 : : }
2559 : :
2560 : :
2561 : : /**
2562 : : * g_option_context_get_description:
2563 : : * @context: a #GOptionContext
2564 : : *
2565 : : * Returns the description. See g_option_context_set_description().
2566 : : *
2567 : : * Returns: the description
2568 : : *
2569 : : * Since: 2.12
2570 : : */
2571 : : const gchar *
2572 : 2 : g_option_context_get_description (GOptionContext *context)
2573 : : {
2574 : 2 : g_return_val_if_fail (context != NULL, NULL);
2575 : :
2576 : 2 : return context->description;
2577 : : }
2578 : :
2579 : : /**
2580 : : * g_option_context_parse_strv:
2581 : : * @context: a #GOptionContext
2582 : : * @arguments: (inout) (array zero-terminated=1) (optional): a pointer
2583 : : * to the command line arguments (which must be in UTF-8 on Windows).
2584 : : * Starting with GLib 2.62, @arguments can be %NULL, which matches
2585 : : * g_option_context_parse().
2586 : : * @error: a return location for errors
2587 : : *
2588 : : * Parses the command line arguments.
2589 : : *
2590 : : * This function is similar to g_option_context_parse() except that it
2591 : : * respects the normal memory rules when dealing with a strv instead of
2592 : : * assuming that the passed-in array is the argv of the main function.
2593 : : *
2594 : : * In particular, strings that are removed from the arguments list will
2595 : : * be freed using g_free().
2596 : : *
2597 : : * On Windows, the strings are expected to be in UTF-8. This is in
2598 : : * contrast to g_option_context_parse() which expects them to be in the
2599 : : * system codepage, which is how they are passed as @argv to main().
2600 : : * See g_win32_get_command_line() for a solution.
2601 : : *
2602 : : * This function is useful if you are trying to use #GOptionContext with
2603 : : * #GApplication.
2604 : : *
2605 : : * Returns: %TRUE if the parsing was successful,
2606 : : * %FALSE if an error occurred
2607 : : *
2608 : : * Since: 2.40
2609 : : **/
2610 : : gboolean
2611 : 50 : g_option_context_parse_strv (GOptionContext *context,
2612 : : gchar ***arguments,
2613 : : GError **error)
2614 : : {
2615 : : gboolean success;
2616 : : gint argc;
2617 : :
2618 : 50 : g_return_val_if_fail (context != NULL, FALSE);
2619 : :
2620 : 50 : context->strv_mode = TRUE;
2621 : 50 : argc = arguments && *arguments ? g_strv_length (*arguments) : 0;
2622 : 50 : success = g_option_context_parse (context, &argc, arguments, error);
2623 : 49 : context->strv_mode = FALSE;
2624 : :
2625 : 49 : return success;
2626 : : }
|