Coverage Report

Created: 2025-11-16 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/glib/goption.c
Line
Count
Source
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
0
#define TRANSLATE(group, str) (((group)->translate_func ? (* (group)->translate_func) ((str), (group)->translate_data) : (str)))
45
46
0
#define NO_ARG(entry) ((entry)->arg == G_OPTION_ARG_NONE ||       \
47
0
                       ((entry)->arg == G_OPTION_ARG_CALLBACK &&  \
48
0
                        ((entry)->flags & G_OPTION_FLAG_NO_ARG)))
49
50
0
#define OPTIONAL_ARG(entry) ((entry)->arg == G_OPTION_ARG_CALLBACK &&  \
51
0
                       (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
_g_unichar_get_width (gunichar c)
142
0
{
143
0
  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
0
  if (g_unichar_iswide (c))
149
0
    return 2;
150
151
0
  return 1;
152
0
}
153
154
static glong
155
_g_utf8_strwidth (const gchar *p)
156
0
{
157
0
  glong len = 0;
158
0
  g_return_val_if_fail (p != NULL, 0);
159
160
0
  while (*p)
161
0
    {
162
0
      len += _g_unichar_get_width (g_utf8_get_char (p));
163
0
      p = g_utf8_next_char (p);
164
0
    }
165
166
0
  return len;
167
0
}
168
169
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
g_option_context_new (const gchar *parameter_string)
204
205
0
{
206
0
  GOptionContext *context;
207
208
0
  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
0
  if (parameter_string != NULL && *parameter_string == '\0')
213
0
    parameter_string = NULL;
214
215
0
  context->parameter_string = g_strdup (parameter_string);
216
0
  context->strict_posix = FALSE;
217
0
  context->help_enabled = TRUE;
218
0
  context->ignore_unknown = FALSE;
219
220
0
  return context;
221
0
}
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
void g_option_context_free (GOptionContext *context)
236
0
{
237
0
  g_return_if_fail (context != NULL);
238
239
0
  g_list_free_full (context->groups, (GDestroyNotify) g_option_group_unref);
240
241
0
  if (context->main_group)
242
0
    g_option_group_unref (context->main_group);
243
244
0
  free_changes_list (context, FALSE);
245
0
  free_pending_nulls (context, FALSE);
246
247
0
  g_free (context->parameter_string);
248
0
  g_free (context->summary);
249
0
  g_free (context->description);
250
251
0
  if (context->translate_notify)
252
0
    (* context->translate_notify) (context->translate_data);
253
254
0
  g_free (context);
255
0
}
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
void g_option_context_set_help_enabled (GOptionContext *context,
271
                                        gboolean        help_enabled)
272
273
0
{
274
0
  g_return_if_fail (context != NULL);
275
276
0
  context->help_enabled = help_enabled;
277
0
}
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
g_option_context_get_help_enabled (GOptionContext *context)
292
0
{
293
0
  g_return_val_if_fail (context != NULL, FALSE);
294
295
0
  return context->help_enabled;
296
0
}
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
g_option_context_set_ignore_unknown_options (GOptionContext *context,
316
                                             gboolean        ignore_unknown)
317
0
{
318
0
  g_return_if_fail (context != NULL);
319
320
0
  context->ignore_unknown = ignore_unknown;
321
0
}
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
g_option_context_get_ignore_unknown_options (GOptionContext *context)
336
0
{
337
0
  g_return_val_if_fail (context != NULL, FALSE);
338
339
0
  return context->ignore_unknown;
340
0
}
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
g_option_context_set_strict_posix (GOptionContext *context,
376
                                   gboolean        strict_posix)
377
0
{
378
0
  g_return_if_fail (context != NULL);
379
380
0
  context->strict_posix = strict_posix;
381
0
}
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
g_option_context_get_strict_posix (GOptionContext *context)
397
0
{
398
0
  g_return_val_if_fail (context != NULL, FALSE);
399
400
0
  return context->strict_posix;
401
0
}
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
g_option_context_add_group (GOptionContext *context,
416
                            GOptionGroup   *group)
417
0
{
418
0
  GList *list;
419
420
0
  g_return_if_fail (context != NULL);
421
0
  g_return_if_fail (group != NULL);
422
0
  g_return_if_fail (group->name != NULL);
423
0
  g_return_if_fail (group->description != NULL);
424
0
  g_return_if_fail (group->help_description != NULL);
425
426
0
  for (list = context->groups; list; list = list->next)
427
0
    {
428
0
      GOptionGroup *g = (GOptionGroup *)list->data;
429
430
0
      if ((group->name == NULL && g->name == NULL) ||
431
0
          (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
0
                   group->name);
434
0
    }
435
436
0
  context->groups = g_list_append (context->groups, group);
437
0
}
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
g_option_context_set_main_group (GOptionContext *context,
453
                                 GOptionGroup   *group)
454
0
{
455
0
  g_return_if_fail (context != NULL);
456
0
  g_return_if_fail (group != NULL);
457
458
0
  if (context->main_group)
459
0
    {
460
0
      g_warning ("This GOptionContext already has a main group");
461
462
0
      return;
463
0
    }
464
465
0
  context->main_group = group;
466
0
}
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
g_option_context_get_main_group (GOptionContext *context)
482
0
{
483
0
  g_return_val_if_fail (context != NULL, NULL);
484
485
0
  return context->main_group;
486
0
}
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
g_option_context_add_main_entries (GOptionContext      *context,
503
                                   const GOptionEntry  *entries,
504
                                   const gchar         *translation_domain)
505
0
{
506
0
  g_return_if_fail (context != NULL);
507
0
  g_return_if_fail (entries != NULL);
508
509
0
  if (!context->main_group)
510
0
    context->main_group = g_option_group_new (NULL, NULL, NULL, NULL, NULL);
511
512
0
  g_option_group_add_entries (context->main_group, entries);
513
0
  g_option_group_set_translation_domain (context->main_group, translation_domain);
514
0
}
515
516
static size_t
517
calculate_max_length (GOptionGroup *group,
518
                      GHashTable   *aliases)
519
0
{
520
0
  GOptionEntry *entry;
521
0
  gsize i, len, max_length;
522
0
  const gchar *long_name;
523
524
0
  max_length = 0;
525
526
0
  for (i = 0; i < group->n_entries; i++)
527
0
    {
528
0
      entry = &group->entries[i];
529
530
0
      if (entry->flags & G_OPTION_FLAG_HIDDEN)
531
0
        continue;
532
533
0
      long_name = g_hash_table_lookup (aliases, &entry->long_name);
534
0
      if (!long_name)
535
0
        long_name = entry->long_name;
536
0
      len = _g_utf8_strwidth (long_name);
537
538
0
      if (entry->short_name)
539
0
        len += 4;
540
541
0
      if (!NO_ARG (entry) && entry->arg_description)
542
0
        len += 1 + _g_utf8_strwidth (TRANSLATE (group, entry->arg_description));
543
544
      /* " (deprecated)" */
545
0
      if (entry->flags & G_OPTION_FLAG_DEPRECATED)
546
0
        len += 3 + _g_utf8_strwidth (_("deprecated"));
547
548
0
      max_length = MAX (max_length, len);
549
0
    }
550
551
0
  return max_length;
552
0
}
553
554
static void
555
print_entry (GOptionGroup       *group,
556
             size_t              max_length,
557
             const GOptionEntry *entry,
558
             GString            *string,
559
             GHashTable         *aliases)
560
0
{
561
0
  GString *str;
562
0
  const gchar *long_name;
563
564
0
  if (entry->flags & G_OPTION_FLAG_HIDDEN)
565
0
    return;
566
567
0
  if (entry->long_name[0] == 0)
568
0
    return;
569
570
0
  long_name = g_hash_table_lookup (aliases, &entry->long_name);
571
0
  if (!long_name)
572
0
    long_name = entry->long_name;
573
574
0
  str = g_string_new (NULL);
575
576
0
  if (entry->short_name)
577
0
    g_string_append_printf (str, "  -%c, --%s", entry->short_name, long_name);
578
0
  else
579
0
    g_string_append_printf (str, "  --%s", long_name);
580
581
0
  if (entry->arg_description)
582
0
    g_string_append_printf (str, "=%s", TRANSLATE (group, entry->arg_description));
583
584
0
  if (entry->flags & G_OPTION_FLAG_DEPRECATED)
585
0
    {
586
0
      const char *deprecated = _("deprecated");
587
0
      g_string_append_printf (str, " (%s)", deprecated);
588
0
    }
589
590
0
  g_string_append_printf (string, "%s%*s %s\n", str->str,
591
0
                          (int) (max_length + 4 - _g_utf8_strwidth (str->str)), "",
592
0
                          entry->description ? TRANSLATE (group, entry->description) : "");
593
594
0
  g_string_free (str, TRUE);
595
0
}
596
597
static gboolean
598
group_has_visible_entries (GOptionContext *context,
599
                           GOptionGroup *group,
600
                           gboolean      main_entries)
601
0
{
602
0
  GOptionFlags reject_filter = G_OPTION_FLAG_HIDDEN;
603
0
  GOptionEntry *entry;
604
0
  size_t i, l;
605
0
  gboolean main_group = group == context->main_group;
606
607
0
  if (!main_entries)
608
0
    reject_filter |= G_OPTION_FLAG_IN_MAIN;
609
610
0
  for (i = 0, l = (group ? group->n_entries : 0); i < l; i++)
611
0
    {
612
0
      entry = &group->entries[i];
613
614
0
      if (main_entries && !main_group && !(entry->flags & G_OPTION_FLAG_IN_MAIN))
615
0
        continue;
616
0
      if (entry->long_name[0] == 0) /* ignore rest entry */
617
0
        continue;
618
0
      if (!(entry->flags & reject_filter))
619
0
        return TRUE;
620
0
    }
621
622
0
  return FALSE;
623
0
}
624
625
static gboolean
626
group_list_has_visible_entries (GOptionContext *context,
627
                                GList          *group_list,
628
                                gboolean       main_entries)
629
0
{
630
0
  while (group_list)
631
0
    {
632
0
      if (group_has_visible_entries (context, group_list->data, main_entries))
633
0
        return TRUE;
634
635
0
      group_list = group_list->next;
636
0
    }
637
638
0
  return FALSE;
639
0
}
640
641
static gboolean
642
context_has_h_entry (GOptionContext *context)
643
0
{
644
0
  gsize i;
645
0
  GList *list;
646
647
0
  if (context->main_group)
648
0
    {
649
0
      for (i = 0; i < context->main_group->n_entries; i++)
650
0
        {
651
0
          if (context->main_group->entries[i].short_name == 'h')
652
0
            return TRUE;
653
0
        }
654
0
    }
655
656
0
  for (list = context->groups; list != NULL; list = g_list_next (list))
657
0
    {
658
0
     GOptionGroup *group;
659
660
0
      group = (GOptionGroup*)list->data;
661
0
      for (i = 0; i < group->n_entries; i++)
662
0
        {
663
0
          if (group->entries[i].short_name == 'h')
664
0
            return TRUE;
665
0
        }
666
0
    }
667
0
  return FALSE;
668
0
}
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
g_option_context_get_help (GOptionContext *context,
690
                           gboolean        main_help,
691
                           GOptionGroup   *group)
692
0
{
693
0
  GList *list;
694
0
  size_t max_length = 0, len;
695
0
  gsize i;
696
0
  GOptionEntry *entry;
697
0
  GHashTable *shadow_map;
698
0
  GHashTable *aliases;
699
0
  gboolean seen[256];
700
0
  const gchar *rest_description;
701
0
  GString *string;
702
0
  guchar token;
703
704
0
  g_return_val_if_fail (context != NULL, NULL);
705
706
0
  string = g_string_sized_new (1024);
707
708
0
  rest_description = NULL;
709
0
  if (context->main_group)
710
0
    {
711
712
0
      for (i = 0; i < context->main_group->n_entries; i++)
713
0
        {
714
0
          entry = &context->main_group->entries[i];
715
0
          if (entry->long_name[0] == 0)
716
0
            {
717
0
              rest_description = TRANSLATE (context->main_group, entry->arg_description);
718
0
              break;
719
0
            }
720
0
        }
721
0
    }
722
723
0
  g_string_append_printf (string, "%s\n  %s", _("Usage:"), g_get_prgname ());
724
0
  if (context->help_enabled ||
725
0
      (context->main_group && context->main_group->n_entries > 0) ||
726
0
      context->groups != NULL)
727
0
    g_string_append_printf (string, " %s", _("[OPTION…]"));
728
729
0
  if (rest_description)
730
0
    {
731
0
      g_string_append (string, " ");
732
0
      g_string_append (string, rest_description);
733
0
    }
734
735
0
  if (context->parameter_string)
736
0
    {
737
0
      g_string_append (string, " ");
738
0
      g_string_append (string, TRANSLATE (context, context->parameter_string));
739
0
    }
740
741
0
  g_string_append (string, "\n\n");
742
743
0
  if (context->summary)
744
0
    {
745
0
      g_string_append (string, TRANSLATE (context, context->summary));
746
0
      g_string_append (string, "\n\n");
747
0
    }
748
749
0
  memset (seen, 0, sizeof (gboolean) * 256);
750
0
  shadow_map = g_hash_table_new (g_str_hash, g_str_equal);
751
0
  aliases = g_hash_table_new_full (NULL, NULL, NULL, g_free);
752
753
0
  if (context->main_group)
754
0
    {
755
0
      for (i = 0; i < context->main_group->n_entries; i++)
756
0
        {
757
0
          entry = &context->main_group->entries[i];
758
0
          g_hash_table_insert (shadow_map,
759
0
                               (gpointer)entry->long_name,
760
0
                               entry);
761
762
0
          if (seen[(guchar)entry->short_name])
763
0
            entry->short_name = 0;
764
0
          else
765
0
            seen[(guchar)entry->short_name] = TRUE;
766
0
        }
767
0
    }
768
769
0
  list = context->groups;
770
0
  while (list != NULL)
771
0
    {
772
0
      GOptionGroup *g = list->data;
773
0
      for (i = 0; i < g->n_entries; i++)
774
0
        {
775
0
          entry = &g->entries[i];
776
0
          if (g_hash_table_lookup (shadow_map, entry->long_name) &&
777
0
              !(entry->flags & G_OPTION_FLAG_NOALIAS))
778
0
            {
779
0
              g_hash_table_insert (aliases, &entry->long_name,
780
0
                                   g_strdup_printf ("%s-%s", g->name, entry->long_name));
781
0
            }
782
0
          else
783
0
            g_hash_table_insert (shadow_map, (gpointer)entry->long_name, entry);
784
785
0
          if (seen[(guchar)entry->short_name] &&
786
0
              !(entry->flags & G_OPTION_FLAG_NOALIAS))
787
0
            entry->short_name = 0;
788
0
          else
789
0
            seen[(guchar)entry->short_name] = TRUE;
790
0
        }
791
0
      list = list->next;
792
0
    }
793
794
0
  g_hash_table_destroy (shadow_map);
795
796
0
  list = context->groups;
797
798
0
  if (context->help_enabled)
799
0
    {
800
0
      max_length = _g_utf8_strwidth ("-?, --help");
801
802
0
      if (list)
803
0
        {
804
0
          len = _g_utf8_strwidth ("--help-all");
805
0
          max_length = MAX (max_length, len);
806
0
        }
807
0
    }
808
809
0
  if (context->main_group)
810
0
    {
811
0
      len = calculate_max_length (context->main_group, aliases);
812
0
      max_length = MAX (max_length, len);
813
0
    }
814
815
0
  while (list != NULL)
816
0
    {
817
0
      GOptionGroup *g = list->data;
818
819
0
      if (!group || group == g)
820
0
        {
821
0
          if (context->help_enabled)
822
0
            {
823
              /* First, we check the --help-<groupname> options */
824
0
              len = _g_utf8_strwidth ("--help-") + _g_utf8_strwidth (g->name);
825
0
              max_length = MAX (max_length, len);
826
0
            }
827
828
          /* Then we go through the entries */
829
0
          if (group_has_visible_entries (context, g, main_help))
830
0
            {
831
0
              len = calculate_max_length (g, aliases);
832
0
              max_length = MAX (max_length, len);
833
0
            }
834
0
        }
835
836
0
      list = list->next;
837
0
    }
838
839
  /* Add a bit of padding */
840
0
  max_length += 4;
841
842
0
  g_assert (max_length <= G_MAXINT);
843
844
0
  if (!group && context->help_enabled)
845
0
    {
846
0
      list = context->groups;
847
848
0
      token = context_has_h_entry (context) ? '?' : 'h';
849
850
0
      g_string_append_printf (string, "%s\n  -%c, --%-*s %s\n",
851
0
                              _("Help Options:"), token, (int) max_length - 4, "help",
852
0
                              _("Show help options"));
853
854
      /* We only want --help-all when there are groups */
855
0
      if (list)
856
0
        g_string_append_printf (string, "  --%-*s %s\n",
857
0
                                (int) max_length, "help-all",
858
0
                                _("Show all help options"));
859
860
0
      while (list)
861
0
        {
862
0
          GOptionGroup *g = list->data;
863
864
0
          if (group_has_visible_entries (context, g, FALSE))
865
0
            g_string_append_printf (string, "  --help-%-*s %s\n",
866
0
                                    (int) max_length - 5, g->name,
867
0
                                    TRANSLATE (g, g->help_description));
868
869
0
          list = list->next;
870
0
        }
871
872
0
      g_string_append (string, "\n");
873
0
    }
874
875
0
  if (group)
876
0
    {
877
      /* Print a certain group */
878
879
0
      if (group_has_visible_entries (context, group, FALSE))
880
0
        {
881
0
          g_string_append (string, TRANSLATE (group, group->description));
882
0
          g_string_append (string, "\n");
883
0
          for (i = 0; i < group->n_entries; i++)
884
0
            print_entry (group, max_length, &group->entries[i], string, aliases);
885
0
          g_string_append (string, "\n");
886
0
        }
887
0
    }
888
0
  else if (!main_help)
889
0
    {
890
      /* Print all groups */
891
892
0
      list = context->groups;
893
894
0
      while (list)
895
0
        {
896
0
          GOptionGroup *g = list->data;
897
898
0
          if (group_has_visible_entries (context, g, FALSE))
899
0
            {
900
0
              g_string_append (string, g->description);
901
0
              g_string_append (string, "\n");
902
0
              for (i = 0; i < g->n_entries; i++)
903
0
                if (!(g->entries[i].flags & G_OPTION_FLAG_IN_MAIN))
904
0
                  print_entry (g, max_length, &g->entries[i], string, aliases);
905
906
0
              g_string_append (string, "\n");
907
0
            }
908
909
0
          list = list->next;
910
0
        }
911
0
    }
912
913
  /* Print application options if --help or --help-all has been specified */
914
0
  if ((main_help || !group) &&
915
0
      (group_has_visible_entries (context, context->main_group, TRUE) ||
916
0
       group_list_has_visible_entries (context, context->groups, TRUE)))
917
0
    {
918
0
      list = context->groups;
919
920
0
      if (context->help_enabled || list)
921
0
        g_string_append (string,  _("Application Options:"));
922
0
      else
923
0
        g_string_append (string, _("Options:"));
924
0
      g_string_append (string, "\n");
925
0
      if (context->main_group)
926
0
        for (i = 0; i < context->main_group->n_entries; i++)
927
0
          print_entry (context->main_group, max_length,
928
0
                       &context->main_group->entries[i], string, aliases);
929
930
0
      while (list != NULL)
931
0
        {
932
0
          GOptionGroup *g = list->data;
933
934
          /* Print main entries from other groups */
935
0
          for (i = 0; i < g->n_entries; i++)
936
0
            if (g->entries[i].flags & G_OPTION_FLAG_IN_MAIN)
937
0
              print_entry (g, max_length, &g->entries[i], string, aliases);
938
939
0
          list = list->next;
940
0
        }
941
942
0
      g_string_append (string, "\n");
943
0
    }
944
945
0
  if (context->description)
946
0
    {
947
0
      g_string_append (string, TRANSLATE (context, context->description));
948
0
      g_string_append (string, "\n");
949
0
    }
950
951
0
  g_hash_table_destroy (aliases);
952
953
0
  return g_string_free (string, FALSE);
954
0
}
955
956
G_NORETURN
957
static void
958
print_help (GOptionContext *context,
959
            gboolean        main_help,
960
            GOptionGroup   *group)
961
0
{
962
0
  gchar *help;
963
964
0
  help = g_option_context_get_help (context, main_help, group);
965
0
  g_print ("%s", help);
966
0
  g_free (help);
967
968
0
  exit (0);
969
0
}
970
971
static gboolean
972
parse_int (const gchar *arg_name,
973
           const gchar *arg,
974
           gint        *result,
975
           GError     **error)
976
0
{
977
0
  gchar *end;
978
0
  glong tmp;
979
980
0
  errno = 0;
981
0
  tmp = strtol (arg, &end, 0);
982
983
0
  if (*arg == '\0' || *end != '\0')
984
0
    {
985
0
      g_set_error (error,
986
0
                   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
987
0
                   _("Cannot parse integer value “%s” for %s"),
988
0
                   arg, arg_name);
989
0
      return FALSE;
990
0
    }
991
992
0
  *result = (int) tmp;
993
0
  if (*result != tmp || errno == ERANGE)
994
0
    {
995
0
      g_set_error (error,
996
0
                   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
997
0
                   _("Integer value “%s” for %s out of range"),
998
0
                   arg, arg_name);
999
0
      return FALSE;
1000
0
    }
1001
1002
0
  return TRUE;
1003
0
}
1004
1005
1006
static gboolean
1007
parse_double (const gchar *arg_name,
1008
           const gchar *arg,
1009
           gdouble        *result,
1010
           GError     **error)
1011
0
{
1012
0
  gchar *end;
1013
0
  gdouble tmp;
1014
1015
0
  errno = 0;
1016
0
  tmp = g_strtod (arg, &end);
1017
1018
0
  if (*arg == '\0' || *end != '\0')
1019
0
    {
1020
0
      g_set_error (error,
1021
0
                   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1022
0
                   _("Cannot parse double value “%s” for %s"),
1023
0
                   arg, arg_name);
1024
0
      return FALSE;
1025
0
    }
1026
0
  if (errno == ERANGE)
1027
0
    {
1028
0
      g_set_error (error,
1029
0
                   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1030
0
                   _("Double value “%s” for %s out of range"),
1031
0
                   arg, arg_name);
1032
0
      return FALSE;
1033
0
    }
1034
1035
0
  *result = tmp;
1036
1037
0
  return TRUE;
1038
0
}
1039
1040
1041
static gboolean
1042
parse_int64 (const gchar *arg_name,
1043
             const gchar *arg,
1044
             gint64      *result,
1045
             GError     **error)
1046
0
{
1047
0
  gchar *end;
1048
0
  gint64 tmp;
1049
1050
0
  errno = 0;
1051
0
  tmp = g_ascii_strtoll (arg, &end, 0);
1052
1053
0
  if (*arg == '\0' || *end != '\0')
1054
0
    {
1055
0
      g_set_error (error,
1056
0
                   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1057
0
                   _("Cannot parse integer value “%s” for %s"),
1058
0
                   arg, arg_name);
1059
0
      return FALSE;
1060
0
    }
1061
0
  if (errno == ERANGE)
1062
0
    {
1063
0
      g_set_error (error,
1064
0
                   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1065
0
                   _("Integer value “%s” for %s out of range"),
1066
0
                   arg, arg_name);
1067
0
      return FALSE;
1068
0
    }
1069
1070
0
  *result = tmp;
1071
1072
0
  return TRUE;
1073
0
}
1074
1075
1076
static Change *
1077
get_change (GOptionContext *context,
1078
            GOptionArg      arg_type,
1079
            gpointer        arg_data)
1080
0
{
1081
0
  GList *list;
1082
0
  Change *change = NULL;
1083
1084
0
  for (list = context->changes; list != NULL; list = list->next)
1085
0
    {
1086
0
      change = list->data;
1087
1088
0
      if (change->arg_data == arg_data)
1089
0
        goto found;
1090
0
    }
1091
1092
0
  change = g_new0 (Change, 1);
1093
0
  change->arg_type = arg_type;
1094
0
  change->arg_data = arg_data;
1095
1096
0
  context->changes = g_list_prepend (context->changes, change);
1097
1098
0
 found:
1099
1100
0
  return change;
1101
0
}
1102
1103
static void
1104
add_pending_null (GOptionContext *context,
1105
                  gchar         **ptr,
1106
                  gchar          *value)
1107
0
{
1108
0
  PendingNull *n;
1109
1110
0
  n = g_new0 (PendingNull, 1);
1111
0
  n->ptr = ptr;
1112
0
  n->value = value;
1113
1114
0
  context->pending_nulls = g_list_prepend (context->pending_nulls, n);
1115
0
}
1116
1117
static gboolean
1118
parse_arg (GOptionContext *context,
1119
           GOptionGroup   *group,
1120
           GOptionEntry   *entry,
1121
           const gchar    *value,
1122
           const gchar    *option_name,
1123
           GError        **error)
1124
1125
0
{
1126
0
  Change *change;
1127
1128
0
  g_assert (value || OPTIONAL_ARG (entry) || NO_ARG (entry));
1129
1130
0
  switch (entry->arg)
1131
0
    {
1132
0
    case G_OPTION_ARG_NONE:
1133
0
      {
1134
0
        (void) get_change (context, G_OPTION_ARG_NONE,
1135
0
                           entry->arg_data);
1136
1137
0
        *(gboolean *)entry->arg_data = !(entry->flags & G_OPTION_FLAG_REVERSE);
1138
0
        break;
1139
0
      }
1140
0
    case G_OPTION_ARG_STRING:
1141
0
      {
1142
0
        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
0
        data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1151
0
#endif
1152
1153
0
        if (!data)
1154
0
          return FALSE;
1155
1156
0
        change = get_change (context, G_OPTION_ARG_STRING,
1157
0
                             entry->arg_data);
1158
1159
0
        if (!change->allocated.str)
1160
0
          change->prev.str = *(gchar **)entry->arg_data;
1161
0
        else
1162
0
          g_free (change->allocated.str);
1163
1164
0
        change->allocated.str = data;
1165
1166
0
        *(gchar **)entry->arg_data = data;
1167
0
        break;
1168
0
      }
1169
0
    case G_OPTION_ARG_STRING_ARRAY:
1170
0
      {
1171
0
        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
0
        data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1180
0
#endif
1181
1182
0
        if (!data)
1183
0
          return FALSE;
1184
1185
0
        change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
1186
0
                             entry->arg_data);
1187
1188
0
        if (change->allocated.array.len == 0)
1189
0
          {
1190
0
            change->prev.array = *(gchar ***)entry->arg_data;
1191
0
            change->allocated.array.data = g_new (gchar *, 2);
1192
0
          }
1193
0
        else
1194
0
          change->allocated.array.data =
1195
0
            g_renew (gchar *, change->allocated.array.data,
1196
0
                     change->allocated.array.len + 2);
1197
1198
0
        change->allocated.array.data[change->allocated.array.len] = data;
1199
0
        change->allocated.array.data[change->allocated.array.len + 1] = NULL;
1200
1201
0
        change->allocated.array.len ++;
1202
1203
0
        *(gchar ***)entry->arg_data = change->allocated.array.data;
1204
1205
0
        break;
1206
0
      }
1207
1208
0
    case G_OPTION_ARG_FILENAME:
1209
0
      {
1210
0
        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
0
        data = g_strdup (value);
1222
0
#endif
1223
0
        change = get_change (context, G_OPTION_ARG_FILENAME,
1224
0
                             entry->arg_data);
1225
1226
0
        if (!change->allocated.str)
1227
0
          change->prev.str = *(gchar **)entry->arg_data;
1228
0
        else
1229
0
          g_free (change->allocated.str);
1230
1231
0
        change->allocated.str = data;
1232
1233
0
        *(gchar **)entry->arg_data = data;
1234
0
        break;
1235
0
      }
1236
1237
0
    case G_OPTION_ARG_FILENAME_ARRAY:
1238
0
      {
1239
0
        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
0
        data = g_strdup (value);
1251
0
#endif
1252
0
        change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
1253
0
                             entry->arg_data);
1254
1255
0
        if (change->allocated.array.len == 0)
1256
0
          {
1257
0
            change->prev.array = *(gchar ***)entry->arg_data;
1258
0
            change->allocated.array.data = g_new (gchar *, 2);
1259
0
          }
1260
0
        else
1261
0
          change->allocated.array.data =
1262
0
            g_renew (gchar *, change->allocated.array.data,
1263
0
                     change->allocated.array.len + 2);
1264
1265
0
        change->allocated.array.data[change->allocated.array.len] = data;
1266
0
        change->allocated.array.data[change->allocated.array.len + 1] = NULL;
1267
1268
0
        change->allocated.array.len ++;
1269
1270
0
        *(gchar ***)entry->arg_data = change->allocated.array.data;
1271
1272
0
        break;
1273
0
      }
1274
1275
0
    case G_OPTION_ARG_INT:
1276
0
      {
1277
0
        gint data;
1278
1279
0
        if (!parse_int (option_name, value,
1280
0
                        &data,
1281
0
                        error))
1282
0
          return FALSE;
1283
1284
0
        change = get_change (context, G_OPTION_ARG_INT,
1285
0
                             entry->arg_data);
1286
0
        change->prev.integer = *(gint *)entry->arg_data;
1287
0
        *(gint *)entry->arg_data = data;
1288
0
        break;
1289
0
      }
1290
0
    case G_OPTION_ARG_CALLBACK:
1291
0
      {
1292
0
        gchar *data;
1293
0
        gboolean retval;
1294
1295
0
        if (!value && entry->flags & G_OPTION_FLAG_OPTIONAL_ARG)
1296
0
          data = NULL;
1297
0
        else if (entry->flags & G_OPTION_FLAG_NO_ARG)
1298
0
          data = NULL;
1299
0
        else if (entry->flags & G_OPTION_FLAG_FILENAME)
1300
0
          {
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
0
#endif
1309
0
          }
1310
0
        else
1311
0
          data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1312
1313
0
        if (!(entry->flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG)) &&
1314
0
            !data)
1315
0
          return FALSE;
1316
1317
0
        retval = (* (GOptionArgFunc) entry->arg_data) (option_name, data, group->user_data, error);
1318
1319
0
        if (!retval && error != NULL && *error == NULL)
1320
0
          g_set_error (error,
1321
0
                       G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
1322
0
                       _("Error parsing option %s"), option_name);
1323
1324
0
        g_free (data);
1325
1326
0
        return retval;
1327
1328
0
        break;
1329
0
      }
1330
0
    case G_OPTION_ARG_DOUBLE:
1331
0
      {
1332
0
        gdouble data;
1333
1334
0
        if (!parse_double (option_name, value,
1335
0
                        &data,
1336
0
                        error))
1337
0
          {
1338
0
            return FALSE;
1339
0
          }
1340
1341
0
        change = get_change (context, G_OPTION_ARG_DOUBLE,
1342
0
                             entry->arg_data);
1343
0
        change->prev.dbl = *(gdouble *)entry->arg_data;
1344
0
        *(gdouble *)entry->arg_data = data;
1345
0
        break;
1346
0
      }
1347
0
    case G_OPTION_ARG_INT64:
1348
0
      {
1349
0
        gint64 data;
1350
1351
0
        if (!parse_int64 (option_name, value,
1352
0
                         &data,
1353
0
                         error))
1354
0
          {
1355
0
            return FALSE;
1356
0
          }
1357
1358
0
        change = get_change (context, G_OPTION_ARG_INT64,
1359
0
                             entry->arg_data);
1360
0
        change->prev.int64 = *(gint64 *)entry->arg_data;
1361
0
        *(gint64 *)entry->arg_data = data;
1362
0
        break;
1363
0
      }
1364
0
    default:
1365
0
      g_assert_not_reached ();
1366
0
    }
