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