]>
Commit | Line | Data |
---|---|---|
1 | /* Handle lists of commands, their decoding and documentation, for GDB. | |
2 | ||
3 | Copyright (C) 1986-2025 Free Software Foundation, Inc. | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | #include "symtab.h" | |
19 | #include <ctype.h> | |
20 | #include "gdbsupport/gdb_regex.h" | |
21 | #include "completer.h" | |
22 | #include "ui-out.h" | |
23 | #include "cli/cli-cmds.h" | |
24 | #include "cli/cli-decode.h" | |
25 | #include "cli/cli-style.h" | |
26 | #include "cli/cli-utils.h" | |
27 | #include <optional> | |
28 | ||
29 | /* Prototypes for local functions. */ | |
30 | ||
31 | static void undef_cmd_error (const char *, const char *); | |
32 | ||
33 | static cmd_list_element::aliases_list_type delete_cmd | |
34 | (const char *name, cmd_list_element **list, cmd_list_element **prehook, | |
35 | cmd_list_element **prehookee, cmd_list_element **posthook, | |
36 | cmd_list_element **posthookee); | |
37 | ||
38 | static struct cmd_list_element *find_cmd (const char *command, | |
39 | int len, | |
40 | struct cmd_list_element *clist, | |
41 | int ignore_help_classes, | |
42 | int *nfound); | |
43 | ||
44 | static void help_cmd_list (struct cmd_list_element *list, | |
45 | enum command_class theclass, | |
46 | bool recurse, | |
47 | struct ui_file *stream); | |
48 | ||
49 | static void help_all (struct ui_file *stream); | |
50 | ||
51 | static int lookup_cmd_composition_1 (const char *text, | |
52 | struct cmd_list_element **alias, | |
53 | struct cmd_list_element **prefix_cmd, | |
54 | struct cmd_list_element **cmd, | |
55 | struct cmd_list_element *cur_list); | |
56 | ||
57 | /* Look up a command whose 'subcommands' field is SUBCOMMANDS. Return the | |
58 | command if found, otherwise return NULL. */ | |
59 | ||
60 | static struct cmd_list_element * | |
61 | lookup_cmd_with_subcommands (cmd_list_element **subcommands, | |
62 | cmd_list_element *list) | |
63 | { | |
64 | struct cmd_list_element *p = NULL; | |
65 | ||
66 | for (p = list; p != NULL; p = p->next) | |
67 | { | |
68 | struct cmd_list_element *q; | |
69 | ||
70 | if (!p->is_prefix ()) | |
71 | continue; | |
72 | ||
73 | else if (p->subcommands == subcommands) | |
74 | { | |
75 | /* If we found an alias, we must return the aliased | |
76 | command. */ | |
77 | return p->is_alias () ? p->alias_target : p; | |
78 | } | |
79 | ||
80 | q = lookup_cmd_with_subcommands (subcommands, *(p->subcommands)); | |
81 | if (q != NULL) | |
82 | return q; | |
83 | } | |
84 | ||
85 | return NULL; | |
86 | } | |
87 | ||
88 | static void | |
89 | print_help_for_command (const cmd_list_element &c, | |
90 | bool recurse, struct ui_file *stream); | |
91 | ||
92 | static void | |
93 | do_simple_func (const char *args, int from_tty, cmd_list_element *c) | |
94 | { | |
95 | c->function.simple_func (args, from_tty); | |
96 | } | |
97 | ||
98 | static void | |
99 | set_cmd_simple_func (struct cmd_list_element *cmd, cmd_simple_func_ftype *simple_func) | |
100 | { | |
101 | if (simple_func == NULL) | |
102 | cmd->func = NULL; | |
103 | else | |
104 | cmd->func = do_simple_func; | |
105 | ||
106 | cmd->function.simple_func = simple_func; | |
107 | } | |
108 | ||
109 | int | |
110 | cmd_simple_func_eq (struct cmd_list_element *cmd, cmd_simple_func_ftype *simple_func) | |
111 | { | |
112 | return (cmd->func == do_simple_func | |
113 | && cmd->function.simple_func == simple_func); | |
114 | } | |
115 | ||
116 | void | |
117 | set_cmd_completer (struct cmd_list_element *cmd, completer_ftype *completer) | |
118 | { | |
119 | cmd->completer = completer; /* Ok. */ | |
120 | } | |
121 | ||
122 | /* See definition in commands.h. */ | |
123 | ||
124 | void | |
125 | set_cmd_completer_handle_brkchars (struct cmd_list_element *cmd, | |
126 | completer_handle_brkchars_ftype *func) | |
127 | { | |
128 | cmd->completer_handle_brkchars = func; | |
129 | } | |
130 | ||
131 | /* See cli-decode.h. */ | |
132 | ||
133 | std::string | |
134 | cmd_list_element::prefixname_no_space () const | |
135 | { | |
136 | if (!this->is_prefix ()) | |
137 | /* Not a prefix command. */ | |
138 | return ""; | |
139 | ||
140 | std::string prefixname; | |
141 | if (this->prefix != nullptr) | |
142 | { | |
143 | prefixname = this->prefix->prefixname_no_space (); | |
144 | prefixname += " "; | |
145 | } | |
146 | ||
147 | prefixname += this->name; | |
148 | ||
149 | return prefixname; | |
150 | } | |
151 | ||
152 | /* See cli-decode.h. */ | |
153 | ||
154 | std::string | |
155 | cmd_list_element::prefixname () const | |
156 | { | |
157 | std::string result = prefixname_no_space (); | |
158 | if (!result.empty ()) | |
159 | result += " "; | |
160 | return result; | |
161 | } | |
162 | ||
163 | /* See cli/cli-decode.h. */ | |
164 | ||
165 | std::vector<std::string> | |
166 | cmd_list_element::command_components () const | |
167 | { | |
168 | std::vector<std::string> result; | |
169 | ||
170 | if (this->prefix != nullptr) | |
171 | result = this->prefix->command_components (); | |
172 | ||
173 | result.emplace_back (this->name); | |
174 | return result; | |
175 | } | |
176 | ||
177 | /* Add element named NAME. | |
178 | Space for NAME and DOC must be allocated by the caller. | |
179 | THECLASS is the top level category into which commands are broken down | |
180 | for "help" purposes. | |
181 | FUN should be the function to execute the command; | |
182 | it will get a character string as argument, with leading | |
183 | and trailing blanks already eliminated. | |
184 | ||
185 | DOC is a documentation string for the command. | |
186 | Its first line should be a complete sentence. | |
187 | It should start with ? for a command that is an abbreviation | |
188 | or with * for a command that most users don't need to know about. | |
189 | ||
190 | Add this command to command list *LIST. | |
191 | ||
192 | Returns a pointer to the added command (not necessarily the head | |
193 | of *LIST). */ | |
194 | ||
195 | static struct cmd_list_element * | |
196 | do_add_cmd (const char *name, enum command_class theclass, | |
197 | const char *doc, struct cmd_list_element **list) | |
198 | { | |
199 | struct cmd_list_element *c = new struct cmd_list_element (name, theclass, | |
200 | doc); | |
201 | ||
202 | /* Turn each alias of the old command into an alias of the new | |
203 | command. */ | |
204 | c->aliases = delete_cmd (name, list, &c->hook_pre, &c->hookee_pre, | |
205 | &c->hook_post, &c->hookee_post); | |
206 | ||
207 | for (cmd_list_element &alias : c->aliases) | |
208 | alias.alias_target = c; | |
209 | ||
210 | if (c->hook_pre) | |
211 | c->hook_pre->hookee_pre = c; | |
212 | ||
213 | if (c->hookee_pre) | |
214 | c->hookee_pre->hook_pre = c; | |
215 | ||
216 | if (c->hook_post) | |
217 | c->hook_post->hookee_post = c; | |
218 | ||
219 | if (c->hookee_post) | |
220 | c->hookee_post->hook_post = c; | |
221 | ||
222 | if (*list == NULL || strcmp ((*list)->name, name) >= 0) | |
223 | { | |
224 | c->next = *list; | |
225 | *list = c; | |
226 | } | |
227 | else | |
228 | { | |
229 | cmd_list_element *p = *list; | |
230 | while (p->next && strcmp (p->next->name, name) <= 0) | |
231 | { | |
232 | p = p->next; | |
233 | } | |
234 | c->next = p->next; | |
235 | p->next = c; | |
236 | } | |
237 | ||
238 | /* Search the prefix cmd of C, and assigns it to C->prefix. | |
239 | See also add_prefix_cmd and update_prefix_field_of_prefixed_commands. */ | |
240 | cmd_list_element *prefixcmd = lookup_cmd_with_subcommands (list, cmdlist); | |
241 | c->prefix = prefixcmd; | |
242 | ||
243 | ||
244 | return c; | |
245 | } | |
246 | ||
247 | struct cmd_list_element * | |
248 | add_cmd (const char *name, enum command_class theclass, | |
249 | const char *doc, struct cmd_list_element **list) | |
250 | { | |
251 | cmd_list_element *result = do_add_cmd (name, theclass, doc, list); | |
252 | result->func = NULL; | |
253 | result->function.simple_func = NULL; | |
254 | return result; | |
255 | } | |
256 | ||
257 | struct cmd_list_element * | |
258 | add_cmd (const char *name, enum command_class theclass, | |
259 | cmd_simple_func_ftype *fun, | |
260 | const char *doc, struct cmd_list_element **list) | |
261 | { | |
262 | cmd_list_element *result = do_add_cmd (name, theclass, doc, list); | |
263 | set_cmd_simple_func (result, fun); | |
264 | return result; | |
265 | } | |
266 | ||
267 | /* Add an element with a suppress notification to the LIST of commands. */ | |
268 | ||
269 | struct cmd_list_element * | |
270 | add_cmd_suppress_notification (const char *name, enum command_class theclass, | |
271 | cmd_simple_func_ftype *fun, const char *doc, | |
272 | struct cmd_list_element **list, | |
273 | bool *suppress_notification) | |
274 | { | |
275 | struct cmd_list_element *element; | |
276 | ||
277 | element = add_cmd (name, theclass, fun, doc, list); | |
278 | element->suppress_notification = suppress_notification; | |
279 | ||
280 | return element; | |
281 | } | |
282 | ||
283 | ||
284 | /* Deprecates a command CMD. | |
285 | REPLACEMENT is the name of the command which should be used in | |
286 | place of this command, or NULL if no such command exists. | |
287 | ||
288 | This function does not check to see if command REPLACEMENT exists | |
289 | since gdb may not have gotten around to adding REPLACEMENT when | |
290 | this function is called. | |
291 | ||
292 | Returns a pointer to the deprecated command. */ | |
293 | ||
294 | struct cmd_list_element * | |
295 | deprecate_cmd (struct cmd_list_element *cmd, const char *replacement) | |
296 | { | |
297 | cmd->cmd_deprecated = 1; | |
298 | cmd->deprecated_warn_user = 1; | |
299 | ||
300 | if (replacement != NULL) | |
301 | cmd->replacement = replacement; | |
302 | else | |
303 | cmd->replacement = NULL; | |
304 | ||
305 | return cmd; | |
306 | } | |
307 | ||
308 | struct cmd_list_element * | |
309 | add_alias_cmd (const char *name, cmd_list_element *target, | |
310 | enum command_class theclass, int abbrev_flag, | |
311 | struct cmd_list_element **list) | |
312 | { | |
313 | gdb_assert (target != nullptr); | |
314 | ||
315 | struct cmd_list_element *c = add_cmd (name, theclass, target->doc, list); | |
316 | ||
317 | /* If TARGET->DOC can be freed, we should make another copy. */ | |
318 | if (target->doc_allocated) | |
319 | { | |
320 | c->doc = xstrdup (target->doc); | |
321 | c->doc_allocated = 1; | |
322 | } | |
323 | /* NOTE: Both FUNC and all the FUNCTIONs need to be copied. */ | |
324 | c->func = target->func; | |
325 | c->function = target->function; | |
326 | c->subcommands = target->subcommands; | |
327 | c->allow_unknown = target->allow_unknown; | |
328 | c->abbrev_flag = abbrev_flag; | |
329 | c->alias_target = target; | |
330 | target->aliases.push_front (*c); | |
331 | ||
332 | return c; | |
333 | } | |
334 | ||
335 | /* Update the prefix field of all sub-commands of the prefix command C. | |
336 | We must do this when a prefix command is defined as the GDB init sequence | |
337 | does not guarantee that a prefix command is created before its sub-commands. | |
338 | For example, break-catch-sig.c initialization runs before breakpoint.c | |
339 | initialization, but it is breakpoint.c that creates the "catch" command used | |
340 | by the "catch signal" command created by break-catch-sig.c. */ | |
341 | ||
342 | static void | |
343 | update_prefix_field_of_prefixed_commands (struct cmd_list_element *c) | |
344 | { | |
345 | for (cmd_list_element *p = *c->subcommands; p != NULL; p = p->next) | |
346 | { | |
347 | p->prefix = c; | |
348 | ||
349 | /* We must recursively update the prefix field to cover | |
350 | e.g. 'info auto-load libthread-db' where the creation | |
351 | order was: | |
352 | libthread-db | |
353 | auto-load | |
354 | info | |
355 | In such a case, when 'auto-load' was created by do_add_cmd, | |
356 | the 'libthread-db' prefix field could not be updated, as the | |
357 | 'auto-load' command was not yet reachable by | |
358 | lookup_cmd_for_subcommands (list, cmdlist) | |
359 | that searches from the top level 'cmdlist'. */ | |
360 | if (p->is_prefix ()) | |
361 | update_prefix_field_of_prefixed_commands (p); | |
362 | } | |
363 | } | |
364 | ||
365 | ||
366 | /* Like add_cmd but adds an element for a command prefix: a name that | |
367 | should be followed by a subcommand to be looked up in another | |
368 | command list. SUBCOMMANDS should be the address of the variable | |
369 | containing that list. */ | |
370 | ||
371 | struct cmd_list_element * | |
372 | add_prefix_cmd (const char *name, enum command_class theclass, | |
373 | cmd_simple_func_ftype *fun, | |
374 | const char *doc, struct cmd_list_element **subcommands, | |
375 | int allow_unknown, struct cmd_list_element **list) | |
376 | { | |
377 | struct cmd_list_element *c = add_cmd (name, theclass, fun, doc, list); | |
378 | ||
379 | c->subcommands = subcommands; | |
380 | c->allow_unknown = allow_unknown; | |
381 | ||
382 | /* Now that prefix command C is defined, we need to set the prefix field | |
383 | of all prefixed commands that were defined before C itself was defined. */ | |
384 | update_prefix_field_of_prefixed_commands (c); | |
385 | ||
386 | return c; | |
387 | } | |
388 | ||
389 | /* A helper function for add_basic_prefix_cmd. This is a command | |
390 | function that just forwards to help_list. */ | |
391 | ||
392 | static void | |
393 | do_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c) | |
394 | { | |
395 | /* Look past all aliases. */ | |
396 | while (c->is_alias ()) | |
397 | c = c->alias_target; | |
398 | ||
399 | help_list (*c->subcommands, c->prefixname_no_space ().c_str (), | |
400 | all_commands, gdb_stdout); | |
401 | } | |
402 | ||
403 | /* See command.h. */ | |
404 | ||
405 | struct cmd_list_element * | |
406 | add_basic_prefix_cmd (const char *name, enum command_class theclass, | |
407 | const char *doc, struct cmd_list_element **subcommands, | |
408 | int allow_unknown, struct cmd_list_element **list) | |
409 | { | |
410 | struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr, | |
411 | doc, subcommands, | |
412 | allow_unknown, list); | |
413 | cmd->func = do_prefix_cmd; | |
414 | return cmd; | |
415 | } | |
416 | ||
417 | /* A helper function for add_show_prefix_cmd. This is a command | |
418 | function that just forwards to cmd_show_list. */ | |
419 | ||
420 | static void | |
421 | do_show_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c) | |
422 | { | |
423 | cmd_show_list (*c->subcommands, from_tty); | |
424 | } | |
425 | ||
426 | /* See command.h. */ | |
427 | ||
428 | struct cmd_list_element * | |
429 | add_show_prefix_cmd (const char *name, enum command_class theclass, | |
430 | const char *doc, struct cmd_list_element **subcommands, | |
431 | int allow_unknown, struct cmd_list_element **list) | |
432 | { | |
433 | struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr, | |
434 | doc, subcommands, | |
435 | allow_unknown, list); | |
436 | cmd->func = do_show_prefix_cmd; | |
437 | return cmd; | |
438 | } | |
439 | ||
440 | /* See command.h. */ | |
441 | ||
442 | set_show_commands | |
443 | add_setshow_prefix_cmd (const char *name, command_class theclass, | |
444 | const char *set_doc, const char *show_doc, | |
445 | cmd_list_element **set_subcommands_list, | |
446 | cmd_list_element **show_subcommands_list, | |
447 | cmd_list_element **set_list, | |
448 | cmd_list_element **show_list) | |
449 | { | |
450 | set_show_commands cmds; | |
451 | ||
452 | cmds.set = add_basic_prefix_cmd (name, theclass, set_doc, | |
453 | set_subcommands_list, 0, | |
454 | set_list); | |
455 | cmds.show = add_show_prefix_cmd (name, theclass, show_doc, | |
456 | show_subcommands_list, 0, | |
457 | show_list); | |
458 | ||
459 | return cmds; | |
460 | } | |
461 | ||
462 | /* Like ADD_PREFIX_CMD but sets the suppress_notification pointer on the | |
463 | new command list element. */ | |
464 | ||
465 | struct cmd_list_element * | |
466 | add_prefix_cmd_suppress_notification | |
467 | (const char *name, enum command_class theclass, | |
468 | cmd_simple_func_ftype *fun, | |
469 | const char *doc, struct cmd_list_element **subcommands, | |
470 | int allow_unknown, struct cmd_list_element **list, | |
471 | bool *suppress_notification) | |
472 | { | |
473 | struct cmd_list_element *element | |
474 | = add_prefix_cmd (name, theclass, fun, doc, subcommands, | |
475 | allow_unknown, list); | |
476 | element->suppress_notification = suppress_notification; | |
477 | return element; | |
478 | } | |
479 | ||
480 | /* Like add_prefix_cmd but sets the abbrev_flag on the new command. */ | |
481 | ||
482 | struct cmd_list_element * | |
483 | add_abbrev_prefix_cmd (const char *name, enum command_class theclass, | |
484 | cmd_simple_func_ftype *fun, const char *doc, | |
485 | struct cmd_list_element **subcommands, | |
486 | int allow_unknown, struct cmd_list_element **list) | |
487 | { | |
488 | struct cmd_list_element *c = add_cmd (name, theclass, fun, doc, list); | |
489 | ||
490 | c->subcommands = subcommands; | |
491 | c->allow_unknown = allow_unknown; | |
492 | c->abbrev_flag = 1; | |
493 | return c; | |
494 | } | |
495 | ||
496 | /* This is an empty "simple func". */ | |
497 | void | |
498 | not_just_help_class_command (const char *args, int from_tty) | |
499 | { | |
500 | } | |
501 | ||
502 | /* This is an empty cmd func. */ | |
503 | ||
504 | static void | |
505 | empty_func (const char *args, int from_tty, cmd_list_element *c) | |
506 | { | |
507 | } | |
508 | ||
509 | /* Add element named NAME to command list LIST (the list for set/show | |
510 | or some sublist thereof). | |
511 | TYPE is set_cmd or show_cmd. | |
512 | THECLASS is as in add_cmd. | |
513 | VAR_TYPE is the kind of thing we are setting. | |
514 | EXTRA_LITERALS if non-NULL define extra literals to be accepted in lieu of | |
515 | a number for integer variables. | |
516 | ARGS is a pre-validated type-erased reference to the variable being | |
517 | controlled by this command. | |
518 | DOC is the documentation string. */ | |
519 | ||
520 | static struct cmd_list_element * | |
521 | add_set_or_show_cmd (const char *name, | |
522 | enum cmd_types type, | |
523 | enum command_class theclass, | |
524 | var_types var_type, | |
525 | const literal_def *extra_literals, | |
526 | const setting::erased_args &arg, | |
527 | const char *doc, | |
528 | struct cmd_list_element **list) | |
529 | { | |
530 | struct cmd_list_element *c = add_cmd (name, theclass, doc, list); | |
531 | ||
532 | gdb_assert (type == set_cmd || type == show_cmd); | |
533 | c->type = type; | |
534 | c->var.emplace (var_type, extra_literals, arg); | |
535 | ||
536 | /* This needs to be something besides NULL so that this isn't | |
537 | treated as a help class. */ | |
538 | c->func = empty_func; | |
539 | return c; | |
540 | } | |
541 | ||
542 | /* Add element named NAME to both command lists SET_LIST and SHOW_LIST. | |
543 | THECLASS is as in add_cmd. VAR_TYPE is the kind of thing we are | |
544 | setting. EXTRA_LITERALS if non-NULL define extra literals to be | |
545 | accepted in lieu of a number for integer variables. ARGS is a | |
546 | pre-validated type-erased reference to the variable being controlled | |
547 | by this command. SET_FUNC and SHOW_FUNC are the callback functions | |
548 | (if non-NULL). SET_DOC, SHOW_DOC and HELP_DOC are the documentation | |
549 | strings. | |
550 | ||
551 | Return the newly created set and show commands. */ | |
552 | ||
553 | static set_show_commands | |
554 | add_setshow_cmd_full_erased (const char *name, | |
555 | enum command_class theclass, | |
556 | var_types var_type, | |
557 | const literal_def *extra_literals, | |
558 | const setting::erased_args &args, | |
559 | const char *set_doc, const char *show_doc, | |
560 | const char *help_doc, | |
561 | cmd_func_ftype *set_func, | |
562 | show_value_ftype *show_func, | |
563 | struct cmd_list_element **set_list, | |
564 | struct cmd_list_element **show_list) | |
565 | { | |
566 | struct cmd_list_element *set; | |
567 | struct cmd_list_element *show; | |
568 | gdb::unique_xmalloc_ptr<char> full_set_doc; | |
569 | gdb::unique_xmalloc_ptr<char> full_show_doc; | |
570 | ||
571 | if (help_doc != NULL) | |
572 | { | |
573 | full_set_doc = xstrprintf ("%s\n%s", set_doc, help_doc); | |
574 | full_show_doc = xstrprintf ("%s\n%s", show_doc, help_doc); | |
575 | } | |
576 | else | |
577 | { | |
578 | full_set_doc = make_unique_xstrdup (set_doc); | |
579 | full_show_doc = make_unique_xstrdup (show_doc); | |
580 | } | |
581 | set = add_set_or_show_cmd (name, set_cmd, theclass, var_type, | |
582 | extra_literals, args, | |
583 | full_set_doc.release (), set_list); | |
584 | set->doc_allocated = 1; | |
585 | ||
586 | if (set_func != NULL) | |
587 | set->func = set_func; | |
588 | ||
589 | show = add_set_or_show_cmd (name, show_cmd, theclass, var_type, | |
590 | extra_literals, args, | |
591 | full_show_doc.release (), show_list); | |
592 | show->doc_allocated = 1; | |
593 | show->show_value_func = show_func; | |
594 | /* Disable the default symbol completer. Doesn't make much sense | |
595 | for the "show" command to complete on anything. */ | |
596 | set_cmd_completer (show, nullptr); | |
597 | ||
598 | return {set, show}; | |
599 | } | |
600 | ||
601 | /* Completes on integer commands that support extra literals. */ | |
602 | ||
603 | static void | |
604 | integer_literals_completer (struct cmd_list_element *c, | |
605 | completion_tracker &tracker, | |
606 | const char *text, const char *word) | |
607 | { | |
608 | const literal_def *extra_literals = c->var->extra_literals (); | |
609 | ||
610 | if (*text == '\0') | |
611 | { | |
612 | tracker.add_completion (make_unique_xstrdup ("NUMBER")); | |
613 | for (const literal_def *l = extra_literals; | |
614 | l->literal != nullptr; | |
615 | l++) | |
616 | tracker.add_completion (make_unique_xstrdup (l->literal)); | |
617 | } | |
618 | else | |
619 | for (const literal_def *l = extra_literals; | |
620 | l->literal != nullptr; | |
621 | l++) | |
622 | if (startswith (l->literal, text)) | |
623 | tracker.add_completion (make_unique_xstrdup (l->literal)); | |
624 | } | |
625 | ||
626 | /* Add element named NAME to both command lists SET_LIST and SHOW_LIST. | |
627 | THECLASS is as in add_cmd. VAR_TYPE is the kind of thing we are | |
628 | setting. VAR is address of the variable being controlled by this | |
629 | command. EXTRA_LITERALS if non-NULL define extra literals to be | |
630 | accepted in lieu of a number for integer variables. If nullptr is | |
631 | given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must | |
632 | be provided. SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks | |
633 | used to access and modify the underlying property, whatever its | |
634 | storage is. SET_FUNC and SHOW_FUNC are the callback functions | |
635 | (if non-NULL). SET_DOC, SHOW_DOC and HELP_DOC are the | |
636 | documentation strings. | |
637 | ||
638 | Return the newly created set and show commands. */ | |
639 | ||
640 | template<typename T> | |
641 | static set_show_commands | |
642 | add_setshow_cmd_full (const char *name, | |
643 | enum command_class theclass, | |
644 | var_types var_type, T *var, | |
645 | const literal_def *extra_literals, | |
646 | const char *set_doc, const char *show_doc, | |
647 | const char *help_doc, | |
648 | typename setting_func_types<T>::set set_setting_func, | |
649 | typename setting_func_types<T>::get get_setting_func, | |
650 | cmd_func_ftype *set_func, | |
651 | show_value_ftype *show_func, | |
652 | struct cmd_list_element **set_list, | |
653 | struct cmd_list_element **show_list) | |
654 | { | |
655 | auto erased_args | |
656 | = setting::erase_args (var_type, var, | |
657 | set_setting_func, get_setting_func); | |
658 | auto cmds = add_setshow_cmd_full_erased (name, | |
659 | theclass, | |
660 | var_type, extra_literals, | |
661 | erased_args, | |
662 | set_doc, show_doc, | |
663 | help_doc, | |
664 | set_func, | |
665 | show_func, | |
666 | set_list, | |
667 | show_list); | |
668 | ||
669 | if (extra_literals != nullptr) | |
670 | set_cmd_completer (cmds.set, integer_literals_completer); | |
671 | ||
672 | return cmds; | |
673 | } | |
674 | ||
675 | /* Same as above but omitting EXTRA_LITERALS. */ | |
676 | ||
677 | template<typename T> | |
678 | static set_show_commands | |
679 | add_setshow_cmd_full (const char *name, | |
680 | enum command_class theclass, | |
681 | var_types var_type, T *var, | |
682 | const char *set_doc, const char *show_doc, | |
683 | const char *help_doc, | |
684 | typename setting_func_types<T>::set set_setting_func, | |
685 | typename setting_func_types<T>::get get_setting_func, | |
686 | cmd_func_ftype *set_func, | |
687 | show_value_ftype *show_func, | |
688 | struct cmd_list_element **set_list, | |
689 | struct cmd_list_element **show_list) | |
690 | { | |
691 | return add_setshow_cmd_full (name, theclass, var_type, var, nullptr, | |
692 | set_doc, show_doc, help_doc, | |
693 | set_setting_func, get_setting_func, | |
694 | set_func, show_func, set_list, show_list); | |
695 | } | |
696 | ||
697 | /* Add element named NAME to command list LIST (the list for set or | |
698 | some sublist thereof). THECLASS is as in add_cmd. ENUMLIST is a list | |
699 | of strings which may follow NAME. VAR is address of the variable | |
700 | which will contain the matching string (from ENUMLIST). */ | |
701 | ||
702 | set_show_commands | |
703 | add_setshow_enum_cmd (const char *name, | |
704 | enum command_class theclass, | |
705 | const char *const *enumlist, | |
706 | const char **var, | |
707 | const char *set_doc, | |
708 | const char *show_doc, | |
709 | const char *help_doc, | |
710 | cmd_func_ftype *set_func, | |
711 | show_value_ftype *show_func, | |
712 | struct cmd_list_element **set_list, | |
713 | struct cmd_list_element **show_list) | |
714 | { | |
715 | /* We require *VAR to be initialized before this call, and | |
716 | furthermore it must be == to one of the values in ENUMLIST. */ | |
717 | gdb_assert (var != nullptr && *var != nullptr); | |
718 | for (int i = 0; ; ++i) | |
719 | { | |
720 | gdb_assert (enumlist[i] != nullptr); | |
721 | if (*var == enumlist[i]) | |
722 | break; | |
723 | } | |
724 | ||
725 | set_show_commands commands | |
726 | = add_setshow_cmd_full<const char *> (name, theclass, var_enum, var, | |
727 | set_doc, show_doc, help_doc, | |
728 | nullptr, nullptr, set_func, | |
729 | show_func, set_list, show_list); | |
730 | commands.set->enums = enumlist; | |
731 | return commands; | |
732 | } | |
733 | ||
734 | /* Same as above but using a getter and a setter function instead of a pointer | |
735 | to a global storage buffer. */ | |
736 | ||
737 | set_show_commands | |
738 | add_setshow_enum_cmd (const char *name, command_class theclass, | |
739 | const char *const *enumlist, const char *set_doc, | |
740 | const char *show_doc, const char *help_doc, | |
741 | setting_func_types<const char *>::set set_func, | |
742 | setting_func_types<const char *>::get get_func, | |
743 | show_value_ftype *show_func, | |
744 | cmd_list_element **set_list, | |
745 | cmd_list_element **show_list) | |
746 | { | |
747 | auto cmds = add_setshow_cmd_full<const char *> (name, theclass, var_enum, | |
748 | nullptr, set_doc, show_doc, | |
749 | help_doc, set_func, get_func, | |
750 | nullptr, show_func, set_list, | |
751 | show_list); | |
752 | ||
753 | cmds.set->enums = enumlist; | |
754 | ||
755 | return cmds; | |
756 | } | |
757 | ||
758 | /* See cli-decode.h. */ | |
759 | ||
760 | void | |
761 | complete_on_color (completion_tracker &tracker, | |
762 | const char *text, const char *word) | |
763 | { | |
764 | complete_on_enum (tracker, ui_file_style::basic_color_enums.data (), | |
765 | text, word); | |
766 | if (*text == '\0') | |
767 | { | |
768 | /* Convenience to let the user know what the option | |
769 | can accept. Note there's no common prefix between | |
770 | the strings on purpose, so that complete_on_enum doesn't do | |
771 | a partial match. */ | |
772 | tracker.add_completion (make_unique_xstrdup ("NUMBER")); | |
773 | tracker.add_completion (make_unique_xstrdup ("#RRGGBB")); | |
774 | } | |
775 | } | |
776 | ||
777 | /* Completer used in color commands. */ | |
778 | ||
779 | static void | |
780 | color_completer (struct cmd_list_element *ignore, | |
781 | completion_tracker &tracker, | |
782 | const char *text, const char *word) | |
783 | { | |
784 | complete_on_color (tracker, text, word); | |
785 | } | |
786 | ||
787 | ||
788 | /* Add element named NAME to command list LIST (the list for set or | |
789 | some sublist thereof). CLASS is as in add_cmd. VAR is address | |
790 | of the variable which will contain the color. */ | |
791 | ||
792 | set_show_commands | |
793 | add_setshow_color_cmd (const char *name, | |
794 | enum command_class theclass, | |
795 | ui_file_style::color *var, | |
796 | const char *set_doc, | |
797 | const char *show_doc, | |
798 | const char *help_doc, | |
799 | cmd_func_ftype *set_func, | |
800 | show_value_ftype *show_func, | |
801 | struct cmd_list_element **set_list, | |
802 | struct cmd_list_element **show_list) | |
803 | { | |
804 | set_show_commands commands = add_setshow_cmd_full<ui_file_style::color> | |
805 | (name, theclass, var_color, var, | |
806 | set_doc, show_doc, help_doc, | |
807 | nullptr, nullptr, set_func, show_func, | |
808 | set_list, show_list); | |
809 | ||
810 | set_cmd_completer (commands.set, color_completer); | |
811 | ||
812 | return commands; | |
813 | } | |
814 | ||
815 | /* Same as above but using a getter and a setter function instead of a pointer | |
816 | to a global storage buffer. */ | |
817 | ||
818 | set_show_commands | |
819 | add_setshow_color_cmd (const char *name, command_class theclass, | |
820 | const char *set_doc, const char *show_doc, | |
821 | const char *help_doc, | |
822 | setting_func_types<ui_file_style::color>::set set_func, | |
823 | setting_func_types<ui_file_style::color>::get get_func, | |
824 | show_value_ftype *show_func, | |
825 | cmd_list_element **set_list, | |
826 | cmd_list_element **show_list) | |
827 | { | |
828 | auto cmds = add_setshow_cmd_full<ui_file_style::color> | |
829 | (name, theclass, var_color, nullptr, | |
830 | set_doc, show_doc, help_doc, | |
831 | set_func, get_func, nullptr, show_func, | |
832 | set_list, show_list); | |
833 | ||
834 | set_cmd_completer (cmds.set, color_completer); | |
835 | ||
836 | return cmds; | |
837 | } | |
838 | ||
839 | /* See cli-decode.h. */ | |
840 | const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; | |
841 | ||
842 | /* Add an auto-boolean command named NAME to both the set and show | |
843 | command list lists. THECLASS is as in add_cmd. VAR is address of the | |
844 | variable which will contain the value. DOC is the documentation | |
845 | string. FUNC is the corresponding callback. */ | |
846 | ||
847 | set_show_commands | |
848 | add_setshow_auto_boolean_cmd (const char *name, | |
849 | enum command_class theclass, | |
850 | enum auto_boolean *var, | |
851 | const char *set_doc, const char *show_doc, | |
852 | const char *help_doc, | |
853 | cmd_func_ftype *set_func, | |
854 | show_value_ftype *show_func, | |
855 | struct cmd_list_element **set_list, | |
856 | struct cmd_list_element **show_list) | |
857 | { | |
858 | set_show_commands commands | |
859 | = add_setshow_cmd_full<enum auto_boolean> (name, theclass, var_auto_boolean, | |
860 | var, set_doc, show_doc, help_doc, | |
861 | nullptr, nullptr, set_func, | |
862 | show_func, set_list, show_list); | |
863 | ||
864 | commands.set->enums = auto_boolean_enums; | |
865 | ||
866 | return commands; | |
867 | } | |
868 | ||
869 | /* Same as above but using a getter and a setter function instead of a pointer | |
870 | to a global storage buffer. */ | |
871 | ||
872 | set_show_commands | |
873 | add_setshow_auto_boolean_cmd (const char *name, command_class theclass, | |
874 | const char *set_doc, const char *show_doc, | |
875 | const char *help_doc, | |
876 | setting_func_types<enum auto_boolean>::set set_func, | |
877 | setting_func_types<enum auto_boolean>::get get_func, | |
878 | show_value_ftype *show_func, | |
879 | cmd_list_element **set_list, | |
880 | cmd_list_element **show_list) | |
881 | { | |
882 | auto cmds = add_setshow_cmd_full<enum auto_boolean> (name, theclass, | |
883 | var_auto_boolean, | |
884 | nullptr, set_doc, | |
885 | show_doc, help_doc, | |
886 | set_func, get_func, | |
887 | nullptr, show_func, | |
888 | set_list, show_list); | |
889 | ||
890 | cmds.set->enums = auto_boolean_enums; | |
891 | ||
892 | return cmds; | |
893 | } | |
894 | ||
895 | /* See cli-decode.h. */ | |
896 | const char * const boolean_enums[] = { "on", "off", NULL }; | |
897 | ||
898 | /* Add element named NAME to both the set and show command LISTs (the | |
899 | list for set/show or some sublist thereof). THECLASS is as in | |
900 | add_cmd. VAR is address of the variable which will contain the | |
901 | value. SET_DOC and SHOW_DOC are the documentation strings. | |
902 | Returns the new command element. */ | |
903 | ||
904 | set_show_commands | |
905 | add_setshow_boolean_cmd (const char *name, enum command_class theclass, bool *var, | |
906 | const char *set_doc, const char *show_doc, | |
907 | const char *help_doc, | |
908 | cmd_func_ftype *set_func, | |
909 | show_value_ftype *show_func, | |
910 | struct cmd_list_element **set_list, | |
911 | struct cmd_list_element **show_list) | |
912 | { | |
913 | set_show_commands commands | |
914 | = add_setshow_cmd_full<bool> (name, theclass, var_boolean, var, | |
915 | set_doc, show_doc, help_doc, | |
916 | nullptr, nullptr, set_func, show_func, | |
917 | set_list, show_list); | |
918 | ||
919 | commands.set->enums = boolean_enums; | |
920 | ||
921 | return commands; | |
922 | } | |
923 | ||
924 | /* Same as above but using a getter and a setter function instead of a pointer | |
925 | to a global storage buffer. */ | |
926 | ||
927 | set_show_commands | |
928 | add_setshow_boolean_cmd (const char *name, command_class theclass, | |
929 | const char *set_doc, const char *show_doc, | |
930 | const char *help_doc, | |
931 | setting_func_types<bool>::set set_func, | |
932 | setting_func_types<bool>::get get_func, | |
933 | show_value_ftype *show_func, | |
934 | cmd_list_element **set_list, | |
935 | cmd_list_element **show_list) | |
936 | { | |
937 | auto cmds = add_setshow_cmd_full<bool> (name, theclass, var_boolean, nullptr, | |
938 | set_doc, show_doc, help_doc, | |
939 | set_func, get_func, nullptr, | |
940 | show_func, set_list, show_list); | |
941 | ||
942 | cmds.set->enums = boolean_enums; | |
943 | ||
944 | return cmds; | |
945 | } | |
946 | ||
947 | /* Add element named NAME to both the set and show command LISTs (the | |
948 | list for set/show or some sublist thereof). */ | |
949 | ||
950 | set_show_commands | |
951 | add_setshow_filename_cmd (const char *name, enum command_class theclass, | |
952 | std::string *var, | |
953 | const char *set_doc, const char *show_doc, | |
954 | const char *help_doc, | |
955 | cmd_func_ftype *set_func, | |
956 | show_value_ftype *show_func, | |
957 | struct cmd_list_element **set_list, | |
958 | struct cmd_list_element **show_list) | |
959 | { | |
960 | set_show_commands commands | |
961 | = add_setshow_cmd_full<std::string> (name, theclass, var_filename, var, | |
962 | set_doc, show_doc, help_doc, | |
963 | nullptr, nullptr, set_func, | |
964 | show_func, set_list, show_list); | |
965 | ||
966 | set_cmd_completer (commands.set, deprecated_filename_completer); | |
967 | ||
968 | return commands; | |
969 | } | |
970 | ||
971 | /* Same as above but using a getter and a setter function instead of a pointer | |
972 | to a global storage buffer. */ | |
973 | ||
974 | set_show_commands | |
975 | add_setshow_filename_cmd (const char *name, command_class theclass, | |
976 | const char *set_doc, const char *show_doc, | |
977 | const char *help_doc, | |
978 | setting_func_types<std::string>::set set_func, | |
979 | setting_func_types<std::string>::get get_func, | |
980 | show_value_ftype *show_func, | |
981 | cmd_list_element **set_list, | |
982 | cmd_list_element **show_list) | |
983 | { | |
984 | auto cmds = add_setshow_cmd_full<std::string> (name, theclass, var_filename, | |
985 | nullptr, set_doc, show_doc, | |
986 | help_doc, set_func, get_func, | |
987 | nullptr, show_func, set_list, | |
988 | show_list); | |
989 | ||
990 | set_cmd_completer (cmds.set, deprecated_filename_completer); | |
991 | ||
992 | return cmds; | |
993 | } | |
994 | ||
995 | /* Add element named NAME to both the set and show command LISTs (the | |
996 | list for set/show or some sublist thereof). */ | |
997 | ||
998 | set_show_commands | |
999 | add_setshow_string_cmd (const char *name, enum command_class theclass, | |
1000 | std::string *var, | |
1001 | const char *set_doc, const char *show_doc, | |
1002 | const char *help_doc, | |
1003 | cmd_func_ftype *set_func, | |
1004 | show_value_ftype *show_func, | |
1005 | struct cmd_list_element **set_list, | |
1006 | struct cmd_list_element **show_list) | |
1007 | { | |
1008 | set_show_commands commands | |
1009 | = add_setshow_cmd_full<std::string> (name, theclass, var_string, var, | |
1010 | set_doc, show_doc, help_doc, | |
1011 | nullptr, nullptr, set_func, | |
1012 | show_func, set_list, show_list); | |
1013 | ||
1014 | /* Disable the default symbol completer. */ | |
1015 | set_cmd_completer (commands.set, nullptr); | |
1016 | ||
1017 | return commands; | |
1018 | } | |
1019 | ||
1020 | /* Same as above but using a getter and a setter function instead of a pointer | |
1021 | to a global storage buffer. */ | |
1022 | ||
1023 | set_show_commands | |
1024 | add_setshow_string_cmd (const char *name, command_class theclass, | |
1025 | const char *set_doc, const char *show_doc, | |
1026 | const char *help_doc, | |
1027 | setting_func_types<std::string>::set set_func, | |
1028 | setting_func_types<std::string>::get get_func, | |
1029 | show_value_ftype *show_func, | |
1030 | cmd_list_element **set_list, | |
1031 | cmd_list_element **show_list) | |
1032 | { | |
1033 | auto cmds = add_setshow_cmd_full<std::string> (name, theclass, var_string, | |
1034 | nullptr, set_doc, show_doc, | |
1035 | help_doc, set_func, get_func, | |
1036 | nullptr, show_func, set_list, | |
1037 | show_list); | |
1038 | ||
1039 | /* Disable the default symbol completer. */ | |
1040 | set_cmd_completer (cmds.set, nullptr); | |
1041 | ||
1042 | return cmds; | |
1043 | } | |
1044 | ||
1045 | /* Add element named NAME to both the set and show command LISTs (the | |
1046 | list for set/show or some sublist thereof). */ | |
1047 | ||
1048 | set_show_commands | |
1049 | add_setshow_string_noescape_cmd (const char *name, enum command_class theclass, | |
1050 | std::string *var, | |
1051 | const char *set_doc, const char *show_doc, | |
1052 | const char *help_doc, | |
1053 | cmd_func_ftype *set_func, | |
1054 | show_value_ftype *show_func, | |
1055 | struct cmd_list_element **set_list, | |
1056 | struct cmd_list_element **show_list) | |
1057 | { | |
1058 | set_show_commands commands | |
1059 | = add_setshow_cmd_full<std::string> (name, theclass, var_string_noescape, | |
1060 | var, set_doc, show_doc, help_doc, | |
1061 | nullptr, nullptr, set_func, show_func, | |
1062 | set_list, show_list); | |
1063 | ||
1064 | /* Disable the default symbol completer. */ | |
1065 | set_cmd_completer (commands.set, nullptr); | |
1066 | ||
1067 | return commands; | |
1068 | } | |
1069 | ||
1070 | /* Same as above but using a getter and a setter function instead of a pointer | |
1071 | to a global storage buffer. */ | |
1072 | ||
1073 | set_show_commands | |
1074 | add_setshow_string_noescape_cmd (const char *name, command_class theclass, | |
1075 | const char *set_doc, const char *show_doc, | |
1076 | const char *help_doc, | |
1077 | setting_func_types<std::string>::set set_func, | |
1078 | setting_func_types<std::string>::get get_func, | |
1079 | show_value_ftype *show_func, | |
1080 | cmd_list_element **set_list, | |
1081 | cmd_list_element **show_list) | |
1082 | { | |
1083 | auto cmds = add_setshow_cmd_full<std::string> (name, theclass, | |
1084 | var_string_noescape, nullptr, | |
1085 | set_doc, show_doc, help_doc, | |
1086 | set_func, get_func, | |
1087 | nullptr, show_func, set_list, | |
1088 | show_list); | |
1089 | ||
1090 | /* Disable the default symbol completer. */ | |
1091 | set_cmd_completer (cmds.set, nullptr); | |
1092 | ||
1093 | return cmds; | |
1094 | } | |
1095 | ||
1096 | /* Add element named NAME to both the set and show command LISTs (the | |
1097 | list for set/show or some sublist thereof). */ | |
1098 | ||
1099 | set_show_commands | |
1100 | add_setshow_optional_filename_cmd (const char *name, enum command_class theclass, | |
1101 | std::string *var, | |
1102 | const char *set_doc, const char *show_doc, | |
1103 | const char *help_doc, | |
1104 | cmd_func_ftype *set_func, | |
1105 | show_value_ftype *show_func, | |
1106 | struct cmd_list_element **set_list, | |
1107 | struct cmd_list_element **show_list) | |
1108 | { | |
1109 | set_show_commands commands | |
1110 | = add_setshow_cmd_full<std::string> (name, theclass, var_optional_filename, | |
1111 | var, set_doc, show_doc, help_doc, | |
1112 | nullptr, nullptr, set_func, show_func, | |
1113 | set_list, show_list); | |
1114 | ||
1115 | set_cmd_completer (commands.set, deprecated_filename_completer); | |
1116 | ||
1117 | return commands; | |
1118 | } | |
1119 | ||
1120 | /* Same as above but using a getter and a setter function instead of a pointer | |
1121 | to a global storage buffer. */ | |
1122 | ||
1123 | set_show_commands | |
1124 | add_setshow_optional_filename_cmd (const char *name, command_class theclass, | |
1125 | const char *set_doc, const char *show_doc, | |
1126 | const char *help_doc, | |
1127 | setting_func_types<std::string>::set set_func, | |
1128 | setting_func_types<std::string>::get get_func, | |
1129 | show_value_ftype *show_func, | |
1130 | cmd_list_element **set_list, | |
1131 | cmd_list_element **show_list) | |
1132 | { | |
1133 | auto cmds = | |
1134 | add_setshow_cmd_full<std::string> (name, theclass, var_optional_filename, | |
1135 | nullptr, set_doc, show_doc, help_doc, | |
1136 | set_func, get_func, nullptr, show_func, | |
1137 | set_list,show_list); | |
1138 | ||
1139 | set_cmd_completer (cmds.set, deprecated_filename_completer); | |
1140 | ||
1141 | return cmds; | |
1142 | } | |
1143 | ||
1144 | /* Add element named NAME to both the set and show command LISTs (the | |
1145 | list for set/show or some sublist thereof). THECLASS is as in | |
1146 | add_cmd. VAR is address of the variable which will contain the | |
1147 | value. SET_DOC and SHOW_DOC are the documentation strings. This | |
1148 | function is only used in Python API. Please don't use it elsewhere. */ | |
1149 | ||
1150 | set_show_commands | |
1151 | add_setshow_integer_cmd (const char *name, enum command_class theclass, | |
1152 | int *var, const literal_def *extra_literals, | |
1153 | const char *set_doc, const char *show_doc, | |
1154 | const char *help_doc, | |
1155 | cmd_func_ftype *set_func, | |
1156 | show_value_ftype *show_func, | |
1157 | struct cmd_list_element **set_list, | |
1158 | struct cmd_list_element **show_list) | |
1159 | { | |
1160 | set_show_commands commands | |
1161 | = add_setshow_cmd_full<int> (name, theclass, var_integer, var, | |
1162 | extra_literals, set_doc, show_doc, | |
1163 | help_doc, nullptr, nullptr, set_func, | |
1164 | show_func, set_list, show_list); | |
1165 | return commands; | |
1166 | } | |
1167 | ||
1168 | /* Same as above but using a getter and a setter function instead of a pointer | |
1169 | to a global storage buffer. */ | |
1170 | ||
1171 | set_show_commands | |
1172 | add_setshow_integer_cmd (const char *name, command_class theclass, | |
1173 | const literal_def *extra_literals, | |
1174 | const char *set_doc, const char *show_doc, | |
1175 | const char *help_doc, | |
1176 | setting_func_types<int>::set set_func, | |
1177 | setting_func_types<int>::get get_func, | |
1178 | show_value_ftype *show_func, | |
1179 | cmd_list_element **set_list, | |
1180 | cmd_list_element **show_list) | |
1181 | { | |
1182 | auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, | |
1183 | extra_literals, set_doc, show_doc, | |
1184 | help_doc, set_func, get_func, nullptr, | |
1185 | show_func, set_list, show_list); | |
1186 | return cmds; | |
1187 | } | |
1188 | ||
1189 | /* Accept `unlimited' or 0, translated internally to INT_MAX. */ | |
1190 | const literal_def integer_unlimited_literals[] = | |
1191 | { | |
1192 | { "unlimited", INT_MAX, 0 }, | |
1193 | { nullptr } | |
1194 | }; | |
1195 | ||
1196 | /* Same as above but using `integer_unlimited_literals', with a pointer | |
1197 | to a global storage buffer. */ | |
1198 | ||
1199 | set_show_commands | |
1200 | add_setshow_integer_cmd (const char *name, enum command_class theclass, | |
1201 | int *var, | |
1202 | const char *set_doc, const char *show_doc, | |
1203 | const char *help_doc, | |
1204 | cmd_func_ftype *set_func, | |
1205 | show_value_ftype *show_func, | |
1206 | struct cmd_list_element **set_list, | |
1207 | struct cmd_list_element **show_list) | |
1208 | { | |
1209 | set_show_commands commands | |
1210 | = add_setshow_cmd_full<int> (name, theclass, var_integer, var, | |
1211 | integer_unlimited_literals, | |
1212 | set_doc, show_doc, help_doc, | |
1213 | nullptr, nullptr, set_func, | |
1214 | show_func, set_list, show_list); | |
1215 | return commands; | |
1216 | } | |
1217 | ||
1218 | /* Same as above but using a getter and a setter function instead of a pointer | |
1219 | to a global storage buffer. */ | |
1220 | ||
1221 | set_show_commands | |
1222 | add_setshow_integer_cmd (const char *name, command_class theclass, | |
1223 | const char *set_doc, const char *show_doc, | |
1224 | const char *help_doc, | |
1225 | setting_func_types<int>::set set_func, | |
1226 | setting_func_types<int>::get get_func, | |
1227 | show_value_ftype *show_func, | |
1228 | cmd_list_element **set_list, | |
1229 | cmd_list_element **show_list) | |
1230 | { | |
1231 | auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, | |
1232 | integer_unlimited_literals, | |
1233 | set_doc, show_doc, help_doc, set_func, | |
1234 | get_func, nullptr, show_func, set_list, | |
1235 | show_list); | |
1236 | return cmds; | |
1237 | } | |
1238 | ||
1239 | /* Add element named NAME to both the set and show command LISTs (the | |
1240 | list for set/show or some sublist thereof). CLASS is as in | |
1241 | add_cmd. VAR is address of the variable which will contain the | |
1242 | value. SET_DOC and SHOW_DOC are the documentation strings. */ | |
1243 | ||
1244 | set_show_commands | |
1245 | add_setshow_pinteger_cmd (const char *name, enum command_class theclass, | |
1246 | int *var, const literal_def *extra_literals, | |
1247 | const char *set_doc, const char *show_doc, | |
1248 | const char *help_doc, | |
1249 | cmd_func_ftype *set_func, | |
1250 | show_value_ftype *show_func, | |
1251 | struct cmd_list_element **set_list, | |
1252 | struct cmd_list_element **show_list) | |
1253 | { | |
1254 | set_show_commands commands | |
1255 | = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var, | |
1256 | extra_literals, set_doc, show_doc, | |
1257 | help_doc, nullptr, nullptr, set_func, | |
1258 | show_func, set_list, show_list); | |
1259 | return commands; | |
1260 | } | |
1261 | ||
1262 | /* Same as above but using a getter and a setter function instead of a pointer | |
1263 | to a global storage buffer. */ | |
1264 | ||
1265 | set_show_commands | |
1266 | add_setshow_pinteger_cmd (const char *name, command_class theclass, | |
1267 | const literal_def *extra_literals, | |
1268 | const char *set_doc, const char *show_doc, | |
1269 | const char *help_doc, | |
1270 | setting_func_types<int>::set set_func, | |
1271 | setting_func_types<int>::get get_func, | |
1272 | show_value_ftype *show_func, | |
1273 | cmd_list_element **set_list, | |
1274 | cmd_list_element **show_list) | |
1275 | { | |
1276 | auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr, | |
1277 | extra_literals, set_doc, show_doc, | |
1278 | help_doc, set_func, get_func, nullptr, | |
1279 | show_func, set_list, show_list); | |
1280 | return cmds; | |
1281 | } | |
1282 | ||
1283 | /* Add element named NAME to both the set and show command LISTs (the | |
1284 | list for set/show or some sublist thereof). THECLASS is as in | |
1285 | add_cmd. VAR is address of the variable which will contain the | |
1286 | value. SET_DOC and SHOW_DOC are the documentation strings. */ | |
1287 | ||
1288 | set_show_commands | |
1289 | add_setshow_uinteger_cmd (const char *name, enum command_class theclass, | |
1290 | unsigned int *var, const literal_def *extra_literals, | |
1291 | const char *set_doc, const char *show_doc, | |
1292 | const char *help_doc, | |
1293 | cmd_func_ftype *set_func, | |
1294 | show_value_ftype *show_func, | |
1295 | struct cmd_list_element **set_list, | |
1296 | struct cmd_list_element **show_list) | |
1297 | { | |
1298 | set_show_commands commands | |
1299 | = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var, | |
1300 | extra_literals, set_doc, show_doc, | |
1301 | help_doc, nullptr, nullptr, set_func, | |
1302 | show_func, set_list, show_list); | |
1303 | return commands; | |
1304 | } | |
1305 | ||
1306 | /* Same as above but using a getter and a setter function instead of a pointer | |
1307 | to a global storage buffer. */ | |
1308 | ||
1309 | set_show_commands | |
1310 | add_setshow_uinteger_cmd (const char *name, command_class theclass, | |
1311 | const literal_def *extra_literals, | |
1312 | const char *set_doc, const char *show_doc, | |
1313 | const char *help_doc, | |
1314 | setting_func_types<unsigned int>::set set_func, | |
1315 | setting_func_types<unsigned int>::get get_func, | |
1316 | show_value_ftype *show_func, | |
1317 | cmd_list_element **set_list, | |
1318 | cmd_list_element **show_list) | |
1319 | { | |
1320 | auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | |
1321 | nullptr, extra_literals, | |
1322 | set_doc, show_doc, help_doc, | |
1323 | set_func, get_func, nullptr, | |
1324 | show_func, set_list, | |
1325 | show_list); | |
1326 | return cmds; | |
1327 | } | |
1328 | ||
1329 | /* Accept `unlimited' or 0, translated internally to UINT_MAX. */ | |
1330 | const literal_def uinteger_unlimited_literals[] = | |
1331 | { | |
1332 | { "unlimited", UINT_MAX, 0 }, | |
1333 | { nullptr } | |
1334 | }; | |
1335 | ||
1336 | /* Same as above but using `uinteger_unlimited_literals', with a pointer | |
1337 | to a global storage buffer. */ | |
1338 | ||
1339 | set_show_commands | |
1340 | add_setshow_uinteger_cmd (const char *name, enum command_class theclass, | |
1341 | unsigned int *var, | |
1342 | const char *set_doc, const char *show_doc, | |
1343 | const char *help_doc, | |
1344 | cmd_func_ftype *set_func, | |
1345 | show_value_ftype *show_func, | |
1346 | struct cmd_list_element **set_list, | |
1347 | struct cmd_list_element **show_list) | |
1348 | { | |
1349 | set_show_commands commands | |
1350 | = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var, | |
1351 | uinteger_unlimited_literals, | |
1352 | set_doc, show_doc, help_doc, nullptr, | |
1353 | nullptr, set_func, show_func, | |
1354 | set_list, show_list); | |
1355 | return commands; | |
1356 | } | |
1357 | ||
1358 | /* Same as above but using a getter and a setter function instead of a pointer | |
1359 | to a global storage buffer. */ | |
1360 | ||
1361 | set_show_commands | |
1362 | add_setshow_uinteger_cmd (const char *name, command_class theclass, | |
1363 | const char *set_doc, const char *show_doc, | |
1364 | const char *help_doc, | |
1365 | setting_func_types<unsigned int>::set set_func, | |
1366 | setting_func_types<unsigned int>::get get_func, | |
1367 | show_value_ftype *show_func, | |
1368 | cmd_list_element **set_list, | |
1369 | cmd_list_element **show_list) | |
1370 | { | |
1371 | auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | |
1372 | nullptr, | |
1373 | uinteger_unlimited_literals, | |
1374 | set_doc, show_doc, help_doc, | |
1375 | set_func, get_func, nullptr, | |
1376 | show_func, set_list, | |
1377 | show_list); | |
1378 | return cmds; | |
1379 | } | |
1380 | ||
1381 | /* Add element named NAME to both the set and show command LISTs (the | |
1382 | list for set/show or some sublist thereof). THECLASS is as in | |
1383 | add_cmd. VAR is address of the variable which will contain the | |
1384 | value. SET_DOC and SHOW_DOC are the documentation strings. */ | |
1385 | ||
1386 | set_show_commands | |
1387 | add_setshow_zinteger_cmd (const char *name, enum command_class theclass, | |
1388 | int *var, | |
1389 | const char *set_doc, const char *show_doc, | |
1390 | const char *help_doc, | |
1391 | cmd_func_ftype *set_func, | |
1392 | show_value_ftype *show_func, | |
1393 | struct cmd_list_element **set_list, | |
1394 | struct cmd_list_element **show_list) | |
1395 | { | |
1396 | return add_setshow_cmd_full<int> (name, theclass, var_integer, var, | |
1397 | set_doc, show_doc, help_doc, | |
1398 | nullptr, nullptr, set_func, | |
1399 | show_func, set_list, show_list); | |
1400 | } | |
1401 | ||
1402 | /* Same as above but using a getter and a setter function instead of a pointer | |
1403 | to a global storage buffer. */ | |
1404 | ||
1405 | set_show_commands | |
1406 | add_setshow_zinteger_cmd (const char *name, command_class theclass, | |
1407 | const char *set_doc, const char *show_doc, | |
1408 | const char *help_doc, | |
1409 | setting_func_types<int>::set set_func, | |
1410 | setting_func_types<int>::get get_func, | |
1411 | show_value_ftype *show_func, | |
1412 | cmd_list_element **set_list, | |
1413 | cmd_list_element **show_list) | |
1414 | { | |
1415 | return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, | |
1416 | set_doc, show_doc, help_doc, set_func, | |
1417 | get_func, nullptr, show_func, set_list, | |
1418 | show_list); | |
1419 | } | |
1420 | ||
1421 | /* Accept `unlimited' or -1, using -1 internally. */ | |
1422 | const literal_def pinteger_unlimited_literals[] = | |
1423 | { | |
1424 | { "unlimited", -1, -1 }, | |
1425 | { nullptr } | |
1426 | }; | |
1427 | ||
1428 | /* Same as above but using `pinteger_unlimited_literals', with a pointer | |
1429 | to a global storage buffer. */ | |
1430 | ||
1431 | set_show_commands | |
1432 | add_setshow_zuinteger_unlimited_cmd (const char *name, | |
1433 | enum command_class theclass, | |
1434 | int *var, | |
1435 | const char *set_doc, | |
1436 | const char *show_doc, | |
1437 | const char *help_doc, | |
1438 | cmd_func_ftype *set_func, | |
1439 | show_value_ftype *show_func, | |
1440 | struct cmd_list_element **set_list, | |
1441 | struct cmd_list_element **show_list) | |
1442 | { | |
1443 | set_show_commands commands | |
1444 | = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var, | |
1445 | pinteger_unlimited_literals, | |
1446 | set_doc, show_doc, help_doc, nullptr, | |
1447 | nullptr, set_func, show_func, set_list, | |
1448 | show_list); | |
1449 | return commands; | |
1450 | } | |
1451 | ||
1452 | /* Same as above but using a getter and a setter function instead of a pointer | |
1453 | to a global storage buffer. */ | |
1454 | ||
1455 | set_show_commands | |
1456 | add_setshow_zuinteger_unlimited_cmd (const char *name, command_class theclass, | |
1457 | const char *set_doc, const char *show_doc, | |
1458 | const char *help_doc, | |
1459 | setting_func_types<int>::set set_func, | |
1460 | setting_func_types<int>::get get_func, | |
1461 | show_value_ftype *show_func, | |
1462 | cmd_list_element **set_list, | |
1463 | cmd_list_element **show_list) | |
1464 | { | |
1465 | auto cmds | |
1466 | = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr, | |
1467 | pinteger_unlimited_literals, | |
1468 | set_doc, show_doc, help_doc, set_func, | |
1469 | get_func, nullptr, show_func, set_list, | |
1470 | show_list); | |
1471 | return cmds; | |
1472 | } | |
1473 | ||
1474 | /* Add element named NAME to both the set and show command LISTs (the | |
1475 | list for set/show or some sublist thereof). THECLASS is as in | |
1476 | add_cmd. VAR is address of the variable which will contain the | |
1477 | value. SET_DOC and SHOW_DOC are the documentation strings. */ | |
1478 | ||
1479 | set_show_commands | |
1480 | add_setshow_zuinteger_cmd (const char *name, enum command_class theclass, | |
1481 | unsigned int *var, | |
1482 | const char *set_doc, const char *show_doc, | |
1483 | const char *help_doc, | |
1484 | cmd_func_ftype *set_func, | |
1485 | show_value_ftype *show_func, | |
1486 | struct cmd_list_element **set_list, | |
1487 | struct cmd_list_element **show_list) | |
1488 | { | |
1489 | return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | |
1490 | var, set_doc, show_doc, help_doc, | |
1491 | nullptr, nullptr, set_func, | |
1492 | show_func, set_list, show_list); | |
1493 | } | |
1494 | ||
1495 | /* Same as above but using a getter and a setter function instead of a pointer | |
1496 | to a global storage buffer. */ | |
1497 | ||
1498 | set_show_commands | |
1499 | add_setshow_zuinteger_cmd (const char *name, command_class theclass, | |
1500 | const char *set_doc, const char *show_doc, | |
1501 | const char *help_doc, | |
1502 | setting_func_types<unsigned int>::set set_func, | |
1503 | setting_func_types<unsigned int>::get get_func, | |
1504 | show_value_ftype *show_func, | |
1505 | cmd_list_element **set_list, | |
1506 | cmd_list_element **show_list) | |
1507 | { | |
1508 | return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | |
1509 | nullptr, set_doc, show_doc, | |
1510 | help_doc, set_func, get_func, | |
1511 | nullptr, show_func, set_list, | |
1512 | show_list); | |
1513 | } | |
1514 | ||
1515 | /* Remove the command named NAME from the command list. Return the list | |
1516 | commands which were aliased to the deleted command. The various *HOOKs are | |
1517 | set to the pre- and post-hook commands for the deleted command. If the | |
1518 | command does not have a hook, the corresponding out parameter is set to | |
1519 | NULL. */ | |
1520 | ||
1521 | static cmd_list_element::aliases_list_type | |
1522 | delete_cmd (const char *name, struct cmd_list_element **list, | |
1523 | struct cmd_list_element **prehook, | |
1524 | struct cmd_list_element **prehookee, | |
1525 | struct cmd_list_element **posthook, | |
1526 | struct cmd_list_element **posthookee) | |
1527 | { | |
1528 | struct cmd_list_element *iter; | |
1529 | struct cmd_list_element **previous_chain_ptr; | |
1530 | cmd_list_element::aliases_list_type aliases; | |
1531 | ||
1532 | *prehook = NULL; | |
1533 | *prehookee = NULL; | |
1534 | *posthook = NULL; | |
1535 | *posthookee = NULL; | |
1536 | previous_chain_ptr = list; | |
1537 | ||
1538 | for (iter = *previous_chain_ptr; iter; iter = *previous_chain_ptr) | |
1539 | { | |
1540 | if (strcmp (iter->name, name) == 0) | |
1541 | { | |
1542 | if (iter->destroyer) | |
1543 | iter->destroyer (iter, iter->context ()); | |
1544 | ||
1545 | if (iter->hookee_pre) | |
1546 | iter->hookee_pre->hook_pre = 0; | |
1547 | *prehook = iter->hook_pre; | |
1548 | *prehookee = iter->hookee_pre; | |
1549 | if (iter->hookee_post) | |
1550 | iter->hookee_post->hook_post = 0; | |
1551 | *posthook = iter->hook_post; | |
1552 | *posthookee = iter->hookee_post; | |
1553 | ||
1554 | /* Update the link. */ | |
1555 | *previous_chain_ptr = iter->next; | |
1556 | ||
1557 | aliases = std::move (iter->aliases); | |
1558 | ||
1559 | /* If this command was an alias, remove it from the list of | |
1560 | aliases. */ | |
1561 | if (iter->is_alias ()) | |
1562 | { | |
1563 | auto it = iter->alias_target->aliases.iterator_to (*iter); | |
1564 | iter->alias_target->aliases.erase (it); | |
1565 | } | |
1566 | ||
1567 | delete iter; | |
1568 | ||
1569 | /* We won't see another command with the same name. */ | |
1570 | break; | |
1571 | } | |
1572 | else | |
1573 | previous_chain_ptr = &iter->next; | |
1574 | } | |
1575 | ||
1576 | return aliases; | |
1577 | } | |
1578 | \f | |
1579 | /* Shorthands to the commands above. */ | |
1580 | ||
1581 | /* Add an element to the list of info subcommands. */ | |
1582 | ||
1583 | struct cmd_list_element * | |
1584 | add_info (const char *name, cmd_simple_func_ftype *fun, const char *doc) | |
1585 | { | |
1586 | return add_cmd (name, class_info, fun, doc, &infolist); | |
1587 | } | |
1588 | ||
1589 | /* Add an alias to the list of info subcommands. */ | |
1590 | ||
1591 | cmd_list_element * | |
1592 | add_info_alias (const char *name, cmd_list_element *target, int abbrev_flag) | |
1593 | { | |
1594 | return add_alias_cmd (name, target, class_run, abbrev_flag, &infolist); | |
1595 | } | |
1596 | ||
1597 | /* Add an element to the list of commands. */ | |
1598 | ||
1599 | struct cmd_list_element * | |
1600 | add_com (const char *name, enum command_class theclass, | |
1601 | cmd_simple_func_ftype *fun, | |
1602 | const char *doc) | |
1603 | { | |
1604 | return add_cmd (name, theclass, fun, doc, &cmdlist); | |
1605 | } | |
1606 | ||
1607 | /* Add an alias or abbreviation command to the list of commands. | |
1608 | For aliases predefined by GDB (such as bt), THECLASS must be | |
1609 | different of class_alias, as class_alias is used to identify | |
1610 | user defined aliases. */ | |
1611 | ||
1612 | cmd_list_element * | |
1613 | add_com_alias (const char *name, cmd_list_element *target, | |
1614 | command_class theclass, int abbrev_flag) | |
1615 | { | |
1616 | return add_alias_cmd (name, target, theclass, abbrev_flag, &cmdlist); | |
1617 | } | |
1618 | ||
1619 | /* Add an element with a suppress notification to the list of commands. */ | |
1620 | ||
1621 | struct cmd_list_element * | |
1622 | add_com_suppress_notification (const char *name, enum command_class theclass, | |
1623 | cmd_simple_func_ftype *fun, const char *doc, | |
1624 | bool *suppress_notification) | |
1625 | { | |
1626 | return add_cmd_suppress_notification (name, theclass, fun, doc, | |
1627 | &cmdlist, suppress_notification); | |
1628 | } | |
1629 | ||
1630 | /* Print the prefix of C followed by name of C in command style. */ | |
1631 | ||
1632 | static void | |
1633 | fput_command_name_styled (const cmd_list_element &c, struct ui_file *stream) | |
1634 | { | |
1635 | std::string prefixname | |
1636 | = c.prefix == nullptr ? "" : c.prefix->prefixname (); | |
1637 | ||
1638 | fprintf_styled (stream, command_style.style (), "%s%s", | |
1639 | prefixname.c_str (), c.name); | |
1640 | } | |
1641 | ||
1642 | /* True if ALIAS has a user-defined documentation. */ | |
1643 | ||
1644 | static bool | |
1645 | user_documented_alias (const cmd_list_element &alias) | |
1646 | { | |
1647 | gdb_assert (alias.is_alias ()); | |
1648 | /* Alias is user documented if it has an allocated documentation | |
1649 | that differs from the aliased command. */ | |
1650 | return (alias.doc_allocated | |
1651 | && strcmp (alias.doc, alias.alias_target->doc) != 0); | |
1652 | } | |
1653 | ||
1654 | /* Print the definition of alias C using title style for alias | |
1655 | and aliased command. */ | |
1656 | ||
1657 | static void | |
1658 | fput_alias_definition_styled (const cmd_list_element &c, | |
1659 | struct ui_file *stream) | |
1660 | { | |
1661 | gdb_assert (c.is_alias ()); | |
1662 | gdb_puts (" alias ", stream); | |
1663 | fput_command_name_styled (c, stream); | |
1664 | gdb_printf (stream, " = "); | |
1665 | fput_command_name_styled (*c.alias_target, stream); | |
1666 | gdb_printf (stream, " %s\n", c.default_args.c_str ()); | |
1667 | } | |
1668 | ||
1669 | /* Print the definition of CMD aliases not deprecated and having default args | |
1670 | and not specifically documented by the user. */ | |
1671 | ||
1672 | static void | |
1673 | fput_aliases_definition_styled (const cmd_list_element &cmd, | |
1674 | struct ui_file *stream) | |
1675 | { | |
1676 | for (const cmd_list_element &alias : cmd.aliases) | |
1677 | if (!alias.cmd_deprecated | |
1678 | && !user_documented_alias (alias) | |
1679 | && !alias.default_args.empty ()) | |
1680 | fput_alias_definition_styled (alias, stream); | |
1681 | } | |
1682 | ||
1683 | /* If C has one or more aliases, style print the name of C and the name of its | |
1684 | aliases not documented specifically by the user, separated by commas. | |
1685 | If ALWAYS_FPUT_C_NAME, print the name of C even if it has no aliases. | |
1686 | If one or more names are printed, POSTFIX is printed after the last name. | |
1687 | */ | |
1688 | ||
1689 | static void | |
1690 | fput_command_names_styled (const cmd_list_element &c, | |
1691 | bool always_fput_c_name, const char *postfix, | |
1692 | struct ui_file *stream) | |
1693 | { | |
1694 | /* First, check if we are going to print something. That is, either if | |
1695 | ALWAYS_FPUT_C_NAME is true or if there exists at least one non-deprecated | |
1696 | alias not documented specifically by the user. */ | |
1697 | ||
1698 | auto print_alias = [] (const cmd_list_element &alias) | |
1699 | { | |
1700 | return !alias.cmd_deprecated && !user_documented_alias (alias); | |
1701 | }; | |
1702 | ||
1703 | bool print_something = always_fput_c_name; | |
1704 | if (!print_something) | |
1705 | for (const cmd_list_element &alias : c.aliases) | |
1706 | { | |
1707 | if (!print_alias (alias)) | |
1708 | continue; | |
1709 | ||
1710 | print_something = true; | |
1711 | break; | |
1712 | } | |
1713 | ||
1714 | if (print_something) | |
1715 | fput_command_name_styled (c, stream); | |
1716 | ||
1717 | for (const cmd_list_element &alias : c.aliases) | |
1718 | { | |
1719 | if (!print_alias (alias)) | |
1720 | continue; | |
1721 | ||
1722 | gdb_puts (", ", stream); | |
1723 | stream->wrap_here (3); | |
1724 | fput_command_name_styled (alias, stream); | |
1725 | } | |
1726 | ||
1727 | if (print_something) | |
1728 | gdb_puts (postfix, stream); | |
1729 | } | |
1730 | ||
1731 | /* If VERBOSE, print the full help for command C and highlight the | |
1732 | documentation parts matching HIGHLIGHT, | |
1733 | otherwise print only one-line help for command C. */ | |
1734 | ||
1735 | static void | |
1736 | print_doc_of_command (const cmd_list_element &c, bool verbose, | |
1737 | compiled_regex &highlight, struct ui_file *stream) | |
1738 | { | |
1739 | /* When printing the full documentation, add a line to separate | |
1740 | this documentation from the previous command help, in the likely | |
1741 | case that apropos finds several commands. */ | |
1742 | if (verbose) | |
1743 | gdb_puts ("\n", stream); | |
1744 | ||
1745 | fput_command_names_styled (c, true, | |
1746 | verbose ? "" : " -- ", stream); | |
1747 | if (verbose) | |
1748 | { | |
1749 | gdb_puts ("\n", stream); | |
1750 | fput_aliases_definition_styled (c, stream); | |
1751 | fputs_highlighted (c.doc, highlight, stream); | |
1752 | gdb_puts ("\n", stream); | |
1753 | } | |
1754 | else | |
1755 | { | |
1756 | print_doc_line (stream, c.doc, false); | |
1757 | gdb_puts ("\n", stream); | |
1758 | fput_aliases_definition_styled (c, stream); | |
1759 | } | |
1760 | } | |
1761 | ||
1762 | /* Recursively walk the commandlist structures, and print out the | |
1763 | documentation of commands that match our regex in either their | |
1764 | name, or their documentation. | |
1765 | If VERBOSE, prints the complete documentation and highlight the | |
1766 | documentation parts matching REGEX, otherwise prints only | |
1767 | the first line. | |
1768 | */ | |
1769 | void | |
1770 | apropos_cmd (struct ui_file *stream, | |
1771 | struct cmd_list_element *commandlist, | |
1772 | bool verbose, compiled_regex ®ex) | |
1773 | { | |
1774 | struct cmd_list_element *c; | |
1775 | int returnvalue; | |
1776 | ||
1777 | /* Walk through the commands. */ | |
1778 | for (c=commandlist;c;c=c->next) | |
1779 | { | |
1780 | if (c->is_alias () && !user_documented_alias (*c)) | |
1781 | { | |
1782 | /* Command aliases/abbreviations not specifically documented by the | |
1783 | user are skipped to ensure we print the doc of a command only once, | |
1784 | when encountering the aliased command. */ | |
1785 | continue; | |
1786 | } | |
1787 | ||
1788 | returnvalue = -1; /* Needed to avoid double printing. */ | |
1789 | if (c->name != NULL) | |
1790 | { | |
1791 | size_t name_len = strlen (c->name); | |
1792 | ||
1793 | /* Try to match against the name. */ | |
1794 | returnvalue = regex.search (c->name, name_len, 0, name_len, NULL); | |
1795 | if (returnvalue >= 0) | |
1796 | print_doc_of_command (*c, verbose, regex, stream); | |
1797 | ||
1798 | /* Try to match against the name of the aliases. */ | |
1799 | for (const cmd_list_element &alias : c->aliases) | |
1800 | { | |
1801 | name_len = strlen (alias.name); | |
1802 | returnvalue = regex.search (alias.name, name_len, 0, name_len, NULL); | |
1803 | if (returnvalue >= 0) | |
1804 | { | |
1805 | print_doc_of_command (*c, verbose, regex, stream); | |
1806 | break; | |
1807 | } | |
1808 | } | |
1809 | } | |
1810 | if (c->doc != NULL && returnvalue < 0) | |
1811 | { | |
1812 | size_t doc_len = strlen (c->doc); | |
1813 | ||
1814 | /* Try to match against documentation. */ | |
1815 | if (regex.search (c->doc, doc_len, 0, doc_len, NULL) >= 0) | |
1816 | print_doc_of_command (*c, verbose, regex, stream); | |
1817 | } | |
1818 | /* Check if this command has subcommands. */ | |
1819 | if (c->is_prefix ()) | |
1820 | { | |
1821 | /* Recursively call ourselves on the subcommand list, | |
1822 | passing the right prefix in. */ | |
1823 | apropos_cmd (stream, *c->subcommands, verbose, regex); | |
1824 | } | |
1825 | } | |
1826 | } | |
1827 | ||
1828 | /* This command really has to deal with two things: | |
1829 | 1) I want documentation on *this string* (usually called by | |
1830 | "help commandname"). | |
1831 | ||
1832 | 2) I want documentation on *this list* (usually called by giving a | |
1833 | command that requires subcommands. Also called by saying just | |
1834 | "help".) | |
1835 | ||
1836 | I am going to split this into two separate commands, help_cmd and | |
1837 | help_list. */ | |
1838 | ||
1839 | void | |
1840 | help_cmd (const char *command, struct ui_file *stream) | |
1841 | { | |
1842 | struct cmd_list_element *c, *alias, *prefix_cmd, *c_cmd; | |
1843 | ||
1844 | if (!command) | |
1845 | { | |
1846 | help_list (cmdlist, "", all_classes, stream); | |
1847 | return; | |
1848 | } | |
1849 | ||
1850 | if (strcmp (command, "all") == 0) | |
1851 | { | |
1852 | help_all (stream); | |
1853 | return; | |
1854 | } | |
1855 | ||
1856 | const char *orig_command = command; | |
1857 | c = lookup_cmd (&command, cmdlist, "", NULL, 0, 0); | |
1858 | ||
1859 | if (c == 0) | |
1860 | return; | |
1861 | ||
1862 | lookup_cmd_composition (orig_command, &alias, &prefix_cmd, &c_cmd); | |
1863 | ||
1864 | /* There are three cases here. | |
1865 | If c->subcommands is nonzero, we have a prefix command. | |
1866 | Print its documentation, then list its subcommands. | |
1867 | ||
1868 | If c->func is non NULL, we really have a command. Print its | |
1869 | documentation and return. | |
1870 | ||
1871 | If c->func is NULL, we have a class name. Print its | |
1872 | documentation (as if it were a command) and then set class to the | |
1873 | number of this class so that the commands in the class will be | |
1874 | listed. */ | |
1875 | ||
1876 | if (alias == nullptr || !user_documented_alias (*alias)) | |
1877 | { | |
1878 | /* Case of a normal command, or an alias not explicitly | |
1879 | documented by the user. */ | |
1880 | /* If the user asked 'help somecommand' and there is no alias, | |
1881 | the false indicates to not output the (single) command name. */ | |
1882 | fput_command_names_styled (*c, false, "\n", stream); | |
1883 | fput_aliases_definition_styled (*c, stream); | |
1884 | gdb_puts (c->doc, stream); | |
1885 | } | |
1886 | else | |
1887 | { | |
1888 | /* Case of an alias explicitly documented by the user. | |
1889 | Only output the alias definition and its explicit documentation. */ | |
1890 | fput_alias_definition_styled (*alias, stream); | |
1891 | fput_command_names_styled (*alias, false, "\n", stream); | |
1892 | gdb_puts (alias->doc, stream); | |
1893 | } | |
1894 | gdb_puts ("\n", stream); | |
1895 | ||
1896 | if (!c->is_prefix () && !c->is_command_class_help ()) | |
1897 | return; | |
1898 | ||
1899 | gdb_printf (stream, "\n"); | |
1900 | ||
1901 | /* If this is a prefix command, print it's subcommands. */ | |
1902 | if (c->is_prefix ()) | |
1903 | help_list (*c->subcommands, c->prefixname_no_space ().c_str (), | |
1904 | all_commands, stream); | |
1905 | ||
1906 | /* If this is a class name, print all of the commands in the class. */ | |
1907 | if (c->is_command_class_help ()) | |
1908 | help_list (cmdlist, "", c->theclass, stream); | |
1909 | ||
1910 | if (c->hook_pre || c->hook_post) | |
1911 | gdb_printf (stream, | |
1912 | "\nThis command has a hook (or hooks) defined:\n"); | |
1913 | ||
1914 | if (c->hook_pre) | |
1915 | gdb_printf (stream, | |
1916 | "\tThis command is run after : %s (pre hook)\n", | |
1917 | c->hook_pre->name); | |
1918 | if (c->hook_post) | |
1919 | gdb_printf (stream, | |
1920 | "\tThis command is run before : %s (post hook)\n", | |
1921 | c->hook_post->name); | |
1922 | } | |
1923 | ||
1924 | /* Get a specific kind of help on a command list. | |
1925 | ||
1926 | LIST is the list. | |
1927 | CMDTYPE is the prefix to use in the title string. It should not | |
1928 | end in a space. | |
1929 | THECLASS is the class with which to list the nodes of this list (see | |
1930 | documentation for help_cmd_list below), As usual, ALL_COMMANDS for | |
1931 | everything, ALL_CLASSES for just classes, and non-negative for only things | |
1932 | in a specific class. | |
1933 | and STREAM is the output stream on which to print things. | |
1934 | If you call this routine with a class >= 0, it recurses. */ | |
1935 | void | |
1936 | help_list (struct cmd_list_element *list, const char *cmdtype, | |
1937 | enum command_class theclass, struct ui_file *stream) | |
1938 | { | |
1939 | int len = strlen (cmdtype); | |
1940 | const char *space = ""; | |
1941 | const char *prefix = ""; | |
1942 | if (len > 0) | |
1943 | { | |
1944 | prefix = "sub"; | |
1945 | space = " "; | |
1946 | } | |
1947 | ||
1948 | if (theclass == all_classes) | |
1949 | gdb_printf (stream, "List of classes of %scommands:\n\n", | |
1950 | prefix); | |
1951 | else if (len == 0) | |
1952 | gdb_printf (stream, "List of commands:\n\n"); | |
1953 | else | |
1954 | gdb_printf (stream, "List of \"%ps\" %scommands:\n\n", | |
1955 | styled_string (command_style.style (), cmdtype), | |
1956 | prefix); | |
1957 | ||
1958 | help_cmd_list (list, theclass, theclass >= 0, stream); | |
1959 | ||
1960 | if (theclass == all_classes) | |
1961 | { | |
1962 | gdb_printf (stream, "\n\ | |
1963 | Type \"%p[help%s%s%p]\" followed by a class name for a list of commands in ", | |
1964 | command_style.style ().ptr (), | |
1965 | space, cmdtype, | |
1966 | nullptr); | |
1967 | stream->wrap_here (0); | |
1968 | gdb_printf (stream, "that class."); | |
1969 | ||
1970 | gdb_printf (stream, "\n\ | |
1971 | Type \"%ps\" for the list of all commands.", | |
1972 | styled_string (command_style.style (), "help all")); | |
1973 | } | |
1974 | ||
1975 | gdb_printf (stream, "\nType \"%p[help%s%s%p]\" followed by %scommand name ", | |
1976 | command_style.style ().ptr (), space, cmdtype, nullptr, | |
1977 | prefix); | |
1978 | stream->wrap_here (0); | |
1979 | gdb_puts ("for ", stream); | |
1980 | stream->wrap_here (0); | |
1981 | gdb_puts ("full ", stream); | |
1982 | stream->wrap_here (0); | |
1983 | gdb_puts ("documentation.\n", stream); | |
1984 | gdb_printf (stream, | |
1985 | "Type \"%ps\" to search " | |
1986 | "for commands related to \"word\".\n", | |
1987 | styled_string (command_style.style (), "apropos word")); | |
1988 | gdb_printf (stream, "Type \"%ps\" for full documentation", | |
1989 | styled_string (command_style.style (), "apropos -v word")); | |
1990 | stream->wrap_here (0); | |
1991 | gdb_puts (" of commands related to \"word\".\n", stream); | |
1992 | gdb_puts ("Command name abbreviations are allowed if unambiguous.\n", | |
1993 | stream); | |
1994 | } | |
1995 | ||
1996 | static void | |
1997 | help_all (struct ui_file *stream) | |
1998 | { | |
1999 | struct cmd_list_element *c; | |
2000 | int seen_unclassified = 0; | |
2001 | ||
2002 | for (c = cmdlist; c; c = c->next) | |
2003 | { | |
2004 | if (c->abbrev_flag) | |
2005 | continue; | |
2006 | /* If this is a class name, print all of the commands in the | |
2007 | class. */ | |
2008 | ||
2009 | if (c->is_command_class_help ()) | |
2010 | { | |
2011 | gdb_printf (stream, "\nCommand class: %s\n\n", c->name); | |
2012 | help_cmd_list (cmdlist, c->theclass, true, stream); | |
2013 | } | |
2014 | } | |
2015 | ||
2016 | /* While it's expected that all commands are in some class, | |
2017 | as a safety measure, we'll print commands outside of any | |
2018 | class at the end. */ | |
2019 | ||
2020 | for (c = cmdlist; c; c = c->next) | |
2021 | { | |
2022 | if (c->abbrev_flag) | |
2023 | continue; | |
2024 | ||
2025 | if (c->theclass == no_class) | |
2026 | { | |
2027 | if (!seen_unclassified) | |
2028 | { | |
2029 | gdb_printf (stream, "\nUnclassified commands\n\n"); | |
2030 | seen_unclassified = 1; | |
2031 | } | |
2032 | print_help_for_command (*c, true, stream); | |
2033 | } | |
2034 | } | |
2035 | ||
2036 | } | |
2037 | ||
2038 | /* See cli-decode.h. */ | |
2039 | ||
2040 | void | |
2041 | print_doc_line (struct ui_file *stream, const char *str, | |
2042 | bool for_value_prefix) | |
2043 | { | |
2044 | const char *p = strchr (str, '\n'); | |
2045 | ||
2046 | /* Only copy the input string if we really need to. */ | |
2047 | std::optional<std::string> line_buffer; | |
2048 | if (p != nullptr) | |
2049 | line_buffer = std::string (str, p); | |
2050 | else if (for_value_prefix) | |
2051 | line_buffer = str; | |
2052 | ||
2053 | if (for_value_prefix) | |
2054 | { | |
2055 | char &c = (*line_buffer)[0]; | |
2056 | if (islower (c)) | |
2057 | c = toupper (c); | |
2058 | if (line_buffer->back () == '.') | |
2059 | line_buffer->pop_back (); | |
2060 | } | |
2061 | ||
2062 | gdb_puts (line_buffer.has_value () | |
2063 | ? line_buffer->c_str () | |
2064 | : str, | |
2065 | stream); | |
2066 | } | |
2067 | ||
2068 | /* Print one-line help for command C. | |
2069 | If RECURSE is non-zero, also print one-line descriptions | |
2070 | of all prefixed subcommands. */ | |
2071 | static void | |
2072 | print_help_for_command (const cmd_list_element &c, | |
2073 | bool recurse, struct ui_file *stream) | |
2074 | { | |
2075 | fput_command_names_styled (c, true, " -- ", stream); | |
2076 | print_doc_line (stream, c.doc, false); | |
2077 | gdb_puts ("\n", stream); | |
2078 | if (!c.default_args.empty ()) | |
2079 | fput_alias_definition_styled (c, stream); | |
2080 | fput_aliases_definition_styled (c, stream); | |
2081 | ||
2082 | if (recurse | |
2083 | && c.is_prefix () | |
2084 | && c.abbrev_flag == 0) | |
2085 | /* Subcommands of a prefix command typically have 'all_commands' | |
2086 | as class. If we pass CLASS to recursive invocation, | |
2087 | most often we won't see anything. */ | |
2088 | help_cmd_list (*c.subcommands, all_commands, true, stream); | |
2089 | } | |
2090 | ||
2091 | /* | |
2092 | * Implement a help command on command list LIST. | |
2093 | * RECURSE should be non-zero if this should be done recursively on | |
2094 | * all sublists of LIST. | |
2095 | * STREAM is the stream upon which the output should be written. | |
2096 | * THECLASS should be: | |
2097 | * A non-negative class number to list only commands in that | |
2098 | * ALL_COMMANDS to list all commands in list. | |
2099 | * ALL_CLASSES to list all classes in list. | |
2100 | * | |
2101 | * Note that aliases are only shown when THECLASS is class_alias. | |
2102 | * In the other cases, the aliases will be shown together with their | |
2103 | * aliased command. | |
2104 | * | |
2105 | * Note that RECURSE will be active on *all* sublists, not just the | |
2106 | * ones selected by the criteria above (ie. the selection mechanism | |
2107 | * is at the low level, not the high-level). | |
2108 | */ | |
2109 | ||
2110 | static void | |
2111 | help_cmd_list (struct cmd_list_element *list, enum command_class theclass, | |
2112 | bool recurse, struct ui_file *stream) | |
2113 | { | |
2114 | struct cmd_list_element *c; | |
2115 | ||
2116 | for (c = list; c; c = c->next) | |
2117 | { | |
2118 | if (c->abbrev_flag == 1 || c->cmd_deprecated) | |
2119 | { | |
2120 | /* Do not show abbreviations or deprecated commands. */ | |
2121 | continue; | |
2122 | } | |
2123 | ||
2124 | if (c->is_alias () && theclass != class_alias) | |
2125 | { | |
2126 | /* Do not show an alias, unless specifically showing the | |
2127 | list of aliases: for all other classes, an alias is | |
2128 | shown (if needed) together with its aliased command. */ | |
2129 | continue; | |
2130 | } | |
2131 | ||
2132 | if (theclass == all_commands | |
2133 | || (theclass == all_classes && c->is_command_class_help ()) | |
2134 | || (theclass == c->theclass && !c->is_command_class_help ())) | |
2135 | { | |
2136 | /* show C when | |
2137 | - showing all commands | |
2138 | - showing all classes and C is a help class | |
2139 | - showing commands of THECLASS and C is not the help class */ | |
2140 | ||
2141 | /* If we show the class_alias and C is an alias, do not recurse, | |
2142 | as this would show the (possibly very long) not very useful | |
2143 | list of sub-commands of the aliased command. */ | |
2144 | print_help_for_command | |
2145 | (*c, | |
2146 | recurse && (theclass != class_alias || !c->is_alias ()), | |
2147 | stream); | |
2148 | continue; | |
2149 | } | |
2150 | ||
2151 | if (recurse | |
2152 | && (theclass == class_user || theclass == class_alias) | |
2153 | && c->is_prefix ()) | |
2154 | { | |
2155 | /* User-defined commands or aliases may be subcommands. */ | |
2156 | help_cmd_list (*c->subcommands, theclass, recurse, stream); | |
2157 | continue; | |
2158 | } | |
2159 | ||
2160 | /* Do not show C or recurse on C, e.g. because C does not belong to | |
2161 | THECLASS or because C is a help class. */ | |
2162 | } | |
2163 | } | |
2164 | \f | |
2165 | ||
2166 | /* Search the input clist for 'command'. Return the command if | |
2167 | found (or NULL if not), and return the number of commands | |
2168 | found in nfound. */ | |
2169 | ||
2170 | static struct cmd_list_element * | |
2171 | find_cmd (const char *command, int len, struct cmd_list_element *clist, | |
2172 | int ignore_help_classes, int *nfound) | |
2173 | { | |
2174 | struct cmd_list_element *found, *c; | |
2175 | ||
2176 | found = NULL; | |
2177 | *nfound = 0; | |
2178 | for (c = clist; c; c = c->next) | |
2179 | if (!strncmp (command, c->name, len) | |
2180 | && (!ignore_help_classes || !c->is_command_class_help ())) | |
2181 | { | |
2182 | found = c; | |
2183 | (*nfound)++; | |
2184 | if (c->name[len] == '\0') | |
2185 | { | |
2186 | *nfound = 1; | |
2187 | break; | |
2188 | } | |
2189 | } | |
2190 | return found; | |
2191 | } | |
2192 | ||
2193 | /* Return the length of command name in TEXT. */ | |
2194 | ||
2195 | int | |
2196 | find_command_name_length (const char *text) | |
2197 | { | |
2198 | const char *p = text; | |
2199 | ||
2200 | /* Treating underscores as part of command words is important | |
2201 | so that "set args_foo()" doesn't get interpreted as | |
2202 | "set args _foo()". */ | |
2203 | /* Some characters are only used for TUI specific commands. | |
2204 | However, they are always allowed for the sake of consistency. | |
2205 | ||
2206 | Note that this is larger than the character set allowed when | |
2207 | creating user-defined commands. */ | |
2208 | ||
2209 | /* Recognize the single character commands so that, e.g., "!ls" | |
2210 | works as expected. */ | |
2211 | if (*p == '!' || *p == '|') | |
2212 | return 1; | |
2213 | ||
2214 | while (valid_cmd_char_p (*p) | |
2215 | /* Characters used by TUI specific commands. */ | |
2216 | || *p == '+' || *p == '<' || *p == '>' || *p == '$') | |
2217 | p++; | |
2218 | ||
2219 | return p - text; | |
2220 | } | |
2221 | ||
2222 | /* See command.h. */ | |
2223 | ||
2224 | bool | |
2225 | valid_cmd_char_p (int c) | |
2226 | { | |
2227 | /* Alas "42" is a legitimate user-defined command. | |
2228 | In the interests of not breaking anything we preserve that. */ | |
2229 | ||
2230 | return isalnum (c) || c == '-' || c == '_' || c == '.'; | |
2231 | } | |
2232 | ||
2233 | /* See command.h. */ | |
2234 | ||
2235 | bool | |
2236 | valid_user_defined_cmd_name_p (const char *name) | |
2237 | { | |
2238 | const char *p; | |
2239 | ||
2240 | if (*name == '\0') | |
2241 | return false; | |
2242 | ||
2243 | for (p = name; *p != '\0'; ++p) | |
2244 | { | |
2245 | if (valid_cmd_char_p (*p)) | |
2246 | ; /* Ok. */ | |
2247 | else | |
2248 | return false; | |
2249 | } | |
2250 | ||
2251 | return true; | |
2252 | } | |
2253 | ||
2254 | /* See command.h. */ | |
2255 | ||
2256 | struct cmd_list_element * | |
2257 | lookup_cmd_1 (const char **text, struct cmd_list_element *clist, | |
2258 | struct cmd_list_element **result_list, std::string *default_args, | |
2259 | int ignore_help_classes, bool lookup_for_completion_p) | |
2260 | { | |
2261 | char *command; | |
2262 | int len, nfound; | |
2263 | struct cmd_list_element *found, *c; | |
2264 | bool found_alias = false; | |
2265 | const char *line = *text; | |
2266 | ||
2267 | while (**text == ' ' || **text == '\t') | |
2268 | (*text)++; | |
2269 | ||
2270 | /* Identify the name of the command. */ | |
2271 | len = find_command_name_length (*text); | |
2272 | ||
2273 | /* If nothing but whitespace, return 0. */ | |
2274 | if (len == 0) | |
2275 | return 0; | |
2276 | ||
2277 | /* *text and p now bracket the first command word to lookup (and | |
2278 | it's length is len). We copy this into a local temporary. */ | |
2279 | ||
2280 | ||
2281 | command = (char *) alloca (len + 1); | |
2282 | memcpy (command, *text, len); | |
2283 | command[len] = '\0'; | |
2284 | ||
2285 | /* Look it up. */ | |
2286 | found = 0; | |
2287 | nfound = 0; | |
2288 | found = find_cmd (command, len, clist, ignore_help_classes, &nfound); | |
2289 | ||
2290 | /* If nothing matches, we have a simple failure. */ | |
2291 | if (nfound == 0) | |
2292 | return 0; | |
2293 | ||
2294 | if (nfound > 1) | |
2295 | { | |
2296 | if (result_list != nullptr) | |
2297 | /* Will be modified in calling routine | |
2298 | if we know what the prefix command is. */ | |
2299 | *result_list = 0; | |
2300 | if (default_args != nullptr) | |
2301 | *default_args = std::string (); | |
2302 | return CMD_LIST_AMBIGUOUS; /* Ambiguous. */ | |
2303 | } | |
2304 | ||
2305 | /* We've matched something on this list. Move text pointer forward. */ | |
2306 | ||
2307 | *text += len; | |
2308 | ||
2309 | if (found->is_alias ()) | |
2310 | { | |
2311 | /* We drop the alias (abbreviation) in favor of the command it | |
2312 | is pointing to. If the alias is deprecated, though, we need to | |
2313 | warn the user about it before we drop it. Note that while we | |
2314 | are warning about the alias, we may also warn about the command | |
2315 | itself and we will adjust the appropriate DEPRECATED_WARN_USER | |
2316 | flags. */ | |
2317 | ||
2318 | if (found->deprecated_warn_user && !lookup_for_completion_p) | |
2319 | deprecated_cmd_warning (line, clist); | |
2320 | ||
2321 | ||
2322 | /* Return the default_args of the alias, not the default_args | |
2323 | of the command it is pointing to. */ | |
2324 | if (default_args != nullptr) | |
2325 | *default_args = found->default_args; | |
2326 | found = found->alias_target; | |
2327 | found_alias = true; | |
2328 | } | |
2329 | /* If we found a prefix command, keep looking. */ | |
2330 | ||
2331 | if (found->is_prefix ()) | |
2332 | { | |
2333 | c = lookup_cmd_1 (text, *found->subcommands, result_list, default_args, | |
2334 | ignore_help_classes, lookup_for_completion_p); | |
2335 | if (!c) | |
2336 | { | |
2337 | /* Didn't find anything; this is as far as we got. */ | |
2338 | if (result_list != nullptr) | |
2339 | *result_list = clist; | |
2340 | if (!found_alias && default_args != nullptr) | |
2341 | *default_args = found->default_args; | |
2342 | return found; | |
2343 | } | |
2344 | else if (c == CMD_LIST_AMBIGUOUS) | |
2345 | { | |
2346 | /* We've gotten this far properly, but the next step is | |
2347 | ambiguous. We need to set the result list to the best | |
2348 | we've found (if an inferior hasn't already set it). */ | |
2349 | if (result_list != nullptr) | |
2350 | if (!*result_list) | |
2351 | /* This used to say *result_list = *found->subcommands. | |
2352 | If that was correct, need to modify the documentation | |
2353 | at the top of this function to clarify what is | |
2354 | supposed to be going on. */ | |
2355 | *result_list = found; | |
2356 | /* For ambiguous commands, do not return any default_args args. */ | |
2357 | if (default_args != nullptr) | |
2358 | *default_args = std::string (); | |
2359 | return c; | |
2360 | } | |
2361 | else | |
2362 | { | |
2363 | /* We matched! */ | |
2364 | return c; | |
2365 | } | |
2366 | } | |
2367 | else | |
2368 | { | |
2369 | if (result_list != nullptr) | |
2370 | *result_list = clist; | |
2371 | if (!found_alias && default_args != nullptr) | |
2372 | *default_args = found->default_args; | |
2373 | return found; | |
2374 | } | |
2375 | } | |
2376 | ||
2377 | /* All this hair to move the space to the front of cmdtype */ | |
2378 | ||
2379 | static void | |
2380 | undef_cmd_error (const char *cmdtype, const char *q) | |
2381 | { | |
2382 | error (_("Undefined %scommand: \"%s\". Try \"help%s%.*s\"."), | |
2383 | cmdtype, | |
2384 | q, | |
2385 | *cmdtype ? " " : "", | |
2386 | (int) strlen (cmdtype) - 1, | |
2387 | cmdtype); | |
2388 | } | |
2389 | ||
2390 | /* Look up the contents of *LINE as a command in the command list LIST. | |
2391 | LIST is a chain of struct cmd_list_element's. | |
2392 | If it is found, return the struct cmd_list_element for that command, | |
2393 | update *LINE to point after the command name, at the first argument | |
2394 | and update *DEFAULT_ARGS (if DEFAULT_ARGS is not null) to the default | |
2395 | args to prepend to the user provided args when running the command. | |
2396 | Note that if the found cmd_list_element is found via an alias, | |
2397 | the default args of the alias are returned. | |
2398 | ||
2399 | If not found, call error if ALLOW_UNKNOWN is zero | |
2400 | otherwise (or if error returns) return zero. | |
2401 | Call error if specified command is ambiguous, | |
2402 | unless ALLOW_UNKNOWN is negative. | |
2403 | CMDTYPE precedes the word "command" in the error message. | |
2404 | ||
2405 | If IGNORE_HELP_CLASSES is nonzero, ignore any command list | |
2406 | elements which are actually help classes rather than commands (i.e. | |
2407 | the function field of the struct cmd_list_element is 0). */ | |
2408 | ||
2409 | struct cmd_list_element * | |
2410 | lookup_cmd (const char **line, struct cmd_list_element *list, | |
2411 | const char *cmdtype, | |
2412 | std::string *default_args, | |
2413 | int allow_unknown, int ignore_help_classes) | |
2414 | { | |
2415 | struct cmd_list_element *last_list = 0; | |
2416 | struct cmd_list_element *c; | |
2417 | ||
2418 | /* Note: Do not remove trailing whitespace here because this | |
2419 | would be wrong for complete_command. Jim Kingdon */ | |
2420 | ||
2421 | if (!*line) | |
2422 | error (_("Lack of needed %scommand"), cmdtype); | |
2423 | ||
2424 | c = lookup_cmd_1 (line, list, &last_list, default_args, ignore_help_classes); | |
2425 | ||
2426 | if (!c) | |
2427 | { | |
2428 | if (!allow_unknown) | |
2429 | { | |
2430 | char *q; | |
2431 | int len = find_command_name_length (*line); | |
2432 | ||
2433 | q = (char *) alloca (len + 1); | |
2434 | strncpy (q, *line, len); | |
2435 | q[len] = '\0'; | |
2436 | undef_cmd_error (cmdtype, q); | |
2437 | } | |
2438 | else | |
2439 | return 0; | |
2440 | } | |
2441 | else if (c == CMD_LIST_AMBIGUOUS) | |
2442 | { | |
2443 | /* Ambiguous. Local values should be off subcommands or called | |
2444 | values. */ | |
2445 | int local_allow_unknown = (last_list ? last_list->allow_unknown : | |
2446 | allow_unknown); | |
2447 | std::string local_cmdtype | |
2448 | = last_list ? last_list->prefixname () : cmdtype; | |
2449 | struct cmd_list_element *local_list = | |
2450 | (last_list ? *(last_list->subcommands) : list); | |
2451 | ||
2452 | if (local_allow_unknown < 0) | |
2453 | { | |
2454 | if (last_list) | |
2455 | return last_list; /* Found something. */ | |
2456 | else | |
2457 | return 0; /* Found nothing. */ | |
2458 | } | |
2459 | else | |
2460 | { | |
2461 | /* Report as error. */ | |
2462 | int amb_len; | |
2463 | char ambbuf[100]; | |
2464 | ||
2465 | for (amb_len = 0; | |
2466 | ((*line)[amb_len] && (*line)[amb_len] != ' ' | |
2467 | && (*line)[amb_len] != '\t'); | |
2468 | amb_len++) | |
2469 | ; | |
2470 | ||
2471 | ambbuf[0] = 0; | |
2472 | for (c = local_list; c; c = c->next) | |
2473 | if (!strncmp (*line, c->name, amb_len)) | |
2474 | { | |
2475 | if (strlen (ambbuf) + strlen (c->name) + 6 | |
2476 | < (int) sizeof ambbuf) | |
2477 | { | |
2478 | if (strlen (ambbuf)) | |
2479 | strcat (ambbuf, ", "); | |
2480 | strcat (ambbuf, c->name); | |
2481 | } | |
2482 | else | |
2483 | { | |
2484 | strcat (ambbuf, ".."); | |
2485 | break; | |
2486 | } | |
2487 | } | |
2488 | error (_("Ambiguous %scommand \"%s\": %s."), | |
2489 | local_cmdtype.c_str (), *line, ambbuf); | |
2490 | } | |
2491 | } | |
2492 | else | |
2493 | { | |
2494 | if (c->type == set_cmd && **line != '\0' && !isspace (**line)) | |
2495 | error (_("Argument must be preceded by space.")); | |
2496 | ||
2497 | /* We've got something. It may still not be what the caller | |
2498 | wants (if this command *needs* a subcommand). */ | |
2499 | while (**line == ' ' || **line == '\t') | |
2500 | (*line)++; | |
2501 | ||
2502 | if (c->is_prefix () && **line && !c->allow_unknown) | |
2503 | undef_cmd_error (c->prefixname ().c_str (), *line); | |
2504 | ||
2505 | /* Seems to be what he wants. Return it. */ | |
2506 | return c; | |
2507 | } | |
2508 | return 0; | |
2509 | } | |
2510 | ||
2511 | /* See command.h. */ | |
2512 | ||
2513 | struct cmd_list_element * | |
2514 | lookup_cmd_exact (const char *name, | |
2515 | struct cmd_list_element *list, | |
2516 | bool ignore_help_classes) | |
2517 | { | |
2518 | const char *tem = name; | |
2519 | struct cmd_list_element *cmd = lookup_cmd (&tem, list, "", NULL, -1, | |
2520 | ignore_help_classes); | |
2521 | if (cmd != nullptr && strcmp (name, cmd->name) != 0) | |
2522 | cmd = nullptr; | |
2523 | return cmd; | |
2524 | } | |
2525 | ||
2526 | /* We are here presumably because an alias or command in TEXT is | |
2527 | deprecated and a warning message should be generated. This | |
2528 | function decodes TEXT and potentially generates a warning message | |
2529 | as outlined below. | |
2530 | ||
2531 | Example for 'set endian big' which has a fictitious alias 'seb'. | |
2532 | ||
2533 | If alias wasn't used in TEXT, and the command is deprecated: | |
2534 | "warning: 'set endian big' is deprecated." | |
2535 | ||
2536 | If alias was used, and only the alias is deprecated: | |
2537 | "warning: 'seb' an alias for the command 'set endian big' is deprecated." | |
2538 | ||
2539 | If alias was used and command is deprecated (regardless of whether | |
2540 | the alias itself is deprecated: | |
2541 | ||
2542 | "warning: 'set endian big' (seb) is deprecated." | |
2543 | ||
2544 | After the message has been sent, clear the appropriate flags in the | |
2545 | command and/or the alias so the user is no longer bothered. | |
2546 | ||
2547 | */ | |
2548 | void | |
2549 | deprecated_cmd_warning (const char *text, struct cmd_list_element *list) | |
2550 | { | |
2551 | struct cmd_list_element *alias = nullptr; | |
2552 | struct cmd_list_element *cmd = nullptr; | |
2553 | ||
2554 | /* Return if text doesn't evaluate to a command. We place this lookup | |
2555 | within its own scope so that the PREFIX_CMD local is not visible | |
2556 | later in this function. The value returned in PREFIX_CMD is based on | |
2557 | the prefix found in TEXT, and is our case this prefix can be missing | |
2558 | in some situations (when LIST is not the global CMDLIST). | |
2559 | ||
2560 | It is better for our purposes to use the prefix commands directly from | |
2561 | the ALIAS and CMD results. */ | |
2562 | { | |
2563 | struct cmd_list_element *prefix_cmd = nullptr; | |
2564 | if (!lookup_cmd_composition_1 (text, &alias, &prefix_cmd, &cmd, list)) | |
2565 | return; | |
2566 | } | |
2567 | ||
2568 | /* Return if nothing is deprecated. */ | |
2569 | if (!((alias != nullptr ? alias->deprecated_warn_user : 0) | |
2570 | || cmd->deprecated_warn_user)) | |
2571 | return; | |
2572 | ||
2573 | /* Join command prefix (if any) and the command name. */ | |
2574 | std::string tmp_cmd_str; | |
2575 | if (cmd->prefix != nullptr) | |
2576 | tmp_cmd_str += cmd->prefix->prefixname (); | |
2577 | tmp_cmd_str += std::string (cmd->name); | |
2578 | ||
2579 | /* Display the appropriate first line, this warns that the thing the user | |
2580 | entered is deprecated. */ | |
2581 | if (alias != nullptr) | |
2582 | { | |
2583 | /* Join the alias prefix (if any) and the alias name. */ | |
2584 | std::string tmp_alias_str; | |
2585 | if (alias->prefix != nullptr) | |
2586 | tmp_alias_str += alias->prefix->prefixname (); | |
2587 | tmp_alias_str += std::string (alias->name); | |
2588 | ||
2589 | if (cmd->cmd_deprecated) | |
2590 | gdb_printf (_("Warning: command '%ps' (%ps) is deprecated.\n"), | |
2591 | styled_string (command_style.style (), | |
2592 | tmp_cmd_str.c_str ()), | |
2593 | styled_string (command_style.style (), | |
2594 | tmp_alias_str.c_str ())); | |
2595 | else | |
2596 | gdb_printf (_("Warning: '%ps', an alias for the command '%ps', " | |
2597 | "is deprecated.\n"), | |
2598 | styled_string (command_style.style (), | |
2599 | tmp_alias_str.c_str ()), | |
2600 | styled_string (command_style.style (), | |
2601 | tmp_cmd_str.c_str ())); | |
2602 | } | |
2603 | else | |
2604 | gdb_printf (_("Warning: command '%ps' is deprecated.\n"), | |
2605 | styled_string (command_style.style (), | |
2606 | tmp_cmd_str.c_str ())); | |
2607 | ||
2608 | /* Now display a second line indicating what the user should use instead. | |
2609 | If it is only the alias that is deprecated, we want to indicate the | |
2610 | new alias, otherwise we'll indicate the new command. */ | |
2611 | const char *replacement; | |
2612 | if (alias != nullptr && !cmd->cmd_deprecated) | |
2613 | replacement = alias->replacement; | |
2614 | else | |
2615 | replacement = cmd->replacement; | |
2616 | if (replacement != nullptr) | |
2617 | gdb_printf (_("Use '%ps'.\n\n"), | |
2618 | styled_string (command_style.style (), | |
2619 | replacement)); | |
2620 | else | |
2621 | gdb_printf (_("No alternative known.\n\n")); | |
2622 | ||
2623 | /* We've warned you, now we'll keep quiet. */ | |
2624 | if (alias != nullptr) | |
2625 | alias->deprecated_warn_user = 0; | |
2626 | cmd->deprecated_warn_user = 0; | |
2627 | } | |
2628 | ||
2629 | /* Look up the contents of TEXT as a command in the command list CUR_LIST. | |
2630 | Return 1 on success, 0 on failure. | |
2631 | ||
2632 | If TEXT refers to an alias, *ALIAS will point to that alias. | |
2633 | ||
2634 | If TEXT is a subcommand (i.e. one that is preceded by a prefix | |
2635 | command) set *PREFIX_CMD. | |
2636 | ||
2637 | Set *CMD to point to the command TEXT indicates, or to | |
2638 | CMD_LIST_AMBIGUOUS if there are multiple possible matches. | |
2639 | ||
2640 | If any of *ALIAS, *PREFIX_CMD, or *CMD cannot be determined or do not | |
2641 | exist, they are NULL when we return. | |
2642 | ||
2643 | */ | |
2644 | ||
2645 | static int | |
2646 | lookup_cmd_composition_1 (const char *text, | |
2647 | struct cmd_list_element **alias, | |
2648 | struct cmd_list_element **prefix_cmd, | |
2649 | struct cmd_list_element **cmd, | |
2650 | struct cmd_list_element *cur_list) | |
2651 | { | |
2652 | *alias = nullptr; | |
2653 | *prefix_cmd = cur_list->prefix; | |
2654 | *cmd = nullptr; | |
2655 | ||
2656 | text = skip_spaces (text); | |
2657 | ||
2658 | /* Go through as many command lists as we need to, to find the command | |
2659 | TEXT refers to. */ | |
2660 | while (1) | |
2661 | { | |
2662 | /* Identify the name of the command. */ | |
2663 | int len = find_command_name_length (text); | |
2664 | ||
2665 | /* If nothing but whitespace, return. */ | |
2666 | if (len == 0) | |
2667 | return 0; | |
2668 | ||
2669 | /* TEXT is the start of the first command word to lookup (and | |
2670 | it's length is LEN). We copy this into a local temporary. */ | |
2671 | std::string command (text, len); | |
2672 | ||
2673 | /* Look it up. */ | |
2674 | int nfound = 0; | |
2675 | *cmd = find_cmd (command.c_str (), len, cur_list, 1, &nfound); | |
2676 | ||
2677 | /* We only handle the case where a single command was found. */ | |
2678 | if (nfound > 1) | |
2679 | { | |
2680 | *cmd = CMD_LIST_AMBIGUOUS; | |
2681 | return 0; | |
2682 | } | |
2683 | else if (*cmd == nullptr) | |
2684 | return 0; | |
2685 | else | |
2686 | { | |
2687 | if ((*cmd)->is_alias ()) | |
2688 | { | |
2689 | /* If the command was actually an alias, we note that an | |
2690 | alias was used (by assigning *ALIAS) and we set *CMD. */ | |
2691 | *alias = *cmd; | |
2692 | *cmd = (*cmd)->alias_target; | |
2693 | } | |
2694 | } | |
2695 | ||
2696 | text += len; | |
2697 | text = skip_spaces (text); | |
2698 | ||
2699 | if ((*cmd)->is_prefix () && *text != '\0') | |
2700 | { | |
2701 | cur_list = *(*cmd)->subcommands; | |
2702 | *prefix_cmd = *cmd; | |
2703 | } | |
2704 | else | |
2705 | return 1; | |
2706 | } | |
2707 | } | |
2708 | ||
2709 | /* Look up the contents of TEXT as a command in the command list 'cmdlist'. | |
2710 | Return 1 on success, 0 on failure. | |
2711 | ||
2712 | If TEXT refers to an alias, *ALIAS will point to that alias. | |
2713 | ||
2714 | If TEXT is a subcommand (i.e. one that is preceded by a prefix | |
2715 | command) set *PREFIX_CMD. | |
2716 | ||
2717 | Set *CMD to point to the command TEXT indicates, or to | |
2718 | CMD_LIST_AMBIGUOUS if there are multiple possible matches. | |
2719 | ||
2720 | If any of *ALIAS, *PREFIX_CMD, or *CMD cannot be determined or do not | |
2721 | exist, they are NULL when we return. | |
2722 | ||
2723 | */ | |
2724 | ||
2725 | int | |
2726 | lookup_cmd_composition (const char *text, | |
2727 | struct cmd_list_element **alias, | |
2728 | struct cmd_list_element **prefix_cmd, | |
2729 | struct cmd_list_element **cmd) | |
2730 | { | |
2731 | return lookup_cmd_composition_1 (text, alias, prefix_cmd, cmd, cmdlist); | |
2732 | } | |
2733 | ||
2734 | /* Helper function for SYMBOL_COMPLETION_FUNCTION. */ | |
2735 | ||
2736 | /* Return a vector of char pointers which point to the different | |
2737 | possible completions in LIST of TEXT. | |
2738 | ||
2739 | WORD points in the same buffer as TEXT, and completions should be | |
2740 | returned relative to this position. For example, suppose TEXT is | |
2741 | "foo" and we want to complete to "foobar". If WORD is "oo", return | |
2742 | "oobar"; if WORD is "baz/foo", return "baz/foobar". */ | |
2743 | ||
2744 | void | |
2745 | complete_on_cmdlist (struct cmd_list_element *list, | |
2746 | completion_tracker &tracker, | |
2747 | const char *text, const char *word, | |
2748 | int ignore_help_classes) | |
2749 | { | |
2750 | struct cmd_list_element *ptr; | |
2751 | int textlen = strlen (text); | |
2752 | int pass; | |
2753 | int saw_deprecated_match = 0; | |
2754 | ||
2755 | /* We do one or two passes. In the first pass, we skip deprecated | |
2756 | commands. If we see no matching commands in the first pass, and | |
2757 | if we did happen to see a matching deprecated command, we do | |
2758 | another loop to collect those. */ | |
2759 | for (pass = 0; pass < 2; ++pass) | |
2760 | { | |
2761 | bool got_matches = false; | |
2762 | ||
2763 | for (ptr = list; ptr; ptr = ptr->next) | |
2764 | if (!strncmp (ptr->name, text, textlen) | |
2765 | && !ptr->abbrev_flag | |
2766 | && (!ignore_help_classes || !ptr->is_command_class_help () | |
2767 | || ptr->is_prefix ())) | |
2768 | { | |
2769 | if (pass == 0) | |
2770 | { | |
2771 | if (ptr->cmd_deprecated) | |
2772 | { | |
2773 | saw_deprecated_match = 1; | |
2774 | continue; | |
2775 | } | |
2776 | } | |
2777 | ||
2778 | tracker.add_completion | |
2779 | (make_completion_match_str (ptr->name, text, word)); | |
2780 | got_matches = true; | |
2781 | } | |
2782 | ||
2783 | if (got_matches) | |
2784 | break; | |
2785 | ||
2786 | /* If we saw no matching deprecated commands in the first pass, | |
2787 | just bail out. */ | |
2788 | if (!saw_deprecated_match) | |
2789 | break; | |
2790 | } | |
2791 | } | |
2792 | ||
2793 | /* Helper function for SYMBOL_COMPLETION_FUNCTION. */ | |
2794 | ||
2795 | /* Add the different possible completions in ENUMLIST of TEXT. | |
2796 | ||
2797 | WORD points in the same buffer as TEXT, and completions should be | |
2798 | returned relative to this position. For example, suppose TEXT is "foo" | |
2799 | and we want to complete to "foobar". If WORD is "oo", return | |
2800 | "oobar"; if WORD is "baz/foo", return "baz/foobar". */ | |
2801 | ||
2802 | void | |
2803 | complete_on_enum (completion_tracker &tracker, | |
2804 | const char *const *enumlist, | |
2805 | const char *text, const char *word) | |
2806 | { | |
2807 | int textlen = strlen (text); | |
2808 | int i; | |
2809 | const char *name; | |
2810 | ||
2811 | for (i = 0; (name = enumlist[i]) != NULL; i++) | |
2812 | if (strncmp (name, text, textlen) == 0) | |
2813 | tracker.add_completion (make_completion_match_str (name, text, word)); | |
2814 | } | |
2815 | ||
2816 | /* Call the command function. */ | |
2817 | void | |
2818 | cmd_func (struct cmd_list_element *cmd, const char *args, int from_tty) | |
2819 | { | |
2820 | if (!cmd->is_command_class_help ()) | |
2821 | { | |
2822 | std::optional<scoped_restore_tmpl<bool>> restore_suppress; | |
2823 | ||
2824 | if (cmd->suppress_notification != NULL) | |
2825 | restore_suppress.emplace (cmd->suppress_notification, true); | |
2826 | ||
2827 | cmd->func (args, from_tty, cmd); | |
2828 | } | |
2829 | else | |
2830 | error (_("Invalid command")); | |
2831 | } | |
2832 | ||
2833 | int | |
2834 | cli_user_command_p (struct cmd_list_element *cmd) | |
2835 | { | |
2836 | return cmd->theclass == class_user && cmd->func == do_simple_func; | |
2837 | } | |
2838 | ||
2839 | /* See cli-decode.h. */ | |
2840 | ||
2841 | ui_file_style::color | |
2842 | parse_cli_var_color (const char **args) | |
2843 | { | |
2844 | /* Do a "set" command. ARG is nullptr if no argument, or the | |
2845 | text of the argument. */ | |
2846 | ||
2847 | if (args == nullptr || *args == nullptr || **args == '\0') | |
2848 | { | |
2849 | std::string msg; | |
2850 | ||
2851 | for (size_t i = 0; ui_file_style::basic_color_enums[i]; ++i) | |
2852 | { | |
2853 | msg.append ("\""); | |
2854 | msg.append (ui_file_style::basic_color_enums[i]); | |
2855 | msg.append ("\", "); | |
2856 | } | |
2857 | ||
2858 | error (_("Requires an argument. Valid arguments are %sinteger from -1 " | |
2859 | "to 255 or an RGB hex triplet in a format #RRGGBB"), | |
2860 | msg.c_str ()); | |
2861 | } | |
2862 | ||
2863 | const char *p = skip_to_space (*args); | |
2864 | size_t len = p - *args; | |
2865 | ||
2866 | int nmatches = 0; | |
2867 | ui_file_style::basic_color match = ui_file_style::NONE; | |
2868 | for (int i = 0; ui_file_style::basic_color_enums[i]; ++i) | |
2869 | if (strncmp (*args, ui_file_style::basic_color_enums[i], len) == 0) | |
2870 | { | |
2871 | match = static_cast<ui_file_style::basic_color> (i - 1); | |
2872 | if (ui_file_style::basic_color_enums[i][len] == '\0') | |
2873 | { | |
2874 | nmatches = 1; | |
2875 | break; /* Exact match. */ | |
2876 | } | |
2877 | else | |
2878 | nmatches++; | |
2879 | } | |
2880 | ||
2881 | if (nmatches == 1) | |
2882 | { | |
2883 | *args += len; | |
2884 | return ui_file_style::color (match); | |
2885 | } | |
2886 | ||
2887 | if (nmatches > 1) | |
2888 | error (_("Ambiguous item \"%.*s\"."), (int) len, *args); | |
2889 | ||
2890 | if (**args != '#') | |
2891 | { | |
2892 | ULONGEST num = get_ulongest (args); | |
2893 | if (num > 255) | |
2894 | error (_("integer %s out of range"), pulongest (num)); | |
2895 | return ui_file_style::color (color_space::XTERM_256COLOR, | |
2896 | static_cast<int> (num)); | |
2897 | } | |
2898 | ||
2899 | /* Try to parse #RRGGBB string. */ | |
2900 | if (len != 7) | |
2901 | error_no_arg (_("invalid RGB hex triplet format")); | |
2902 | ||
2903 | uint32_t rgb; | |
2904 | uint8_t r, g, b; | |
2905 | int scanned_chars = 0; | |
2906 | int parsed_args = sscanf (*args, "#%6" SCNx32 "%n", | |
2907 | &rgb, &scanned_chars); | |
2908 | ||
2909 | if (parsed_args != 1 || scanned_chars != 7) | |
2910 | error_no_arg (_("invalid RGB hex triplet format")); | |
2911 | ||
2912 | gdb_assert ((rgb >> 24) == 0); | |
2913 | r = (rgb >> 16) & 0xff; | |
2914 | g = (rgb >> 8) & 0xff; | |
2915 | b = rgb & 0xff; | |
2916 | ||
2917 | *args += len; | |
2918 | return ui_file_style::color (r, g, b); | |
2919 | } | |
2920 | ||
2921 | /* See cli-decode.h. */ | |
2922 | ||
2923 | ui_file_style::color | |
2924 | parse_var_color (const char *arg) | |
2925 | { | |
2926 | const char *end_arg = arg; | |
2927 | ui_file_style::color color = parse_cli_var_color (&end_arg); | |
2928 | ||
2929 | int len = end_arg - arg; | |
2930 | const char *after = skip_spaces (end_arg); | |
2931 | if (*after != '\0') | |
2932 | error (_("Junk after item \"%.*s\": %s"), len, arg, after); | |
2933 | ||
2934 | return color; | |
2935 | } |