mi-parse.c revision 1.8 1 1.1 christos /* MI Command Set - MI parser.
2 1.1 christos
3 1.8 christos Copyright (C) 2000-2019 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos Contributed by Cygnus Solutions (a Red Hat company).
6 1.1 christos
7 1.1 christos This file is part of GDB.
8 1.1 christos
9 1.1 christos This program is free software; you can redistribute it and/or modify
10 1.1 christos it under the terms of the GNU General Public License as published by
11 1.1 christos the Free Software Foundation; either version 3 of the License, or
12 1.1 christos (at your option) any later version.
13 1.1 christos
14 1.1 christos This program is distributed in the hope that it will be useful,
15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 1.1 christos GNU General Public License for more details.
18 1.1 christos
19 1.1 christos You should have received a copy of the GNU General Public License
20 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 1.1 christos
22 1.1 christos #include "defs.h"
23 1.1 christos #include "mi-cmds.h"
24 1.1 christos #include "mi-parse.h"
25 1.1 christos #include "charset.h"
26 1.1 christos
27 1.1 christos #include <ctype.h>
28 1.1 christos #include "cli/cli-utils.h"
29 1.1 christos #include "language.h"
30 1.1 christos
31 1.1 christos static const char mi_no_values[] = "--no-values";
32 1.1 christos static const char mi_simple_values[] = "--simple-values";
33 1.1 christos static const char mi_all_values[] = "--all-values";
34 1.1 christos
35 1.1 christos /* Like parse_escape, but leave the results as a host char, not a
36 1.1 christos target char. */
37 1.1 christos
38 1.1 christos static int
39 1.1 christos mi_parse_escape (const char **string_ptr)
40 1.1 christos {
41 1.1 christos int c = *(*string_ptr)++;
42 1.1 christos
43 1.1 christos switch (c)
44 1.1 christos {
45 1.1 christos case '\n':
46 1.1 christos return -2;
47 1.1 christos case 0:
48 1.1 christos (*string_ptr)--;
49 1.1 christos return 0;
50 1.1 christos
51 1.1 christos case '0':
52 1.1 christos case '1':
53 1.1 christos case '2':
54 1.1 christos case '3':
55 1.1 christos case '4':
56 1.1 christos case '5':
57 1.1 christos case '6':
58 1.1 christos case '7':
59 1.1 christos {
60 1.1 christos int i = host_hex_value (c);
61 1.1 christos int count = 0;
62 1.1 christos
63 1.1 christos while (++count < 3)
64 1.1 christos {
65 1.1 christos c = (**string_ptr);
66 1.1 christos if (isdigit (c) && c != '8' && c != '9')
67 1.1 christos {
68 1.1 christos (*string_ptr)++;
69 1.1 christos i *= 8;
70 1.1 christos i += host_hex_value (c);
71 1.1 christos }
72 1.1 christos else
73 1.1 christos {
74 1.1 christos break;
75 1.1 christos }
76 1.1 christos }
77 1.1 christos return i;
78 1.1 christos }
79 1.1 christos
80 1.1 christos case 'a':
81 1.1 christos c = '\a';
82 1.1 christos break;
83 1.1 christos case 'b':
84 1.1 christos c = '\b';
85 1.1 christos break;
86 1.1 christos case 'f':
87 1.1 christos c = '\f';
88 1.1 christos break;
89 1.1 christos case 'n':
90 1.1 christos c = '\n';
91 1.1 christos break;
92 1.1 christos case 'r':
93 1.1 christos c = '\r';
94 1.1 christos break;
95 1.1 christos case 't':
96 1.1 christos c = '\t';
97 1.1 christos break;
98 1.1 christos case 'v':
99 1.1 christos c = '\v';
100 1.1 christos break;
101 1.1 christos
102 1.1 christos default:
103 1.1 christos break;
104 1.1 christos }
105 1.1 christos
106 1.1 christos return c;
107 1.1 christos }
108 1.1 christos
109 1.1 christos static void
110 1.1 christos mi_parse_argv (const char *args, struct mi_parse *parse)
111 1.1 christos {
112 1.1 christos const char *chp = args;
113 1.1 christos int argc = 0;
114 1.6 christos char **argv = XNEWVEC (char *, argc + 1);
115 1.1 christos
116 1.1 christos argv[argc] = NULL;
117 1.1 christos while (1)
118 1.1 christos {
119 1.1 christos char *arg;
120 1.1 christos
121 1.1 christos /* Skip leading white space. */
122 1.8 christos chp = skip_spaces (chp);
123 1.1 christos /* Three possibilities: EOF, quoted string, or other text. */
124 1.1 christos switch (*chp)
125 1.1 christos {
126 1.1 christos case '\0':
127 1.1 christos parse->argv = argv;
128 1.1 christos parse->argc = argc;
129 1.1 christos return;
130 1.1 christos case '"':
131 1.1 christos {
132 1.1 christos /* A quoted string. */
133 1.1 christos int len;
134 1.1 christos const char *start = chp + 1;
135 1.1 christos
136 1.1 christos /* Determine the buffer size. */
137 1.1 christos chp = start;
138 1.1 christos len = 0;
139 1.1 christos while (*chp != '\0' && *chp != '"')
140 1.1 christos {
141 1.1 christos if (*chp == '\\')
142 1.1 christos {
143 1.1 christos chp++;
144 1.1 christos if (mi_parse_escape (&chp) <= 0)
145 1.1 christos {
146 1.1 christos /* Do not allow split lines or "\000". */
147 1.1 christos freeargv (argv);
148 1.1 christos return;
149 1.1 christos }
150 1.1 christos }
151 1.1 christos else
152 1.1 christos chp++;
153 1.1 christos len++;
154 1.1 christos }
155 1.1 christos /* Insist on a closing quote. */
156 1.1 christos if (*chp != '"')
157 1.1 christos {
158 1.1 christos freeargv (argv);
159 1.1 christos return;
160 1.1 christos }
161 1.1 christos /* Insist on trailing white space. */
162 1.1 christos if (chp[1] != '\0' && !isspace (chp[1]))
163 1.1 christos {
164 1.1 christos freeargv (argv);
165 1.1 christos return;
166 1.1 christos }
167 1.1 christos /* Create the buffer and copy characters in. */
168 1.6 christos arg = XNEWVEC (char, len + 1);
169 1.1 christos chp = start;
170 1.1 christos len = 0;
171 1.1 christos while (*chp != '\0' && *chp != '"')
172 1.1 christos {
173 1.1 christos if (*chp == '\\')
174 1.1 christos {
175 1.1 christos chp++;
176 1.1 christos arg[len] = mi_parse_escape (&chp);
177 1.1 christos }
178 1.1 christos else
179 1.1 christos arg[len] = *chp++;
180 1.1 christos len++;
181 1.1 christos }
182 1.1 christos arg[len] = '\0';
183 1.1 christos chp++; /* That closing quote. */
184 1.1 christos break;
185 1.1 christos }
186 1.1 christos default:
187 1.1 christos {
188 1.1 christos /* An unquoted string. Accumulate all non-blank
189 1.1 christos characters into a buffer. */
190 1.1 christos int len;
191 1.1 christos const char *start = chp;
192 1.1 christos
193 1.1 christos while (*chp != '\0' && !isspace (*chp))
194 1.1 christos {
195 1.1 christos chp++;
196 1.1 christos }
197 1.1 christos len = chp - start;
198 1.6 christos arg = XNEWVEC (char, len + 1);
199 1.1 christos strncpy (arg, start, len);
200 1.1 christos arg[len] = '\0';
201 1.1 christos break;
202 1.1 christos }
203 1.1 christos }
204 1.1 christos /* Append arg to argv. */
205 1.6 christos argv = XRESIZEVEC (char *, argv, argc + 2);
206 1.1 christos argv[argc++] = arg;
207 1.1 christos argv[argc] = NULL;
208 1.1 christos }
209 1.1 christos }
210 1.1 christos
211 1.7 christos mi_parse::mi_parse ()
212 1.7 christos : op (MI_COMMAND),
213 1.7 christos command (NULL),
214 1.7 christos token (NULL),
215 1.7 christos cmd (NULL),
216 1.7 christos cmd_start (NULL),
217 1.7 christos args (NULL),
218 1.7 christos argv (NULL),
219 1.7 christos argc (0),
220 1.7 christos all (0),
221 1.7 christos thread_group (-1),
222 1.7 christos thread (-1),
223 1.7 christos frame (-1),
224 1.7 christos language (language_unknown)
225 1.1 christos {
226 1.1 christos }
227 1.1 christos
228 1.7 christos mi_parse::~mi_parse ()
229 1.1 christos {
230 1.7 christos xfree (command);
231 1.7 christos xfree (token);
232 1.7 christos xfree (args);
233 1.7 christos freeargv (argv);
234 1.1 christos }
235 1.1 christos
236 1.7 christos std::unique_ptr<struct mi_parse>
237 1.1 christos mi_parse (const char *cmd, char **token)
238 1.1 christos {
239 1.1 christos const char *chp;
240 1.1 christos
241 1.7 christos std::unique_ptr<struct mi_parse> parse (new struct mi_parse);
242 1.1 christos
243 1.1 christos /* Before starting, skip leading white space. */
244 1.8 christos cmd = skip_spaces (cmd);
245 1.1 christos
246 1.1 christos /* Find/skip any token and then extract it. */
247 1.1 christos for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
248 1.1 christos ;
249 1.6 christos *token = (char *) xmalloc (chp - cmd + 1);
250 1.1 christos memcpy (*token, cmd, (chp - cmd));
251 1.1 christos (*token)[chp - cmd] = '\0';
252 1.1 christos
253 1.1 christos /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
254 1.1 christos if (*chp != '-')
255 1.1 christos {
256 1.8 christos chp = skip_spaces (chp);
257 1.1 christos parse->command = xstrdup (chp);
258 1.1 christos parse->op = CLI_COMMAND;
259 1.1 christos
260 1.1 christos return parse;
261 1.1 christos }
262 1.1 christos
263 1.1 christos /* Extract the command. */
264 1.1 christos {
265 1.1 christos const char *tmp = chp + 1; /* discard ``-'' */
266 1.1 christos
267 1.1 christos for (; *chp && !isspace (*chp); chp++)
268 1.1 christos ;
269 1.6 christos parse->command = (char *) xmalloc (chp - tmp + 1);
270 1.1 christos memcpy (parse->command, tmp, chp - tmp);
271 1.1 christos parse->command[chp - tmp] = '\0';
272 1.1 christos }
273 1.1 christos
274 1.1 christos /* Find the command in the MI table. */
275 1.1 christos parse->cmd = mi_lookup (parse->command);
276 1.1 christos if (parse->cmd == NULL)
277 1.1 christos throw_error (UNDEFINED_COMMAND_ERROR,
278 1.1 christos _("Undefined MI command: %s"), parse->command);
279 1.1 christos
280 1.1 christos /* Skip white space following the command. */
281 1.8 christos chp = skip_spaces (chp);
282 1.1 christos
283 1.1 christos /* Parse the --thread and --frame options, if present. At present,
284 1.1 christos some important commands, like '-break-*' are implemented by
285 1.1 christos forwarding to the CLI layer directly. We want to parse --thread
286 1.1 christos and --frame here, so as not to leave those option in the string
287 1.1 christos that will be passed to CLI.
288 1.1 christos
289 1.1 christos Same for the --language option. */
290 1.1 christos
291 1.1 christos for (;;)
292 1.1 christos {
293 1.1 christos const char *option;
294 1.1 christos size_t as = sizeof ("--all ") - 1;
295 1.1 christos size_t tgs = sizeof ("--thread-group ") - 1;
296 1.1 christos size_t ts = sizeof ("--thread ") - 1;
297 1.1 christos size_t fs = sizeof ("--frame ") - 1;
298 1.1 christos size_t ls = sizeof ("--language ") - 1;
299 1.1 christos
300 1.1 christos if (strncmp (chp, "--all ", as) == 0)
301 1.1 christos {
302 1.1 christos parse->all = 1;
303 1.1 christos chp += as;
304 1.1 christos }
305 1.1 christos /* See if --all is the last token in the input. */
306 1.1 christos if (strcmp (chp, "--all") == 0)
307 1.1 christos {
308 1.1 christos parse->all = 1;
309 1.1 christos chp += strlen (chp);
310 1.1 christos }
311 1.1 christos if (strncmp (chp, "--thread-group ", tgs) == 0)
312 1.1 christos {
313 1.1 christos char *endp;
314 1.1 christos
315 1.1 christos option = "--thread-group";
316 1.1 christos if (parse->thread_group != -1)
317 1.1 christos error (_("Duplicate '--thread-group' option"));
318 1.1 christos chp += tgs;
319 1.1 christos if (*chp != 'i')
320 1.1 christos error (_("Invalid thread group id"));
321 1.1 christos chp += 1;
322 1.1 christos parse->thread_group = strtol (chp, &endp, 10);
323 1.1 christos chp = endp;
324 1.1 christos }
325 1.1 christos else if (strncmp (chp, "--thread ", ts) == 0)
326 1.1 christos {
327 1.1 christos char *endp;
328 1.1 christos
329 1.1 christos option = "--thread";
330 1.1 christos if (parse->thread != -1)
331 1.1 christos error (_("Duplicate '--thread' option"));
332 1.1 christos chp += ts;
333 1.1 christos parse->thread = strtol (chp, &endp, 10);
334 1.1 christos chp = endp;
335 1.1 christos }
336 1.1 christos else if (strncmp (chp, "--frame ", fs) == 0)
337 1.1 christos {
338 1.1 christos char *endp;
339 1.1 christos
340 1.1 christos option = "--frame";
341 1.1 christos if (parse->frame != -1)
342 1.1 christos error (_("Duplicate '--frame' option"));
343 1.1 christos chp += fs;
344 1.1 christos parse->frame = strtol (chp, &endp, 10);
345 1.1 christos chp = endp;
346 1.1 christos }
347 1.1 christos else if (strncmp (chp, "--language ", ls) == 0)
348 1.1 christos {
349 1.1 christos option = "--language";
350 1.1 christos chp += ls;
351 1.8 christos std::string lang_name = extract_arg (&chp);
352 1.1 christos
353 1.8 christos parse->language = language_enum (lang_name.c_str ());
354 1.1 christos if (parse->language == language_unknown
355 1.1 christos || parse->language == language_auto)
356 1.8 christos error (_("Invalid --language argument: %s"), lang_name.c_str ());
357 1.1 christos }
358 1.1 christos else
359 1.1 christos break;
360 1.1 christos
361 1.1 christos if (*chp != '\0' && !isspace (*chp))
362 1.1 christos error (_("Invalid value for the '%s' option"), option);
363 1.8 christos chp = skip_spaces (chp);
364 1.1 christos }
365 1.1 christos
366 1.1 christos /* For new argv commands, attempt to return the parsed argument
367 1.1 christos list. */
368 1.1 christos if (parse->cmd->argv_func != NULL)
369 1.1 christos {
370 1.7 christos mi_parse_argv (chp, parse.get ());
371 1.1 christos if (parse->argv == NULL)
372 1.1 christos error (_("Problem parsing arguments: %s %s"), parse->command, chp);
373 1.1 christos }
374 1.1 christos
375 1.1 christos /* FIXME: DELETE THIS */
376 1.1 christos /* For CLI commands, also return the remainder of the
377 1.1 christos command line as a single string. */
378 1.1 christos if (parse->cmd->cli.cmd != NULL)
379 1.1 christos parse->args = xstrdup (chp);
380 1.1 christos
381 1.1 christos /* Fully parsed, flag as an MI command. */
382 1.1 christos parse->op = MI_COMMAND;
383 1.1 christos return parse;
384 1.1 christos }
385 1.1 christos
386 1.1 christos enum print_values
387 1.1 christos mi_parse_print_values (const char *name)
388 1.1 christos {
389 1.1 christos if (strcmp (name, "0") == 0
390 1.1 christos || strcmp (name, mi_no_values) == 0)
391 1.1 christos return PRINT_NO_VALUES;
392 1.1 christos else if (strcmp (name, "1") == 0
393 1.1 christos || strcmp (name, mi_all_values) == 0)
394 1.1 christos return PRINT_ALL_VALUES;
395 1.1 christos else if (strcmp (name, "2") == 0
396 1.1 christos || strcmp (name, mi_simple_values) == 0)
397 1.1 christos return PRINT_SIMPLE_VALUES;
398 1.1 christos else
399 1.1 christos error (_("Unknown value for PRINT_VALUES: must be: \
400 1.1 christos 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
401 1.1 christos mi_no_values, mi_all_values, mi_simple_values);
402 1.1 christos }
403