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