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