1367
1368
0
  return TRUE;
1369
0
}
1370
1371
static gboolean
1372
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
0
{
1382
0
  gsize j;
1383
1384
0
  for (j = 0; j < group->n_entries; j++)
1385
0
    {
1386
0
      if (arg == group->entries[j].short_name)
1387
0
        {
1388
0
          gchar *option_name;
1389
0
          gchar *value = NULL;
1390
1391
0
          option_name = g_strdup_printf ("-%c", group->entries[j].short_name);
1392
1393
0
          if (NO_ARG (&group->entries[j]))
1394
0
            value = NULL;
1395
0
          else
1396
0
            {
1397
0
              if (*new_idx > idx)
1398
0
                {
1399
0
                  g_set_error (error,
1400
0
                               G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
1401
0
                               _("Error parsing option %s"), option_name);
1402
0
                  g_free (option_name);
1403
0
                  return FALSE;
1404
0
                }
1405
1406
0
              if (idx < *argc - 1)
1407
0
                {
1408
0
                  if (OPTIONAL_ARG (&group->entries[j]) && ((*argv)[idx + 1][0] == '-'))
1409
0
                    value = NULL;
1410
0
                  else
1411
0
                    {
1412
0
                      value = (*argv)[idx + 1];
1413
0
                      add_pending_null (context, &((*argv)[idx + 1]), NULL);
1414
0
                      *new_idx = idx + 1;
1415
0
                    }
1416
0
                }
1417
0
              else if (idx >= *argc - 1 && OPTIONAL_ARG (&group->entries[j]))
1418
0
                value = NULL;
1419
0
              else
1420
0
                {
1421
0
                  g_set_error (error,
1422
0
                               G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1423
0
                               _("Missing argument for %s"), option_name);
1424
0
                  g_free (option_name);
1425
0
                  return FALSE;
1426
0
                }
1427
0
            }
1428
1429
0
          if (!parse_arg (context, group, &group->entries[j],
1430
0
                          value, option_name, error))
1431
0
            {
1432
0
              g_free (option_name);
1433
0
              return FALSE;
1434
0
            }
1435
1436
0
          g_free (option_name);
1437
0
          *parsed = TRUE;
1438
0
        }
1439
0
    }
1440
1441
0
  return TRUE;
1442
0
}
1443
1444
static gboolean
1445
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
0
{
1455
0
  gsize j;
1456
1457
0
  for (j = 0; j < group->n_entries; j++)
1458
0
    {
1459
0
      if (*idx >= *argc)
1460
0
        return TRUE;
1461
1462
0
      if (aliased && (group->entries[j].flags & G_OPTION_FLAG_NOALIAS))
1463
0
        continue;
1464
1465
0
      if (NO_ARG (&group->entries[j]) &&
1466
0
          strcmp (arg, group->entries[j].long_name) == 0)
1467
0
        {
1468
0
          gchar *option_name;
1469
0
          gboolean retval;
1470
1471
0
          option_name = g_strconcat ("--", group->entries[j].long_name, NULL);
1472
0
          retval = parse_arg (context, group, &group->entries[j],
1473
0
                              NULL, option_name, error);
1474
0
          g_free (option_name);
1475
1476
0
          add_pending_null (context, &((*argv)[*idx]), NULL);
1477
0
          *parsed = TRUE;
1478
1479
0
          return retval;
1480
0
        }
1481
0
      else
1482
0
        {
1483
0
          size_t len = strlen (group->entries[j].long_name);
1484
1485
0
          if (strncmp (arg, group->entries[j].long_name, len) == 0 &&
1486
0
              (arg[len] == '=' || arg[len] == 0))
1487
0
            {
1488
0
              gchar *value = NULL;
1489
0
              gchar *option_name;
1490
1491
0
              add_pending_null (context, &((*argv)[*idx]), NULL);
1492
0
              option_name = g_strconcat ("--", group->entries[j].long_name, NULL);
1493
1494
0
              if (arg[len] == '=')
1495
0
                value = arg + len + 1;
1496
0
              else if (*idx < *argc - 1)
1497
0
                {
1498
0
                  if (!OPTIONAL_ARG (&group->entries[j]))
1499
0
                    {
1500
0
                      value = (*argv)[*idx + 1];
1501
0
                      add_pending_null (context, &((*argv)[*idx + 1]), NULL);
1502
0
                      (*idx)++;
1503
0
                    }
1504
0
                  else
1505
0
                    {
1506
0
                      if ((*argv)[*idx + 1][0] == '-')
1507
0
                        {
1508
0
                          gboolean retval;
1509
0
                          retval = parse_arg (context, group, &group->entries[j],
1510
0
                                              NULL, option_name, error);
1511
0
                          *parsed = TRUE;
1512
0
                          g_free (option_name);
1513
0
                          return retval;
1514
0
                        }
1515
0
                      else
1516
0
                        {
1517
0
                          value = (*argv)[*idx + 1];
1518
0
                          add_pending_null (context, &((*argv)[*idx + 1]), NULL);
1519
0
                          (*idx)++;
1520
0
                        }
1521
0
                    }
1522
0
                }
1523
0
              else if (*idx >= *argc - 1 && OPTIONAL_ARG (&group->entries[j]))
1524
0
                {
1525
0
                    gboolean retval;
1526
0
                    retval = parse_arg (context, group, &group->entries[j],
1527
0
                                        NULL, option_name, error);
1528
0
                    *parsed = TRUE;
1529
0
                    g_free (option_name);
1530
0
                    return retval;
1531
0
                }
1532
0
              else
1533
0
                {
1534
0
                  g_set_error (error,
1535
0
                               G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1536
0
                               _("Missing argument for %s"), option_name);
1537
0
                  g_free (option_name);
1538
0
                  return FALSE;
1539
0
                }
1540
1541
0
              if (!parse_arg (context, group, &group->entries[j],
1542
0
                              value, option_name, error))
1543
0
                {
1544
0
                  g_free (option_name);
1545
0
                  return FALSE;
1546
0
                }
1547
1548
0
              g_free (option_name);
1549
0
              *parsed = TRUE;
1550
0
            }
1551
0
        }
1552
0
    }
1553
1554
0
  return TRUE;
1555
0
}
1556
1557
static gboolean
1558
parse_remaining_arg (GOptionContext *context,
1559
                     GOptionGroup   *group,
1560
                     gint           *idx,
1561
                     gint           *argc,
1562
                     gchar        ***argv,
1563
                     GError        **error,
1564
                     gboolean       *parsed)
