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