]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/mi/mi-parse.c
0af90cb711bf482ad526031f5f64a3846da7e0c8
1 /* MI Command Set - MI parser.
3 Copyright (C) 2000-2025 Free Software Foundation, Inc.
5 Contributed by Cygnus Solutions (a Red Hat company).
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
26 #include "cli/cli-utils.h"
29 static const char mi_no_values
[] = "--no-values";
30 static const char mi_simple_values
[] = "--simple-values";
31 static const char mi_all_values
[] = "--all-values";
33 /* Like parse_escape, but leave the results as a host char, not a
37 mi_parse_escape (const char **string_ptr
)
39 int c
= *(*string_ptr
)++;
64 if (isdigit (c
) && c
!= '8' && c
!= '9')
108 mi_parse::parse_argv ()
110 /* If arguments were already computed (or were supplied at
111 construction), then there's no need to re-compute them. */
115 const char *chp
= m_args
.c_str ();
117 char **argv
= XNEWVEC (char *, argc
+ 1);
124 /* Skip leading white space. */
125 chp
= skip_spaces (chp
);
126 /* Three possibilities: EOF, quoted string, or other text. */
135 /* A quoted string. */
137 const char *start
= chp
+ 1;
139 /* Determine the buffer size. */
142 while (*chp
!= '\0' && *chp
!= '"')
147 if (mi_parse_escape (&chp
) <= 0)
149 /* Do not allow split lines or "\000". */
158 /* Insist on a closing quote. */
164 /* Insist on trailing white space. */
165 if (chp
[1] != '\0' && !isspace (chp
[1]))
170 /* Create the buffer and copy characters in. */
171 arg
= XNEWVEC (char, len
+ 1);
174 while (*chp
!= '\0' && *chp
!= '"')
179 arg
[len
] = mi_parse_escape (&chp
);
186 chp
++; /* That closing quote. */
191 /* An unquoted string. Accumulate all non-blank
192 characters into a buffer. */
194 const char *start
= chp
;
196 while (*chp
!= '\0' && !isspace (*chp
))
201 arg
= XNEWVEC (char, len
+ 1);
202 strncpy (arg
, start
, len
);
207 /* Append arg to argv. */
208 argv
= XRESIZEVEC (char *, argv
, argc
+ 2);
214 mi_parse::~mi_parse ()
219 /* See mi-parse.h. */
224 /* If args were already computed, or if there is no pre-computed
225 argv, just return the args. */
226 if (!m_args
.empty () || argv
== nullptr)
227 return m_args
.c_str ();
229 /* Compute args from argv. */
230 for (int i
= 0; i
< argc
; ++i
)
232 if (!m_args
.empty ())
237 return m_args
.c_str ();
240 /* See mi-parse.h. */
243 mi_parse::set_thread_group (const char *arg
, char **endp
)
245 if (thread_group
!= -1)
246 error (_("Duplicate '--thread-group' option"));
248 error (_("Invalid thread group id"));
250 thread_group
= strtol (arg
, endp
, 10);
253 /* See mi-parse.h. */
256 mi_parse::set_thread (const char *arg
, char **endp
)
259 error (_("Duplicate '--thread' option"));
260 thread
= strtol (arg
, endp
, 10);
263 /* See mi-parse.h. */
266 mi_parse::set_frame (const char *arg
, char **endp
)
269 error (_("Duplicate '--frame' option"));
270 frame
= strtol (arg
, endp
, 10);
273 /* See mi-parse.h. */
276 mi_parse::set_language (const char *arg
, const char **endp
)
278 std::string lang_name
= extract_arg (&arg
);
280 language
= language_enum (lang_name
.c_str ());
281 if (language
== language_unknown
)
282 error (_("Invalid --language argument: %s"), lang_name
.c_str ());
288 /* See mi-parse.h. */
290 mi_parse::mi_parse (const char *cmd
, std::string
*token
)
294 /* Before starting, skip leading white space. */
295 cmd
= skip_spaces (cmd
);
297 /* Find/skip any token and then extract it. */
298 for (chp
= cmd
; *chp
>= '0' && *chp
<= '9'; chp
++)
300 *token
= std::string (cmd
, chp
- cmd
);
302 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
305 chp
= skip_spaces (chp
);
306 this->command
= make_unique_xstrdup (chp
);
307 this->op
= CLI_COMMAND
;
312 /* Extract the command. */
314 const char *tmp
= chp
+ 1; /* discard ``-'' */
316 for (; *chp
&& !isspace (*chp
); chp
++)
318 this->command
= make_unique_xstrndup (tmp
, chp
- tmp
);
321 /* Find the command in the MI table. */
322 this->cmd
= mi_cmd_lookup (this->command
.get ());
323 if (this->cmd
== NULL
)
324 throw_error (UNDEFINED_COMMAND_ERROR
,
325 _("Undefined MI command: %s"), this->command
.get ());
327 /* Skip white space following the command. */
328 chp
= skip_spaces (chp
);
330 /* Parse the --thread and --frame options, if present. At present,
331 some important commands, like '-break-*' are implemented by
332 forwarding to the CLI layer directly. We want to parse --thread
333 and --frame here, so as not to leave those option in the string
334 that will be passed to CLI.
336 Same for the --language option. */
341 size_t as
= sizeof ("--all ") - 1;
342 size_t tgs
= sizeof ("--thread-group ") - 1;
343 size_t ts
= sizeof ("--thread ") - 1;
344 size_t fs
= sizeof ("--frame ") - 1;
345 size_t ls
= sizeof ("--language ") - 1;
347 if (strncmp (chp
, "--all ", as
) == 0)
352 /* See if --all is the last token in the input. */
353 if (strcmp (chp
, "--all") == 0)
358 if (strncmp (chp
, "--thread-group ", tgs
) == 0)
362 option
= "--thread-group";
364 this->set_thread_group (chp
, &endp
);
367 else if (strncmp (chp
, "--thread ", ts
) == 0)
373 this->set_thread (chp
, &endp
);
376 else if (strncmp (chp
, "--frame ", fs
) == 0)
382 this->set_frame (chp
, &endp
);
385 else if (strncmp (chp
, "--language ", ls
) == 0)
387 option
= "--language";
389 this->set_language (chp
, &chp
);
394 if (*chp
!= '\0' && !isspace (*chp
))
395 error (_("Invalid value for the '%s' option"), option
);
396 chp
= skip_spaces (chp
);
399 /* Save the rest of the arguments for the command. */
402 /* Fully parsed, flag as an MI command. */
403 this->op
= MI_COMMAND
;
406 /* See mi-parse.h. */
408 mi_parse::mi_parse (gdb::unique_xmalloc_ptr
<char> command
,
409 std::vector
<gdb::unique_xmalloc_ptr
<char>> args
)
411 this->command
= std::move (command
);
414 if (this->command
.get ()[0] != '-')
415 throw_error (UNDEFINED_COMMAND_ERROR
,
416 _("MI command '%s' does not start with '-'"),
417 this->command
.get ());
419 /* Find the command in the MI table. */
420 this->cmd
= mi_cmd_lookup (this->command
.get () + 1);
421 if (this->cmd
== NULL
)
422 throw_error (UNDEFINED_COMMAND_ERROR
,
423 _("Undefined MI command: %s"), this->command
.get ());
425 /* This over-allocates slightly, but it seems unimportant. */
426 this->argv
= XCNEWVEC (char *, args
.size () + 1);
428 for (size_t i
= 0; i
< args
.size (); ++i
)
430 const char *chp
= args
[i
].get ();
432 /* See if --all is the last token in the input. */
433 if (strcmp (chp
, "--all") == 0)
437 else if (strcmp (chp
, "--thread-group") == 0)
440 if (i
== args
.size ())
441 error ("No argument to '--thread-group'");
442 this->set_thread_group (args
[i
].get (), nullptr);
444 else if (strcmp (chp
, "--thread") == 0)
447 if (i
== args
.size ())
448 error ("No argument to '--thread'");
449 this->set_thread (args
[i
].get (), nullptr);
451 else if (strcmp (chp
, "--frame") == 0)
454 if (i
== args
.size ())
455 error ("No argument to '--frame'");
456 this->set_frame (args
[i
].get (), nullptr);
458 else if (strcmp (chp
, "--language") == 0)
461 if (i
== args
.size ())
462 error ("No argument to '--language'");
463 this->set_language (args
[i
].get (), nullptr);
466 this->argv
[this->argc
++] = args
[i
].release ();
469 /* Fully parsed, flag as an MI command. */
470 this->op
= MI_COMMAND
;
474 mi_parse_print_values (const char *name
)
476 if (strcmp (name
, "0") == 0
477 || strcmp (name
, mi_no_values
) == 0)
478 return PRINT_NO_VALUES
;
479 else if (strcmp (name
, "1") == 0
480 || strcmp (name
, mi_all_values
) == 0)
481 return PRINT_ALL_VALUES
;
482 else if (strcmp (name
, "2") == 0
483 || strcmp (name
, mi_simple_values
) == 0)
484 return PRINT_SIMPLE_VALUES
;
486 error (_("Unknown value for PRINT_VALUES: must be: \
487 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
488 mi_no_values
, mi_all_values
, mi_simple_values
);