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