mi-parse.c revision 1.6 1 1.1 christos /* MI Command Set - MI parser.
2 1.1 christos
3 1.6 christos Copyright (C) 2000-2016 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.1 christos chp = skip_spaces_const (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.1 christos void
212 1.1 christos mi_parse_free (struct mi_parse *parse)
213 1.1 christos {
214 1.1 christos if (parse == NULL)
215 1.1 christos return;
216 1.1 christos if (parse->command != NULL)
217 1.1 christos xfree (parse->command);
218 1.1 christos if (parse->token != NULL)
219 1.1 christos xfree (parse->token);
220 1.1 christos if (parse->args != NULL)
221 1.1 christos xfree (parse->args);
222 1.1 christos if (parse->argv != NULL)
223 1.1 christos freeargv (parse->argv);
224 1.1 christos xfree (parse);
225 1.1 christos }
226 1.1 christos
227 1.1 christos /* A cleanup that calls mi_parse_free. */
228 1.1 christos
229 1.1 christos static void
230 1.1 christos mi_parse_cleanup (void *arg)
231 1.1 christos {
232 1.6 christos mi_parse_free ((struct mi_parse *) arg);
233 1.1 christos }
234 1.1 christos
235 1.1 christos struct mi_parse *
236 1.1 christos mi_parse (const char *cmd, char **token)
237 1.1 christos {
238 1.1 christos const char *chp;
239 1.3 christos struct mi_parse *parse = XNEW (struct mi_parse);
240 1.1 christos struct cleanup *cleanup;
241 1.1 christos
242 1.1 christos memset (parse, 0, sizeof (*parse));
243 1.1 christos parse->all = 0;
244 1.1 christos parse->thread_group = -1;
245 1.1 christos parse->thread = -1;
246 1.1 christos parse->frame = -1;
247 1.1 christos parse->language = language_unknown;
248 1.1 christos
249 1.1 christos cleanup = make_cleanup (mi_parse_cleanup, parse);
250 1.1 christos
251 1.1 christos /* Before starting, skip leading white space. */
252 1.1 christos cmd = skip_spaces_const (cmd);
253 1.1 christos
254 1.1 christos /* Find/skip any token and then extract it. */
255 1.1 christos for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
256 1.1 christos ;
257 1.6 christos *token = (char *) xmalloc (chp - cmd + 1);
258 1.1 christos memcpy (*token, cmd, (chp - cmd));
259 1.1 christos (*token)[chp - cmd] = '\0';
260 1.1 christos
261 1.1 christos /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
262 1.1 christos if (*chp != '-')
263 1.1 christos {
264 1.1 christos chp = skip_spaces_const (chp);
265 1.1 christos parse->command = xstrdup (chp);
266 1.1 christos parse->op = CLI_COMMAND;
267 1.1 christos
268 1.1 christos discard_cleanups (cleanup);
269 1.1 christos
270 1.1 christos return parse;
271 1.1 christos }
272 1.1 christos
273 1.1 christos /* Extract the command. */
274 1.1 christos {
275 1.1 christos const char *tmp = chp + 1; /* discard ``-'' */
276 1.1 christos
277 1.1 christos for (; *chp && !isspace (*chp); chp++)
278 1.1 christos ;
279 1.6 christos parse->command = (char *) xmalloc (chp - tmp + 1);
280 1.1 christos memcpy (parse->command, tmp, chp - tmp);
281 1.1 christos parse->command[chp - tmp] = '\0';
282 1.1 christos }
283 1.1 christos
284 1.1 christos /* Find the command in the MI table. */
285 1.1 christos parse->cmd = mi_lookup (parse->command);
286 1.1 christos if (parse->cmd == NULL)
287 1.1 christos throw_error (UNDEFINED_COMMAND_ERROR,
288 1.1 christos _("Undefined MI command: %s"), parse->command);
289 1.1 christos
290 1.1 christos /* Skip white space following the command. */
291 1.1 christos chp = skip_spaces_const (chp);
292 1.1 christos
293 1.1 christos /* Parse the --thread and --frame options, if present. At present,
294 1.1 christos some important commands, like '-break-*' are implemented by
295 1.1 christos forwarding to the CLI layer directly. We want to parse --thread
296 1.1 christos and --frame here, so as not to leave those option in the string
297 1.1 christos that will be passed to CLI.
298 1.1 christos
299 1.1 christos Same for the --language option. */
300 1.1 christos
301 1.1 christos for (;;)
302 1.1 christos {
303 1.1 christos const char *option;
304 1.1 christos size_t as = sizeof ("--all ") - 1;
305 1.1 christos size_t tgs = sizeof ("--thread-group ") - 1;
306 1.1 christos size_t ts = sizeof ("--thread ") - 1;
307 1.1 christos size_t fs = sizeof ("--frame ") - 1;
308 1.1 christos size_t ls = sizeof ("--language ") - 1;
309 1.1 christos
310 1.1 christos if (strncmp (chp, "--all ", as) == 0)
311 1.1 christos {
312 1.1 christos parse->all = 1;
313 1.1 christos chp += as;
314 1.1 christos }
315 1.1 christos /* See if --all is the last token in the input. */
316 1.1 christos if (strcmp (chp, "--all") == 0)
317 1.1 christos {
318 1.1 christos parse->all = 1;
319 1.1 christos chp += strlen (chp);
320 1.1 christos }
321 1.1 christos if (strncmp (chp, "--thread-group ", tgs) == 0)
322 1.1 christos {
323 1.1 christos char *endp;
324 1.1 christos
325 1.1 christos option = "--thread-group";
326 1.1 christos if (parse->thread_group != -1)
327 1.1 christos error (_("Duplicate '--thread-group' option"));
328 1.1 christos chp += tgs;
329 1.1 christos if (*chp != 'i')
330 1.1 christos error (_("Invalid thread group id"));
331 1.1 christos chp += 1;
332 1.1 christos parse->thread_group = strtol (chp, &endp, 10);
333 1.1 christos chp = endp;
334 1.1 christos }
335 1.1 christos else if (strncmp (chp, "--thread ", ts) == 0)
336 1.1 christos {
337 1.1 christos char *endp;
338 1.1 christos
339 1.1 christos option = "--thread";
340 1.1 christos if (parse->thread != -1)
341 1.1 christos error (_("Duplicate '--thread' option"));
342 1.1 christos chp += ts;
343 1.1 christos parse->thread = strtol (chp, &endp, 10);
344 1.1 christos chp = endp;
345 1.1 christos }
346 1.1 christos else if (strncmp (chp, "--frame ", fs) == 0)
347 1.1 christos {
348 1.1 christos char *endp;
349 1.1 christos
350 1.1 christos option = "--frame";
351 1.1 christos if (parse->frame != -1)
352 1.1 christos error (_("Duplicate '--frame' option"));
353 1.1 christos chp += fs;
354 1.1 christos parse->frame = strtol (chp, &endp, 10);
355 1.1 christos chp = endp;
356 1.1 christos }
357 1.1 christos else if (strncmp (chp, "--language ", ls) == 0)
358 1.1 christos {
359 1.1 christos char *lang_name;
360 1.1 christos struct cleanup *old_chain;
361 1.1 christos
362 1.1 christos option = "--language";
363 1.1 christos chp += ls;
364 1.1 christos lang_name = extract_arg_const (&chp);
365 1.1 christos old_chain = make_cleanup (xfree, lang_name);
366 1.1 christos
367 1.1 christos parse->language = language_enum (lang_name);
368 1.1 christos if (parse->language == language_unknown
369 1.1 christos || parse->language == language_auto)
370 1.1 christos error (_("Invalid --language argument: %s"), lang_name);
371 1.1 christos
372 1.1 christos do_cleanups (old_chain);
373 1.1 christos }
374 1.1 christos else
375 1.1 christos break;
376 1.1 christos
377 1.1 christos if (*chp != '\0' && !isspace (*chp))
378 1.1 christos error (_("Invalid value for the '%s' option"), option);
379 1.1 christos chp = skip_spaces_const (chp);
380 1.1 christos }
381 1.1 christos
382 1.1 christos /* For new argv commands, attempt to return the parsed argument
383 1.1 christos list. */
384 1.1 christos if (parse->cmd->argv_func != NULL)
385 1.1 christos {
386 1.1 christos mi_parse_argv (chp, parse);
387 1.1 christos if (parse->argv == NULL)
388 1.1 christos error (_("Problem parsing arguments: %s %s"), parse->command, chp);
389 1.1 christos }
390 1.1 christos
391 1.1 christos /* FIXME: DELETE THIS */
392 1.1 christos /* For CLI commands, also return the remainder of the
393 1.1 christos command line as a single string. */
394 1.1 christos if (parse->cmd->cli.cmd != NULL)
395 1.1 christos parse->args = xstrdup (chp);
396 1.1 christos
397 1.1 christos discard_cleanups (cleanup);
398 1.1 christos
399 1.1 christos /* Fully parsed, flag as an MI command. */
400 1.1 christos parse->op = MI_COMMAND;
401 1.1 christos return parse;
402 1.1 christos }
403 1.1 christos
404 1.1 christos enum print_values
405 1.1 christos mi_parse_print_values (const char *name)
406 1.1 christos {
407 1.1 christos if (strcmp (name, "0") == 0
408 1.1 christos || strcmp (name, mi_no_values) == 0)
409 1.1 christos return PRINT_NO_VALUES;
410 1.1 christos else if (strcmp (name, "1") == 0
411 1.1 christos || strcmp (name, mi_all_values) == 0)
412 1.1 christos return PRINT_ALL_VALUES;
413 1.1 christos else if (strcmp (name, "2") == 0
414 1.1 christos || strcmp (name, mi_simple_values) == 0)
415 1.1 christos return PRINT_SIMPLE_VALUES;
416 1.1 christos else
417 1.1 christos error (_("Unknown value for PRINT_VALUES: must be: \
418 1.1 christos 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
419 1.1 christos mi_no_values, mi_all_values, mi_simple_values);
420 1.1 christos }
421