1565
0
{
1566
0
  gsize j;
1567
1568
0
  for (j = 0; j < group->n_entries; j++)
1569
0
    {
1570
0
      if (*idx >= *argc)
1571
0
        return TRUE;
1572
1573
0
      if (group->entries[j].long_name[0])
1574
0
        continue;
1575
1576
0
      g_return_val_if_fail (group->entries[j].arg == G_OPTION_ARG_CALLBACK ||
1577
0
                            group->entries[j].arg == G_OPTION_ARG_STRING_ARRAY ||
1578
0
                            group->entries[j].arg == G_OPTION_ARG_FILENAME_ARRAY, FALSE);
1579
1580
0
      add_pending_null (context, &((*argv)[*idx]), NULL);
1581
1582
0
      if (!parse_arg (context, group, &group->entries[j], (*argv)[*idx], "", error))
1583
0
        return FALSE;
1584
1585
0
      *parsed = TRUE;
1586
0
      return TRUE;
1587
0
    }
1588
1589
0
  return TRUE;
1590
0
}
1591
1592
static void
1593
free_changes_list (GOptionContext *context,
1594
                   gboolean        revert)
1595
0
{
1596
0
  GList *list;
1597
1598
0
  for (list = context->changes; list != NULL; list = list->next)
1599
0
    {
1600
0
      Change *change = list->data;
1601
1602
0
      if (revert)
1603
0
        {
1604
0
          switch (change->arg_type)
1605
0
            {
1606
0
            case G_OPTION_ARG_NONE:
1607
0
              *(gboolean *)change->arg_data = change->prev.boolean;
1608
0
              break;
1609
0
            case G_OPTION_ARG_INT:
1610
0
              *(gint *)change->arg_data = change->prev.integer;
1611
0
              break;
1612
0
            case G_OPTION_ARG_STRING:
1613
0
            case G_OPTION_ARG_FILENAME:
1614
0
              g_free (change->allocated.str);
1615
0
              *(gchar **)change->arg_data = change->prev.str;
1616
0
              break;
1617
0
            case G_OPTION_ARG_STRING_ARRAY:
1618
0
            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
0
              g_assert_not_reached ();
1630
0
            }
1631
0
        }
1632
1633
0
      g_free (change);
1634
0
    }
1635
1636
0
  g_list_free (context->changes);
1637
0
  context->changes = NULL;
1638
0
}
1639
1640
static void
1641
free_pending_nulls (GOptionContext *context,
1642
                    gboolean        perform_nulls)
