Coverage Report

Created: 2025-08-26 06:31

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