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