xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/cli/cli-option.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /* CLI options framework, for GDB.
2 
3    Copyright (C) 2017-2020 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   char *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 	  xfree (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 = xstrdup (str.c_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 	= ov->value->string;
607       ov->value->string = nullptr;
608       break;
609     default:
610       gdb_assert_not_reached ("unhandled option type");
611     }
612 }
613 
614 /* See cli-option.h.  */
615 
616 bool
617 process_options (const char **args,
618 		 process_options_mode mode,
619 		 gdb::array_view<const option_def_group> options_group)
620 {
621   if (*args == nullptr)
622     return false;
623 
624   /* If ARGS starts with "-", look for a "--" sequence.  If one is
625      found, then interpret everything up until the "--" as
626      'gdb::option'-style command line options.  Otherwise, interpret
627      ARGS as possibly the command's operands.  */
628   bool have_delimiter = find_end_options_delimiter (*args) != nullptr;
629 
630   if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER && !have_delimiter)
631     return false;
632 
633   bool processed_any = false;
634 
635   while (1)
636     {
637       *args = skip_spaces (*args);
638 
639       auto ov = parse_option (options_group, mode, have_delimiter, args);
640       if (!ov)
641 	{
642 	  if (processed_any)
643 	    return true;
644 	  return false;
645 	}
646 
647       processed_any = true;
648 
649       save_option_value_in_ctx (ov);
650     }
651 }
652 
653 /* Helper for build_help.  Return a fragment of a help string showing
654    OPT's possible values.  Returns NULL if OPT doesn't take an
655    argument.  */
656 
657 static const char *
658 get_val_type_str (const option_def &opt, std::string &buffer)
659 {
660   if (!opt.have_argument)
661     return nullptr;
662 
663   switch (opt.type)
664     {
665     case var_boolean:
666       return "[on|off]";
667     case var_uinteger:
668     case var_zuinteger_unlimited:
669       return "NUMBER|unlimited";
670     case var_enum:
671       {
672 	buffer = "";
673 	for (size_t i = 0; opt.enums[i] != nullptr; i++)
674 	  {
675 	    if (i != 0)
676 	      buffer += "|";
677 	    buffer += opt.enums[i];
678 	  }
679 	return buffer.c_str ();
680       }
681     case var_string:
682       return "STRING";
683     default:
684       return nullptr;
685     }
686 }
687 
688 /* Helper for build_help.  Appends an indented version of DOC into
689    HELP.  */
690 
691 static void
692 append_indented_doc (const char *doc, std::string &help)
693 {
694   const char *p = doc;
695   const char *n = strchr (p, '\n');
696 
697   while (n != nullptr)
698     {
699       help += "    ";
700       help.append (p, n - p + 1);
701       p = n + 1;
702       n = strchr (p, '\n');
703     }
704   help += "    ";
705   help += p;
706 }
707 
708 /* Fill HELP with an auto-generated "help" string fragment for
709    OPTIONS.  */
710 
711 static void
712 build_help_option (gdb::array_view<const option_def> options,
713 		   std::string &help)
714 {
715   std::string buffer;
716 
717   for (const auto &o : options)
718     {
719       if (o.set_doc == nullptr)
720 	continue;
721 
722       help += "  -";
723       help += o.name;
724 
725       const char *val_type_str = get_val_type_str (o, buffer);
726       if (val_type_str != nullptr)
727 	{
728 	  help += ' ';
729 	  help += val_type_str;
730 	}
731       help += "\n";
732       append_indented_doc (o.set_doc, help);
733       if (o.help_doc != nullptr)
734 	{
735 	  help += "\n";
736 	  append_indented_doc (o.help_doc, help);
737 	}
738     }
739 }
740 
741 /* See cli-option.h.  */
742 
743 std::string
744 build_help (const char *help_tmpl,
745 	    gdb::array_view<const option_def_group> options_group)
746 {
747   bool need_newlines = false;
748   std::string help_str;
749 
750   const char *p = strstr (help_tmpl, "%OPTIONS%");
751   help_str.assign (help_tmpl, p);
752 
753   for (const auto &grp : options_group)
754     for (const auto &opt : grp.options)
755       {
756 	if (need_newlines)
757 	  help_str += "\n\n";
758 	else
759 	  need_newlines = true;
760 	build_help_option (opt, help_str);
761       }
762 
763   p += strlen ("%OPTIONS%");
764   help_str.append (p);
765 
766   return help_str;
767 }
768 
769 /* See cli-option.h.  */
770 
771 void
772 add_setshow_cmds_for_options (command_class cmd_class,
773 			      void *data,
774 			      gdb::array_view<const option_def> options,
775 			      struct cmd_list_element **set_list,
776 			      struct cmd_list_element **show_list)
777 {
778   for (const auto &option : options)
779     {
780       if (option.type == var_boolean)
781 	{
782 	  add_setshow_boolean_cmd (option.name, cmd_class,
783 				   option.var_address.boolean (option, data),
784 				   option.set_doc, option.show_doc,
785 				   option.help_doc,
786 				   nullptr, option.show_cmd_cb,
787 				   set_list, show_list);
788 	}
789       else if (option.type == var_uinteger)
790 	{
791 	  add_setshow_uinteger_cmd (option.name, cmd_class,
792 				    option.var_address.uinteger (option, data),
793 				    option.set_doc, option.show_doc,
794 				    option.help_doc,
795 				    nullptr, option.show_cmd_cb,
796 				    set_list, show_list);
797 	}
798       else if (option.type == var_zuinteger_unlimited)
799 	{
800 	  add_setshow_zuinteger_unlimited_cmd
801 	    (option.name, cmd_class,
802 	     option.var_address.integer (option, data),
803 	     option.set_doc, option.show_doc,
804 	     option.help_doc,
805 	     nullptr, option.show_cmd_cb,
806 	     set_list, show_list);
807 	}
808       else if (option.type == var_enum)
809 	{
810 	  add_setshow_enum_cmd (option.name, cmd_class,
811 				option.enums,
812 				option.var_address.enumeration (option, data),
813 				option.set_doc, option.show_doc,
814 				option.help_doc,
815 				nullptr, option.show_cmd_cb,
816 				set_list, show_list);
817 	}
818       else if (option.type == var_string)
819 	{
820 	  add_setshow_string_cmd (option.name, cmd_class,
821 				  option.var_address.string (option, data),
822 				  option.set_doc, option.show_doc,
823 				  option.help_doc,
824 				  nullptr, option.show_cmd_cb,
825 				  set_list, show_list);
826 	}
827       else
828 	gdb_assert_not_reached (_("option type not handled"));
829     }
830 }
831 
832 } /* namespace option */
833 } /* namespace gdb */
834