Check in for PR other/46020 was meant for PR other/46026.
[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)++;
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
AC
105static void
106mi_parse_argv (char *args, struct mi_parse *parse)
107{
108 char *chp = args;
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
fb40c209
AC
117 /* skip leading white space */
118 while (isspace (*chp))
119 chp++;
120 /* Three possibilities: EOF, quoted string, or other text. */
121 switch (*chp)
122 {
123 case '\0':
124 parse->argv = argv;
125 parse->argc = argc;
126 return;
127 case '"':
128 {
129 /* A quoted string. */
130 int len;
131 char *start = chp + 1;
102040f0 132
fb40c209
AC
133 /* Determine the buffer size. */
134 chp = start;
135 len = 0;
136 while (*chp != '\0' && *chp != '"')
137 {
138 if (*chp == '\\')
139 {
140 chp++;
f870a310 141 if (mi_parse_escape (&chp) <= 0)
fb40c209
AC
142 {
143 /* Do not allow split lines or "\000" */
144 freeargv (argv);
145 return;
146 }
147 }
148 else
149 chp++;
150 len++;
151 }
152 /* Insist on a closing quote. */
153 if (*chp != '"')
154 {
155 freeargv (argv);
156 return;
157 }
158 /* Insist on trailing white space. */
159 if (chp[1] != '\0' && !isspace (chp[1]))
160 {
161 freeargv (argv);
162 return;
163 }
164 /* create the buffer. */
165 arg = xmalloc ((len + 1) * sizeof (char));
166 /* And copy the characters in. */
167 chp = start;
168 len = 0;
169 while (*chp != '\0' && *chp != '"')
170 {
171 if (*chp == '\\')
172 {
173 chp++;
f870a310 174 arg[len] = mi_parse_escape (&chp);
fb40c209
AC
175 }
176 else
177 arg[len] = *chp++;
178 len++;
179 }
180 arg[len] = '\0';
181 chp++; /* that closing quote. */
182 break;
183 }
184 default:
185 {
186 /* An unquoted string. Accumulate all non blank
187 characters into a buffer. */
188 int len;
189 char *start = chp;
102040f0 190
fb40c209
AC
191 while (*chp != '\0' && !isspace (*chp))
192 {
193 chp++;
194 }
195 len = chp - start;
196 arg = xmalloc ((len + 1) * sizeof (char));
197 strncpy (arg, start, len);
198 arg[len] = '\0';
199 break;
200 }
201 }
202 /* Append arg to argv. */
203 argv = xrealloc (argv, (argc + 2) * sizeof (char *));
204 argv[argc++] = arg;
205 argv[argc] = NULL;
206 }
207}
208
209
210void
211mi_parse_free (struct mi_parse *parse)
212{
213 if (parse == NULL)
214 return;
215 if (parse->command != NULL)
b8c9b27d 216 xfree (parse->command);
fb40c209 217 if (parse->token != NULL)
b8c9b27d 218 xfree (parse->token);
fb40c209 219 if (parse->args != NULL)
b8c9b27d 220 xfree (parse->args);
fb40c209
AC
221 if (parse->argv != NULL)
222 freeargv (parse->argv);
b8c9b27d 223 xfree (parse);
fb40c209
AC
224}
225
226
227struct mi_parse *
228mi_parse (char *cmd)
229{
230 char *chp;
231 struct mi_parse *parse = XMALLOC (struct mi_parse);
102040f0 232
fb40c209 233 memset (parse, 0, sizeof (*parse));
a79b8f6e
VP
234 parse->all = 0;
235 parse->thread_group = -1;
1e92afda
VP
236 parse->thread = -1;
237 parse->frame = -1;
fb40c209
AC
238
239 /* Before starting, skip leading white space. */
240 while (isspace (*cmd))
241 cmd++;
242
243 /* Find/skip any token and then extract it. */
244 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
245 ;
246 parse->token = xmalloc ((chp - cmd + 1) * sizeof (char *));
247 memcpy (parse->token, cmd, (chp - cmd));
248 parse->token[chp - cmd] = '\0';
249
250 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
251 if (*chp != '-')
252 {
253 while (isspace (*chp))
254 chp++;
255 parse->command = xstrdup (chp);
256 parse->op = CLI_COMMAND;
257 return parse;
258 }
259
260 /* Extract the command. */
261 {
262 char *tmp = chp + 1; /* discard ``-'' */
102040f0 263
fb40c209
AC
264 for (; *chp && !isspace (*chp); chp++)
265 ;
266 parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *));
267 memcpy (parse->command, tmp, chp - tmp);
268 parse->command[chp - tmp] = '\0';
269 }
270
271 /* Find the command in the MI table. */
272 parse->cmd = mi_lookup (parse->command);
273 if (parse->cmd == NULL)
274 {
275 /* FIXME: This should be a function call. */
276 fprintf_unfiltered
277 (raw_stdout,
278 "%s^error,msg=\"Undefined MI command: %s\"\n",
279 parse->token, parse->command);
280 mi_parse_free (parse);
281 return NULL;
282 }
283
284 /* Skip white space following the command. */
285 while (isspace (*chp))
286 chp++;
287
1e92afda
VP
288 /* Parse the --thread and --frame options, if present. At present,
289 some important commands, like '-break-*' are implemented by forwarding
290 to the CLI layer directly. We want to parse --thread and --frame
291 here, so as not to leave those option in the string that will be passed
292 to CLI. */
293 for (;;)
294 {
295 char *start = chp;
a79b8f6e
VP
296 size_t as = sizeof ("--all ") - 1;
297 size_t tgs = sizeof ("--thread-group ") - 1;
1e92afda
VP
298 size_t ts = sizeof ("--thread ") - 1;
299 size_t fs = sizeof ("--frame ") - 1;
102040f0 300
a79b8f6e
VP
301 if (strncmp (chp, "--all ", as) == 0)
302 {
303 parse->all = 1;
304 chp += as;
305 }
306 /* See if --all is the last token in the input. */
307 if (strcmp (chp, "--all") == 0)
308 {
309 parse->all = 1;
310 chp += strlen (chp);
311 }
312 if (strncmp (chp, "--thread-group ", tgs) == 0)
313 {
314 if (parse->thread_group != -1)
315 error (_("Duplicate '--thread-group' option"));
316 chp += tgs;
317 if (*chp != 'i')
318 error (_("Invalid thread group id"));
319 chp += 1;
320 parse->thread_group = strtol (chp, &chp, 10);
321 }
1e92afda
VP
322 if (strncmp (chp, "--thread ", ts) == 0)
323 {
324 if (parse->thread != -1)
a79b8f6e 325 error (_("Duplicate '--thread' option"));
1e92afda
VP
326 chp += ts;
327 parse->thread = strtol (chp, &chp, 10);
328 }
329 else if (strncmp (chp, "--frame ", fs) == 0)
330 {
331 if (parse->frame != -1)
a79b8f6e 332 error (_("Duplicate '--frame' option"));
1e92afda
VP
333 chp += fs;
334 parse->frame = strtol (chp, &chp, 10);
335 }
336 else
337 break;
338
339 if (*chp != '\0' && !isspace (*chp))
a79b8f6e 340 error (_("Invalid value for the '%s' option"),
1e92afda
VP
341 start[2] == 't' ? "--thread" : "--frame");
342 while (isspace (*chp))
343 chp++;
344 }
345
fb40c209
AC
346 /* For new argv commands, attempt to return the parsed argument
347 list. */
348 if (parse->cmd->argv_func != NULL)
349 {
350 mi_parse_argv (chp, parse);
351 if (parse->argv == NULL)
352 {
353 /* FIXME: This should be a function call. */
354 fprintf_unfiltered
355 (raw_stdout,
356 "%s^error,msg=\"Problem parsing arguments: %s %s\"\n",
357 parse->token, parse->command, chp);
358 mi_parse_free (parse);
359 return NULL;
360 }
361 }
362
363 /* FIXME: DELETE THIS */
9e22b03a 364 /* For CLI commands, also return the remainder of the
fb40c209 365 command line as a single string. */
9e22b03a
VP
366 if (parse->cmd->cli.cmd != NULL)
367 parse->args = xstrdup (chp);
fb40c209
AC
368
369 /* Fully parsed. */
370 parse->op = MI_COMMAND;
371 return parse;
372}
This page took 1.26306 seconds and 4 git commands to generate.