Coverage Report

Created: 2025-11-11 06:44

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