1643
0
{
1644
0
  GList *list;
1645
1646
0
  for (list = context->pending_nulls; list != NULL; list = list->next)
1647
0
    {
1648
0
      PendingNull *n = list->data;
1649
1650
0
      if (perform_nulls)
1651
0
        {
1652
0
          if (n->value)
1653
0
            {
1654
              /* Copy back the short options */
1655
0
              *(n->ptr)[0] = '-';
1656
0
              strcpy (*n->ptr + 1, n->value);
1657
0
            }
1658
0
          else
1659
0
            {
1660
0
              if (context->strv_mode)
1661
0
                g_free (*n->ptr);
1662
1663
0
              *n->ptr = NULL;
1664
0
            }
1665
0
        }
1666
1667
0
      g_free (n->value);
1668
0
      g_free (n);
1669
0
    }
1670
1671
0
  g_list_free (context->pending_nulls);
1672
0
  context->pending_nulls = NULL;
1673
0
}
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
platform_get_argv0 (void)
1682
0
{
1683
0
#ifdef HAVE_PROC_SELF_CMDLINE
1684
0
  char *cmdline;
1685
0
  char *base_arg0;
1686
0
  gsize len;
1687
1688
0
  if (!g_file_get_contents ("/proc/self/cmdline",
1689
0
          &cmdline,
1690
0
          &len,
1691
0
          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
0
  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
0
  base_arg0 = g_path_get_basename (cmdline);
1704
0
  g_free (cmdline);
1705
0
  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
0
  return NULL;
1779
0
}
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
g_option_context_parse (GOptionContext   *context,
1817
                        gint             *argc,
1818
                        gchar          ***argv,
1819
                        GError          **error)
1820
0
{
1821
0
  gint i, k;
1822
0
  GList *list;
1823
1824
0
  g_return_val_if_fail (context != NULL, FALSE);
1825
1826
  /* Set program name */
1827
0
  if (!g_get_prgname())
1828
0
    {
1829
0
      gchar *prgname;
1830
1831
0
      if (argc && argv && *argc)
1832
0
  prgname = g_path_get_basename ((*argv)[0]);
1833
0
      else
1834
0
  prgname = platform_get_argv0 ();
1835
1836
0
      g_set_prgname_once (prgname ? prgname : "<unknown>");
1837
1838
0
      g_free (prgname);
1839
0
    }
1840
1841
  /* Call pre-parse hooks */
1842
0
  list = context->groups;
1843
0
  while (list)
1844
0
    {
1845
0
      GOptionGroup *group = list->data;
1846
1847
0
      if (group->pre_parse_func)
1848
0
        {
1849
0
          if (!(* group->pre_parse_func) (context, group,
1850
0
                                          group->user_data, error))
1851
0
            goto fail;
1852
0
        }
1853
1854
0
      list = list->next;
1855
0
    }
1856
1857
0
  if (context->main_group && context->main_group->pre_parse_func)
1858
0
    {
1859
0
      if (!(* context->main_group->pre_parse_func) (context, context->main_group,
1860
0
                                                    context->main_group->user_data, error))
1861
0
        goto fail;
1862
0
    }
1863
1864
0
  if (argc && argv)
1865
0
    {
1866
0
      gboolean stop_parsing = FALSE;
1867
0
      gboolean has_unknown = FALSE;
1868
0
      gint separator_pos = 0;
1869
1870
0
      for (i = 1; i < *argc; i++)
1871
0
        {
1872
0
          gchar *arg, *dash;
1873
0
          gboolean parsed = FALSE;
1874
1875
0
          if ((*argv)[i][0] == '-' && (*argv)[i][1] != '\0' && !stop_parsing)
1876
0
            {
1877
0
              if ((*argv)[i][1] == '-')
1878
0
                {
1879
                  /* -- option */
1880
1881
0
                  arg = (*argv)[i] + 2;
1882
1883
                  /* '--' terminates list of arguments */
1884
0
                  if (*arg == 0)
1885
0
                    {
1886
0
                      separator_pos = i;
1887
0
                      stop_parsing = TRUE;
1888
0
                      continue;
1889
0
                    }
1890
1891
                  /* Handle help options */
1892
0
                  if (context->help_enabled)
1893
0
                    {
1894
0
                      if (strcmp (arg, "help") == 0)
1895
0
                        print_help (context, TRUE, NULL);
1896
0
                      else if (strcmp (arg, "help-all") == 0)
1897
0
                        print_help (context, FALSE, NULL);
1898
0
                      else if (strncmp (arg, "help-", 5) == 0)
1899
0
                        {
1900
0
                          list = context->groups;
1901
1902
0
                          while (list)
1903
0
                            {
1904
0
                              GOptionGroup *group = list->data;
1905
1906
0
                              if (strcmp (arg + 5, group->name) == 0)
1907
0
                                print_help (context, FALSE, group);
1908
1909
0
                              list = list->next;
1910
0
                            }
1911
0
                        }
1912
0
                    }
1913
1914
0
                  if (context->main_group &&
1915
0
                      !parse_long_option (context, context->main_group, &i, arg,
1916
0
                                          FALSE, argc, argv, error, &parsed))
1917
0
                    goto fail;
1918
1919
0
                  if (parsed)
1920
0
                    continue;
1921
1922
                  /* Try the groups */
1923
0
                  list = context->groups;
1924
0
                  while (list)
1925
0
                    {
1926
0
                      GOptionGroup *group = list->data;
1927
1928
0
                      if (!parse_long_option (context, group, &i, arg,
1929
0
                                              FALSE, argc, argv, error, &parsed))
1930
0
                        goto fail;
1931
1932
0
                      if (parsed)
1933
0
                        break;
1934
1935
0
                      list = list->next;
1936
0
                    }
1937
1938
0
                  if (parsed)
1939
0
                    continue;
1940
1941
                  /* Now look for --<group>-<option> */
1942
0
                  dash = strchr (arg, '-');
1943
0
                  if (dash && arg < dash)
1944
0
                    {
1945
                      /* Try the groups */
1946
0
                      list = context->groups;
1947
0
                      while (list)
1948
0
                        {
1949
0
                          GOptionGroup *group = list->data;
1950
1951
0
                          if (strncmp (group->name, arg, dash - arg) == 0)
1952
0
                            {
1953
0
                              if (!parse_long_option (context, group, &i, dash + 1,
1954
0
                                                      TRUE, argc, argv, error, &parsed))
1955
0
                                goto fail;
1956
1957
0
                              if (parsed)
1958
0
                                break;
1959
0
                            }
1960
1961
0
                          list = list->next;
1962
0
                        }
1963
0
                    }
1964
1965
0
                  if (context->ignore_unknown)
1966
0
                    continue;
1967
0
                }
1968
0
              else
1969
0
                { /* short option */
1970
0
                  gint new_i = i;
1971
0
                  size_t arg_length;
1972
0
                  gboolean *nulled_out = NULL;
1973
0
                  gboolean has_h_entry = context_has_h_entry (context);
1974
0
                  arg = (*argv)[i] + 1;
1975
0
                  arg_length = strlen (arg);
1976
0
                  nulled_out = g_newa0 (gboolean, arg_length);
1977
0
                  for (size_t j = 0; j < arg_length; j++)
1978
0
                    {
1979
0
                      if (context->help_enabled && (arg[j] == '?' ||
1980
0
                        (arg[j] == 'h' && !has_h_entry)))
1981
0
                        print_help (context, TRUE, NULL);
1982
0
                      parsed = FALSE;
1983
0
                      if (context->main_group &&
1984
0
                          !parse_short_option (context, context->main_group,
1985
0
                                               i, &new_i, arg[j],
1986
0
                                               argc, argv, error, &parsed))
1987
0
                        goto fail;
1988
0
                      if (!parsed)
1989
0
                        {
1990
                          /* Try the groups */
1991
0
                          list = context->groups;
1992
0
                          while (list)
1993
0
                            {
1994
0
                              GOptionGroup *group = list->data;
1995
0
                              if (!parse_short_option (context, group, i, &new_i, arg[j],
1996
0
                                                       argc, argv, error, &parsed))
1997
0
                                goto fail;
1998
0
                              if (parsed)
1999
0
                                break;
2000
0
                              list = list->next;
2001
0
                            }
2002
0
                        }
2003
2004
0
                      if (context->ignore_unknown && parsed)
2005
0
                        nulled_out[j] = TRUE;
2006
0
                      else if (context->ignore_unknown)
2007
0
                        continue;
2008
0
                      else if (!parsed)
2009
0
                        break;
2010
                      /* !context->ignore_unknown && parsed */
2011
0
                    }
2012
0
                  if (context->ignore_unknown)
2013
0
                    {
2014
0
                      gchar *new_arg = NULL;
2015
0
                      gint arg_index = 0;
2016
0
                      for (size_t j = 0; j < arg_length; j++)
2017
0
                        {
2018
0
                          if (!nulled_out[j])
2019
0
                            {
2020
0
                              if (!new_arg)
2021
0
                                new_arg = g_malloc (arg_length + 1);
2022
0
                              new_arg[arg_index++] = arg[j];
2023
0
                            }
2024
0
                        }
2025
0
                      if (new_arg)
2026
0
                        new_arg[arg_index] = '\0';
2027
0
                      add_pending_null (context, &((*argv)[i]), new_arg);
2028
0
                      i = new_i;
2029
0
                    }
2030
0
                  else if (parsed)
2031
0
                    {
2032
0
                      add_pending_null (context, &((*argv)[i]), NULL);
2033
0
                      i = new_i;
2034
0
                    }
2035
0
                }
2036
2037
0
              if (!parsed)
2038
0
                has_unknown = TRUE;
2039
2040
0
              if (!parsed && !context->ignore_unknown)
2041
0
                {
2042
0
                  g_set_error (error,
2043
0
                               G_OPTION_ERROR, G_OPTION_ERROR_UNKNOWN_OPTION,
2044
0
                                   _("Unknown option %s"), (*argv)[i]);
2045
0
                  goto fail;
2046
0
                }
2047
0
            }
2048
0
          else
2049
0
            {
2050
0
              if (context->strict_posix)
2051
0
                stop_parsing = TRUE;
2052
2053
              /* Collect remaining args */
2054
0
              if (context->main_group &&
2055
0
                  !parse_remaining_arg (context, context->main_group, &i,
2056
0
                                        argc, argv, error, &parsed))
2057
0
                goto fail;
2058
2059
0
              if (!parsed && (has_unknown || (*argv)[i][0] == '-'))
2060
0
                separator_pos = 0;
2061
0
            }
2062
0
        }
2063
2064
0
      if (separator_pos > 0)
2065
0
        add_pending_null (context, &((*argv)[separator_pos]), NULL);
2066
2067
0
    }
2068
2069
  /* Call post-parse hooks */
2070
0
  list = context->groups;
2071
0
  while (list)
2072
0
    {
2073
0
      GOptionGroup *group = list->data;
2074
2075
0
      if (group->post_parse_func)
2076
0
        {
2077
0
          if (!(* group->post_parse_func) (context, group,
2078
0
                                           group->user_data, error))
2079
0
            goto fail;
2080
0
        }
2081
2082
0
      list = list->next;
2083
0
    }
2084
2085
0
  if (context->main_group && context->main_group->post_parse_func)
2086
0
    {
2087
0
      if (!(* context->main_group->post_parse_func) (context, context->main_group,
2088
0
                                                     context->main_group->user_data, error))
2089
0
        goto fail;
2090
0
    }
2091
2092
0
  if (argc && argv)
2093
0
    {
2094
0
      free_pending_nulls (context, TRUE);
2095
2096
0
      for (i = 1; i < *argc; i++)
2097
0
        {
2098
0
          for (k = i; k < *argc; k++)
2099
0
            if ((*argv)[k] != NULL)
2100
0
              break;
2101
2102
0
          if (k > i)
2103
0
            {
2104
0
              k -= i;
2105
0
              for (int j = i + k; j < *argc; j++)
2106
0
                {
2107
0
                  (*argv)[j-k] = (*argv)[j];
2108
0
                  (*argv)[j] = NULL;
2109
0
                }
2110
0
              *argc -= k;
2111
0
            }
2112
0
        }
2113
0
    }
2114
2115
0
  return TRUE;
2116
2117
0
 fail:
2118
2119
  /* Call error hooks */
2120
0
  list = context->groups;
2121
0
  while (list)
2122
0
    {
2123
0
      GOptionGroup *group = list->data;
2124
2125
0
      if (group->error_func)
2126
0
        (* group->error_func) (context, group,
2127
0
                               group->user_data, error);
2128
2129
0
      list = list->next;
2130
0
    }
2131
2132
0
  if (context->main_group && context->main_group->error_func)
2133
0
    (* context->main_group->error_func) (context, context->main_group,
2134
0
                                         context->main_group->user_data, error);
2135
2136
0
  free_changes_list (context, TRUE);
2137
0
  free_pending_nulls (context, FALSE);
2138
2139
0
  return FALSE;
2140
0
}
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
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
0
{
2176
0
  GOptionGroup *group;
2177
2178
0
  group = g_new0 (GOptionGroup, 1);
2179
0
  group->ref_count = 1;
2180
0
  group->name = g_strdup (name);
2181
0
  group->description = g_strdup (description);
2182
0
  group->help_description = g_strdup (help_description);
2183
0
  group->user_data = user_data;
2184
0
  group->destroy_notify = destroy;
2185
2186
0
  return group;
2187
0
}
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
g_option_group_free (GOptionGroup *group)
2203
0
{
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
g_option_group_ref (GOptionGroup *group)
2219
0
{
2220
0
  g_return_val_if_fail (group != NULL, NULL);
2221
2222
0
  group->ref_count++;
2223
2224
0
  return group;
2225
0
}
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
g_option_group_unref (GOptionGroup *group)
2239
0
{
2240
0
  g_return_if_fail (group != NULL);
2241
2242
0
  if (--group->ref_count == 0)
2243
0
    {
2244
0
      g_free (group->name);
2245
0
      g_free (group->description);
2246
0
      g_free (group->help_description);
2247
2248
0
      g_free (group->entries);
2249
2250
0
      if (group->destroy_notify)
2251
0
        (* group->destroy_notify) (group->user_data);
2252
2253
0
      if (group->translate_notify)
2254
0
        (* group->translate_notify) (group->translate_data);
2255
2256
0
      g_free (group);
2257
0
    }
2258
0
}
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
g_option_group_add_entries (GOptionGroup       *group,
2271
                            const GOptionEntry *entries)
2272
0
{
2273
0
  gsize i, n_entries;
2274
2275
0
  g_return_if_fail (group != NULL);
2276
0
  g_return_if_fail (entries != NULL);
2277
2278
0
  for (n_entries = 0; entries[n_entries].long_name != NULL; n_entries++) ;
2279
2280
0
  g_return_if_fail (n_entries <= G_MAXSIZE - group->n_entries);
2281
2282
0
  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
0
  if (n_entries != 0)
2287
0
    memcpy (group->entries + group->n_entries, entries, sizeof (GOptionEntry) * n_entries);
2288
2289
0
  for (i = group->n_entries; i < group->n_entries + n_entries; i++)
2290
0
    {
2291
0
      gchar c = group->entries[i].short_name;
2292
2293
0
      if (c == '-' || (c != 0 && !g_ascii_isprint (c)))
2294
0
        {
2295
0
          g_warning (G_STRLOC ": ignoring invalid short option '%c' (%d) in entry %s:%s",
2296
0
              c, c, group->name, group->entries[i].long_name);
2297
0
          group->entries[i].short_name = '\0';
2298
0
        }
2299
2300
0
      if (group->entries[i].arg != G_OPTION_ARG_NONE &&
2301
0
          (group->entries[i].flags & G_OPTION_FLAG_REVERSE) != 0)
2302
0
        {
2303
0
          g_warning (G_STRLOC ": ignoring reverse flag on option of arg-type %d in entry %s:%s",
2304
0
              group->entries[i].arg, group->name, group->entries[i].long_name);
2305
2306
0
          group->entries[i].flags &= ~G_OPTION_FLAG_REVERSE;
2307
0
        }
2308
2309
0
      if (group->entries[i].arg != G_OPTION_ARG_CALLBACK &&
2310
0
          (group->entries[i].flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG|G_OPTION_FLAG_FILENAME)) != 0)
2311
0
        {
2312
0
          g_warning (G_STRLOC ": ignoring no-arg, optional-arg or filename flags (%d) on option of arg-type %d in entry %s:%s",
2313
0
              group->entries[i].flags, group->entries[i].arg, group->name, group->entries[i].long_name);
2314
2315
0
          group->entries[i].flags &= ~(G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG|G_OPTION_FLAG_FILENAME);
2316
0
        }
2317
0
    }
2318
2319
0
  group->n_entries += n_entries;
2320
0
}
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
g_option_group_set_parse_hooks (GOptionGroup     *group,
2340
                                GOptionParseFunc  pre_parse_func,
2341
                                GOptionParseFunc  post_parse_func)
2342
0
{
2343
0
  g_return_if_fail (group != NULL);
2344
2345
0
  group->pre_parse_func = pre_parse_func;
2346
0
  group->post_parse_func = post_parse_func;
2347
0
}
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
g_option_group_set_error_hook (GOptionGroup     *group,
2364
                               GOptionErrorFunc  error_func)
2365
0
{
2366
0
  g_return_if_fail (group != NULL);
2367
2368
0
  group->error_func = error_func;
2369
0
}
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
g_option_group_set_translate_func (GOptionGroup   *group,
2390
                                   GTranslateFunc  func,
2391
                                   gpointer        data,
2392
                                   GDestroyNotify  destroy_notify)
2393
0
{
2394
0
  g_return_if_fail (group != NULL);
2395
2396
0
  if (group->translate_notify)
2397
0
    group->translate_notify (group->translate_data);
2398
2399
0
  group->translate_func = func;
2400
0
  group->translate_data = data;
2401
0
  group->translate_notify = destroy_notify;
2402
0
}
2403
2404
static const gchar *
2405
dgettext_swapped (const gchar *msgid,
2406
                  const gchar *domainname)
2407
0
{
2408
0
  return g_dgettext (domainname, msgid);
2409
0
}
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
g_option_group_set_translation_domain (GOptionGroup *group,
2423
                                       const gchar  *domain)
2424
0
{
2425
0
  g_return_if_fail (group != NULL);
2426
2427
0
  g_option_group_set_translate_func (group,
2428
0
                                     (GTranslateFunc)dgettext_swapped,
2429
0
                                     g_strdup (domain),
2430
0
                                     g_free);
2431
0
}
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
g_option_context_set_translate_func (GOptionContext *context,
2456
                                     GTranslateFunc func,
2457
                                     gpointer       data,
2458
                                     GDestroyNotify destroy_notify)
2459
0
{
2460
0
  g_return_if_fail (context != NULL);
2461
2462
0
  if (context->translate_notify)
2463
0
    context->translate_notify (context->translate_data);
2464
2465
0
  context->translate_func = func;
2466
0
  context->translate_data = data;
2467
0
  context->translate_notify = destroy_notify;
2468
0
}
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
g_option_context_set_translation_domain (GOptionContext *context,
2482
                                         const gchar     *domain)
2483
0
{
2484
0
  g_return_if_fail (context != NULL);
2485
2486
0
  g_option_context_set_translate_func (context,
2487
0
                                       (GTranslateFunc)dgettext_swapped,
2488
0
                                       g_strdup (domain),
2489
0
                                       g_free);
2490
0
}
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
g_option_context_set_summary (GOptionContext *context,
2509
                              const gchar    *summary)
2510
0
{
2511
0
  g_return_if_fail (context != NULL);
2512
2513
0
  g_free (context->summary);
2514
0
  context->summary = g_strdup (summary);
2515
0
}
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
g_option_context_get_summary (GOptionContext *context)
2530
0
{
2531
0
  g_return_val_if_fail (context != NULL, NULL);
2532
2533
0
  return context->summary;
2534
0
}
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
g_option_context_set_description (GOptionContext *context,
2552
                                  const gchar    *description)
2553
0
{
2554
0
  g_return_if_fail (context != NULL);
2555
2556
0
  g_free (context->description);
2557
0
  context->description = g_strdup (description);
2558
0
}
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
g_option_context_get_description (GOptionContext *context)
2573
0
{
2574
0
  g_return_val_if_fail (context != NULL, NULL);
2575
2576
0
  return context->description;
2577
0
}
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
g_option_context_parse_strv (GOptionContext   *context,
2612
                             gchar          ***arguments,
2613
                             GError          **error)
2614
0
{
2615
0
  gboolean success;
2616
0
  gint argc;
2617
2618
0
  g_return_val_if_fail (context != NULL, FALSE);
2619
2620
0
  context->strv_mode = TRUE;
2621
0
  argc = arguments && *arguments ? g_strv_length (*arguments) : 0;
2622
0
  success = g_option_context_parse (context, &argc, arguments, error);
2623
0
  context->strv_mode = FALSE;
2624
2625
0
  return success;
2626
0
}