1 /* CLI options framework, for GDB.
2 
3    Copyright (C) 2017-2024 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "cli/cli-option.h"
21 #include "cli/cli-decode.h"
22 #include "cli/cli-utils.h"
23 #include "cli/cli-setshow.h"
24 #include "command.h"
25 #include <vector>
26 
27 namespace gdb {
28 namespace option {
29 
30 /* An option's value.  Which field is active depends on the option's
31    type.  */
32 union option_value
33 {
34   /* For var_boolean options.  */
35   bool boolean;
36 
37   /* For var_uinteger options.  */
38   unsigned int uinteger;
39 
40   /* For var_integer and var_pinteger options.  */
41   int integer;
42 
43   /* For var_enum options.  */
44   const char *enumeration;
45 
46   /* For var_string options.  This is malloc-allocated.  */
47   std::string *string;
48 };
49 
50 /* Holds an options definition and its value.  */
51 struct option_def_and_value
52 {
53   /* The option definition.  */
54   const option_def &option;
55 
56   /* A context.  */
57   void *ctx;
58 
59   /* The option's value, if any.  */
60   std::optional<option_value> value;
61 
62   /* Constructor.  */
63   option_def_and_value (const option_def &option_, void *ctx_,
64                               std::optional<option_value> &&value_ = {})
optionoption_def_and_value65     : option (option_),
66       ctx (ctx_),
67       value (std::move (value_))
68   {
69     clear_value (option_, value_);
70   }
71 
72   /* Move constructor.  Need this because for some types the values
73      are allocated on the heap.  */
option_def_and_valueoption_def_and_value74   option_def_and_value (option_def_and_value &&rval)
75     : option (rval.option),
76       ctx (rval.ctx),
77       value (std::move (rval.value))
78   {
79     clear_value (rval.option, rval.value);
80   }
81 
82   DISABLE_COPY_AND_ASSIGN (option_def_and_value);
83 
~option_def_and_valueoption_def_and_value84   ~option_def_and_value ()
85   {
86     if (value.has_value ())
87       {
88           if (option.type == var_string)
89             delete value->string;
90       }
91   }
92 
93 private:
94 
95   /* Clear the option_value, without releasing it.  This is used after
96      the value has been moved to some other option_def_and_value
97      instance.  This is needed because for some types the value is
98      allocated on the heap, so we must clear the pointer in the
99      source, to avoid a double free.  */
clear_valueoption_def_and_value100   static void clear_value (const option_def &option,
101                                  std::optional<option_value> &value)
102   {
103     if (value.has_value ())
104       {
105           if (option.type == var_string)
106             value->string = nullptr;
107       }
108   }
109 };
110 
111 static void save_option_value_in_ctx (std::optional<option_def_and_value> &ov);
112 
113 /* Info passed around when handling completion.  */
114 struct parse_option_completion_info
115 {
116   /* The completion word.  */
117   const char *word;
118 
119   /* The tracker.  */
120   completion_tracker &tracker;
121 };
122 
123 /* If ARGS starts with "-", look for a "--" delimiter.  If one is
124    found, then interpret everything up until the "--" as command line
125    options.  Otherwise, interpret unknown input as the beginning of
126    the command's operands.  */
127 
128 static const char *
find_end_options_delimiter(const char * args)129 find_end_options_delimiter (const char *args)
130 {
131   if (args[0] == '-')
132     {
133       const char *p = args;
134 
135       p = skip_spaces (p);
136       while (*p)
137           {
138             if (check_for_argument (&p, "--"))
139               return p;
140             else
141               p = skip_to_space (p);
142             p = skip_spaces (p);
143           }
144     }
145 
146   return nullptr;
147 }
148 
149 /* Complete TEXT/WORD on all options in OPTIONS_GROUP.  */
150 
151 static void
complete_on_options(gdb::array_view<const option_def_group> options_group,completion_tracker & tracker,const char * text,const char * word)152 complete_on_options (gdb::array_view<const option_def_group> options_group,
153                          completion_tracker &tracker,
154                          const char *text, const char *word)
155 {
156   size_t textlen = strlen (text);
157   for (const auto &grp : options_group)
158     for (const auto &opt : grp.options)
159       if (strncmp (opt.name, text, textlen) == 0)
160           {
161             tracker.add_completion
162               (make_completion_match_str (opt.name, text, word));
163           }
164 }
165 
166 /* See cli-option.h.  */
167 
168 void
complete_on_all_options(completion_tracker & tracker,gdb::array_view<const option_def_group> options_group)169 complete_on_all_options (completion_tracker &tracker,
170                                gdb::array_view<const option_def_group> options_group)
171 {
172   static const char opt[] = "-";
173   complete_on_options (options_group, tracker, opt + 1, opt);
174 }
175 
176 /* Parse ARGS, guided by OPTIONS_GROUP.  HAVE_DELIMITER is true if the
177    whole ARGS line included the "--" options-terminator delimiter.  */
178 
179 static std::optional<option_def_and_value>
180 parse_option (gdb::array_view<const option_def_group> options_group,
181                 process_options_mode mode,
182                 bool have_delimiter,
183                 const char **args,
184                 parse_option_completion_info *completion = nullptr)
185 {
186   if (*args == nullptr)
187     return {};
188   else if (**args != '-')
189     {
190       if (have_delimiter)
191           error (_("Unrecognized option at: %s"), *args);
192       return {};
193     }
194   else if (check_for_argument (args, "--"))
195     return {};
196 
197   /* Skip the initial '-'.  */
198   const char *arg = *args + 1;
199 
200   const char *after = skip_to_space (arg);
201   size_t len = after - arg;
202   const option_def *match = nullptr;
203   void *match_ctx = nullptr;
204 
205   for (const auto &grp : options_group)
206     {
207       for (const auto &o : grp.options)
208           {
209             if (strncmp (o.name, arg, len) == 0)
210               {
211                 if (match != nullptr)
212                     {
213                       if (completion != nullptr && arg[len] == '\0')
214                         {
215                           complete_on_options (options_group,
216                                                      completion->tracker,
217                                                      arg, completion->word);
218                           return {};
219                         }
220 
221                       error (_("Ambiguous option at: -%s"), arg);
222                     }
223 
224                 match = &o;
225                 match_ctx = grp.ctx;
226 
227                 if ((isspace (arg[len]) || arg[len] == '\0')
228                       && strlen (o.name) == len)
229                     break; /* Exact match.  */
230               }
231           }
232     }
233 
234   if (match == nullptr)
235     {
236       if (have_delimiter || mode != PROCESS_OPTIONS_UNKNOWN_IS_OPERAND)
237           error (_("Unrecognized option at: %s"), *args);
238 
239       return {};
240     }
241 
242   if (completion != nullptr && arg[len] == '\0')
243     {
244       complete_on_options (options_group, completion->tracker,
245                                  arg, completion->word);
246       return {};
247     }
248 
249   *args += 1 + len;
250   *args = skip_spaces (*args);
251   if (completion != nullptr)
252     completion->word = *args;
253 
254   switch (match->type)
255     {
256     case var_boolean:
257       {
258           if (!match->have_argument)
259             {
260               option_value val;
261               val.boolean = true;
262               return option_def_and_value {*match, match_ctx, val};
263             }
264 
265           const char *val_str = *args;
266           int res;
267 
268           if (**args == '\0' && completion != nullptr)
269             {
270               /* Complete on both "on/off" and more options.  */
271 
272               if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER)
273                 {
274                     complete_on_enum (completion->tracker,
275                                           boolean_enums, val_str, val_str);
276                     complete_on_all_options (completion->tracker, options_group);
277                 }
278               return option_def_and_value {*match, match_ctx};
279             }
280           else if (**args == '-')
281             {
282               /* Treat:
283                      "cmd -boolean-option -another-opt..."
284                  as:
285                      "cmd -boolean-option on -another-opt..."
286                */
287               res = 1;
288             }
289           else if (**args == '\0')
290             {
291               /* Treat:
292                      (1) "cmd -boolean-option "
293                  as:
294                      (1) "cmd -boolean-option on"
295                */
296               res = 1;
297             }
298           else
299             {
300               res = parse_cli_boolean_value (args);
301               if (res < 0)
302                 {
303                     const char *end = skip_to_space (*args);
304                     if (completion != nullptr)
305                       {
306                         if (*end == '\0')
307                           {
308                               complete_on_enum (completion->tracker,
309                                                     boolean_enums, val_str, val_str);
310                               return option_def_and_value {*match, match_ctx};
311                           }
312                       }
313 
314                     if (have_delimiter)
315                       error (_("Value given for `-%s' is not a boolean: %.*s"),
316                                match->name, (int) (end - val_str), val_str);
317                     /* The user didn't separate options from operands
318                        using "--", so treat this unrecognized value as the
319                        start of the operands.  This makes "frame apply all
320                        -past-main CMD" work.  */
321                     return option_def_and_value {*match, match_ctx};
322                 }
323               else if (completion != nullptr && **args == '\0')
324                 {
325                     /* While "cmd -boolean [TAB]" only offers "on" and
326                        "off", the boolean option actually accepts "1",
327                        "yes", etc. as boolean values.  We complete on all
328                        of those instead of BOOLEAN_ENUMS here to make
329                        these work:
330 
331                         "p -object 1[TAB]" -> "p -object 1 "
332                         "p -object ye[TAB]" -> "p -object yes "
333 
334                        Etc.  Note that it's important that the space is
335                        auto-appended.  Otherwise, if we only completed on
336                        on/off here, then it might look to the user like
337                        "1" isn't valid, like:
338                        "p -object 1[TAB]" -> "p -object 1" (i.e., nothing happens).
339                     */
340                     static const char *const all_boolean_enums[] = {
341                       "on", "off",
342                       "yes", "no",
343                       "enable", "disable",
344                       "0", "1",
345                       nullptr,
346                     };
347                     complete_on_enum (completion->tracker, all_boolean_enums,
348                                           val_str, val_str);
349                     return {};
350                 }
351             }
352 
353           option_value val;
354           val.boolean = res;
355           return option_def_and_value {*match, match_ctx, val};
356       }
357     case var_uinteger:
358     case var_integer:
359     case var_pinteger:
360       {
361           if (completion != nullptr && match->extra_literals != nullptr)
362             {
363               /* Convenience to let the user know what the option can
364                  accept.  Make sure there's no common prefix between
365                  "NUMBER" and all the strings when adding new ones,
366                  so that readline doesn't do a partial match.  */
367               if (**args == '\0')
368                 {
369                     completion->tracker.add_completion
370                       (make_unique_xstrdup ("NUMBER"));
371                     for (const literal_def *l = match->extra_literals;
372                          l->literal != nullptr;
373                          l++)
374                       completion->tracker.add_completion
375                         (make_unique_xstrdup (l->literal));
376                     return {};
377                 }
378               else
379                 {
380                     bool completions = false;
381                     for (const literal_def *l = match->extra_literals;
382                          l->literal != nullptr;
383                          l++)
384                       if (startswith (l->literal, *args))
385                         {
386                           completion->tracker.add_completion
387                               (make_unique_xstrdup (l->literal));
388                           completions = true;
389                         }
390                     if (completions)
391                       return {};
392                 }
393             }
394 
395           LONGEST v = parse_cli_var_integer (match->type,
396                                                      match->extra_literals,
397                                                      args, false);
398           option_value val;
399           if (match->type == var_uinteger)
400             val.uinteger = v;
401           else
402             val.integer = v;
403           return option_def_and_value {*match, match_ctx, val};
404       }
405     case var_enum:
406       {
407           if (completion != nullptr)
408             {
409               const char *after_arg = skip_to_space (*args);
410               if (*after_arg == '\0')
411                 {
412                     complete_on_enum (completion->tracker,
413                                           match->enums, *args, *args);
414                     if (completion->tracker.have_completions ())
415                       return {};
416 
417                     /* If we don't have completions, let the
418                        non-completion path throw on invalid enum value
419                        below, so that completion processing stops.  */
420                 }
421             }
422 
423           if (check_for_argument (args, "--"))
424             {
425               /* Treat e.g., "backtrace -entry-values --" as if there
426                  was no argument after "-entry-values".  This makes
427                  parse_cli_var_enum throw an error with a suggestion of
428                  what are the valid options.  */
429               args = nullptr;
430             }
431 
432           option_value val;
433           val.enumeration = parse_cli_var_enum (args, match->enums);
434           return option_def_and_value {*match, match_ctx, val};
435       }
436     case var_string:
437       {
438           if (check_for_argument (args, "--"))
439             {
440               /* Treat e.g., "maint test-options -string --" as if there
441                  was no argument after "-string".  */
442               error (_("-%s requires an argument"), match->name);
443             }
444 
445           const char *arg_start = *args;
446           std::string str = extract_string_maybe_quoted (args);
447           if (*args == arg_start)
448             error (_("-%s requires an argument"), match->name);
449 
450           option_value val;
451           val.string = new std::string (std::move (str));
452           return option_def_and_value {*match, match_ctx, val};
453       }
454 
455     default:
456       /* Not yet.  */
457       gdb_assert_not_reached ("option type not supported");
458     }
459 
460   return {};
461 }
462 
463 /* See cli-option.h.  */
464 
465 bool
complete_options(completion_tracker & tracker,const char ** args,process_options_mode mode,gdb::array_view<const option_def_group> options_group)466 complete_options (completion_tracker &tracker,
467                       const char **args,
468                       process_options_mode mode,
469                       gdb::array_view<const option_def_group> options_group)
470 {
471   const char *text = *args;
472 
473   tracker.set_use_custom_word_point (true);
474 
475   const char *delimiter = find_end_options_delimiter (text);
476   bool have_delimiter = delimiter != nullptr;
477 
478   if (text[0] == '-' && (!have_delimiter || *delimiter == '\0'))
479     {
480       parse_option_completion_info completion_info {nullptr, tracker};
481 
482       while (1)
483           {
484             *args = skip_spaces (*args);
485             completion_info.word = *args;
486 
487             if (strcmp (*args, "-") == 0)
488               {
489                 complete_on_options (options_group, tracker, *args + 1,
490                                            completion_info.word);
491               }
492             else if (strcmp (*args, "--") == 0)
493               {
494                 tracker.add_completion (make_unique_xstrdup (*args));
495               }
496             else if (**args == '-')
497               {
498                 std::optional<option_def_and_value> ov
499                     = parse_option (options_group, mode, have_delimiter,
500                                         args, &completion_info);
501                 if (!ov && !tracker.have_completions ())
502                     {
503                       tracker.advance_custom_word_point_by (*args - text);
504                       return mode == PROCESS_OPTIONS_REQUIRE_DELIMITER;
505                     }
506 
507                 if (ov
508                       && ov->option.type == var_boolean
509                       && !ov->value.has_value ())
510                     {
511                       /* Looked like a boolean option, but we failed to
512                          parse the value.  If this command requires a
513                          delimiter, this value can't be the start of the
514                          operands, so return true.  Otherwise, if the
515                          command doesn't require a delimiter return false
516                          so that the caller tries to complete on the
517                          operand.  */
518                       tracker.advance_custom_word_point_by (*args - text);
519                       return mode == PROCESS_OPTIONS_REQUIRE_DELIMITER;
520                     }
521 
522                 /* If we parsed an option with an argument, and reached
523                      the end of the input string with no trailing space,
524                      return true, so that our callers don't try to
525                      complete anything by themselves.  E.g., this makes it
526                      so that with:
527 
528                       (gdb) frame apply all -limit 10[TAB]
529 
530                      we don't try to complete on command names.  */
531                 if (ov
532                       && !tracker.have_completions ()
533                       && **args == '\0'
534                       && *args > text && !isspace ((*args)[-1]))
535                     {
536                       tracker.advance_custom_word_point_by
537                         (*args - text);
538                       return true;
539                     }
540 
541                 /* If the caller passed in a context, then it is
542                      interested in the option argument values.  */
543                 if (ov && ov->ctx != nullptr)
544                     save_option_value_in_ctx (ov);
545               }
546             else
547               {
548                 tracker.advance_custom_word_point_by
549                     (completion_info.word - text);
550 
551                 /* If the command requires a delimiter, but we haven't
552                      seen one, then return true, so that the caller
553                      doesn't try to complete on whatever follows options,
554                      which for these commands should only be done if
555                      there's a delimiter.  */
556                 if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER
557                       && !have_delimiter)
558                     {
559                       /* If we reached the end of the input string, then
560                          offer all options, since that's all the user can
561                          type (plus "--").  */
562                       if (completion_info.word[0] == '\0')
563                         complete_on_all_options (tracker, options_group);
564                       return true;
565                     }
566                 else
567                     return false;
568               }
569 
570             if (tracker.have_completions ())
571               {
572                 tracker.advance_custom_word_point_by
573                     (completion_info.word - text);
574                 return true;
575               }
576           }
577     }
578   else if (delimiter != nullptr)
579     {
580       tracker.advance_custom_word_point_by (delimiter - text);
581       *args = delimiter;
582       return false;
583     }
584 
585   return false;
586 }
587 
588 /* Save the parsed value in the option's context.  */
589 
590 static void
save_option_value_in_ctx(std::optional<option_def_and_value> & ov)591 save_option_value_in_ctx (std::optional<option_def_and_value> &ov)
592 {
593   switch (ov->option.type)
594     {
595     case var_boolean:
596       {
597           bool value = ov->value.has_value () ? ov->value->boolean : true;
598           *ov->option.var_address.boolean (ov->option, ov->ctx) = value;
599       }
600       break;
601     case var_uinteger:
602       *ov->option.var_address.uinteger (ov->option, ov->ctx)
603           = ov->value->uinteger;
604       break;
605     case var_integer:
606     case var_pinteger:
607       *ov->option.var_address.integer (ov->option, ov->ctx)
608           = ov->value->integer;
609       break;
610     case var_enum:
611       *ov->option.var_address.enumeration (ov->option, ov->ctx)
612           = ov->value->enumeration;
613       break;
614     case var_string:
615       *ov->option.var_address.string (ov->option, ov->ctx)
616           = std::move (*ov->value->string);
617       break;
618     default:
619       gdb_assert_not_reached ("unhandled option type");
620     }
621 }
622 
623 /* See cli-option.h.  */
624 
625 bool
process_options(const char ** args,process_options_mode mode,gdb::array_view<const option_def_group> options_group)626 process_options (const char **args,
627                      process_options_mode mode,
628                      gdb::array_view<const option_def_group> options_group)
629 {
630   if (*args == nullptr)
631     return false;
632 
633   /* If ARGS starts with "-", look for a "--" sequence.  If one is
634      found, then interpret everything up until the "--" as
635      'gdb::option'-style command line options.  Otherwise, interpret
636      ARGS as possibly the command's operands.  */
637   bool have_delimiter = find_end_options_delimiter (*args) != nullptr;
638 
639   if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER && !have_delimiter)
640     return false;
641 
642   bool processed_any = false;
643 
644   while (1)
645     {
646       *args = skip_spaces (*args);
647 
648       auto ov = parse_option (options_group, mode, have_delimiter, args);
649       if (!ov)
650           {
651             if (processed_any)
652               return true;
653             return false;
654           }
655 
656       processed_any = true;
657 
658       save_option_value_in_ctx (ov);
659     }
660 }
661 
662 /* Helper for build_help.  Return a fragment of a help string showing
663    OPT's possible values.  Returns NULL if OPT doesn't take an
664    argument.  */
665 
666 static const char *
get_val_type_str(const option_def & opt,std::string & buffer)667 get_val_type_str (const option_def &opt, std::string &buffer)
668 {
669   if (!opt.have_argument)
670     return nullptr;
671 
672   switch (opt.type)
673     {
674     case var_boolean:
675       return "[on|off]";
676     case var_uinteger:
677     case var_integer:
678     case var_pinteger:
679       {
680           buffer = "NUMBER";
681           if (opt.extra_literals != nullptr)
682             for (const literal_def *l = opt.extra_literals;
683                  l->literal != nullptr;
684                  l++)
685               {
686                 buffer += '|';
687                 buffer += l->literal;
688               }
689           return buffer.c_str ();
690       }
691     case var_enum:
692       {
693           buffer = "";
694           for (size_t i = 0; opt.enums[i] != nullptr; i++)
695             {
696               if (i != 0)
697                 buffer += "|";
698               buffer += opt.enums[i];
699             }
700           return buffer.c_str ();
701       }
702     case var_string:
703       return "STRING";
704     default:
705       return nullptr;
706     }
707 }
708 
709 /* Helper for build_help.  Appends an indented version of DOC into
710    HELP.  */
711 
712 static void
append_indented_doc(const char * doc,std::string & help)713 append_indented_doc (const char *doc, std::string &help)
714 {
715   const char *p = doc;
716   const char *n = strchr (p, '\n');
717 
718   while (n != nullptr)
719     {
720       help += "    ";
721       help.append (p, n - p + 1);
722       p = n + 1;
723       n = strchr (p, '\n');
724     }
725   help += "    ";
726   help += p;
727 }
728 
729 /* Fill HELP with an auto-generated "help" string fragment for
730    OPTIONS.  */
731 
732 static void
build_help_option(gdb::array_view<const option_def> options,std::string & help)733 build_help_option (gdb::array_view<const option_def> options,
734                        std::string &help)
735 {
736   std::string buffer;
737 
738   for (const auto &o : options)
739     {
740       if (o.set_doc == nullptr)
741           continue;
742 
743       help += "  -";
744       help += o.name;
745 
746       const char *val_type_str = get_val_type_str (o, buffer);
747       if (val_type_str != nullptr)
748           {
749             help += ' ';
750             help += val_type_str;
751           }
752       help += "\n";
753       append_indented_doc (o.set_doc, help);
754       if (o.help_doc != nullptr)
755           {
756             help += "\n";
757             append_indented_doc (o.help_doc, help);
758           }
759     }
760 }
761 
762 /* See cli-option.h.  */
763 
764 std::string
build_help(const char * help_tmpl,gdb::array_view<const option_def_group> options_group)765 build_help (const char *help_tmpl,
766               gdb::array_view<const option_def_group> options_group)
767 {
768   bool need_newlines = false;
769   std::string help_str;
770 
771   const char *p = strstr (help_tmpl, "%OPTIONS%");
772   help_str.assign (help_tmpl, p);
773 
774   for (const auto &grp : options_group)
775     for (const auto &opt : grp.options)
776       {
777           if (need_newlines)
778             help_str += "\n\n";
779           else
780             need_newlines = true;
781           build_help_option (opt, help_str);
782       }
783 
784   p += strlen ("%OPTIONS%");
785   help_str.append (p);
786 
787   return help_str;
788 }
789 
790 /* See cli-option.h.  */
791 
792 void
add_setshow_cmds_for_options(command_class cmd_class,void * data,gdb::array_view<const option_def> options,struct cmd_list_element ** set_list,struct cmd_list_element ** show_list)793 add_setshow_cmds_for_options (command_class cmd_class,
794                                     void *data,
795                                     gdb::array_view<const option_def> options,
796                                     struct cmd_list_element **set_list,
797                                     struct cmd_list_element **show_list)
798 {
799   for (const auto &option : options)
800     {
801       if (option.type == var_boolean)
802           {
803             add_setshow_boolean_cmd (option.name, cmd_class,
804                                            option.var_address.boolean (option, data),
805                                            option.set_doc, option.show_doc,
806                                            option.help_doc,
807                                            nullptr, option.show_cmd_cb,
808                                            set_list, show_list);
809           }
810       else if (option.type == var_uinteger)
811           {
812             add_setshow_uinteger_cmd (option.name, cmd_class,
813                                             option.var_address.uinteger (option, data),
814                                             option.extra_literals,
815                                             option.set_doc, option.show_doc,
816                                             option.help_doc,
817                                             nullptr, option.show_cmd_cb,
818                                             set_list, show_list);
819           }
820       else if (option.type == var_integer)
821           {
822             add_setshow_integer_cmd (option.name, cmd_class,
823                                            option.var_address.integer (option, data),
824                                            option.extra_literals,
825                                            option.set_doc, option.show_doc,
826                                            option.help_doc,
827                                            nullptr, option.show_cmd_cb,
828                                            set_list, show_list);
829           }
830       else if (option.type == var_pinteger)
831           {
832             add_setshow_pinteger_cmd (option.name, cmd_class,
833                                             option.var_address.integer (option, data),
834                                             option.extra_literals,
835                                             option.set_doc, option.show_doc,
836                                             option.help_doc,
837                                             nullptr, option.show_cmd_cb,
838                                             set_list, show_list);
839           }
840       else if (option.type == var_enum)
841           {
842             add_setshow_enum_cmd (option.name, cmd_class,
843                                         option.enums,
844                                         option.var_address.enumeration (option, data),
845                                         option.set_doc, option.show_doc,
846                                         option.help_doc,
847                                         nullptr, option.show_cmd_cb,
848                                         set_list, show_list);
849           }
850       else if (option.type == var_string)
851           {
852             add_setshow_string_cmd (option.name, cmd_class,
853                                           option.var_address.string (option, data),
854                                           option.set_doc, option.show_doc,
855                                           option.help_doc,
856                                           nullptr, option.show_cmd_cb,
857                                           set_list, show_list);
858           }
859       else
860           gdb_assert_not_reached ("option type not handled");
861     }
862 }
863 
864 } /* namespace option */
865 } /* namespace gdb */
866