* config/tc-z80.c (md_apply_fix): Rename var to fix shadow warning.
[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
305aeedc
TT
226/* A cleanup that calls mi_parse_free. */
227
228static void
229mi_parse_cleanup (void *arg)
230{
231 mi_parse_free (arg);
232}
fb40c209
AC
233
234struct mi_parse *
305aeedc 235mi_parse (char *cmd, char **token)
fb40c209
AC
236{
237 char *chp;
238 struct mi_parse *parse = XMALLOC (struct mi_parse);
305aeedc 239 struct cleanup *cleanup;
102040f0 240
fb40c209 241 memset (parse, 0, sizeof (*parse));
a79b8f6e
VP
242 parse->all = 0;
243 parse->thread_group = -1;
1e92afda
VP
244 parse->thread = -1;
245 parse->frame = -1;
fb40c209 246
305aeedc
TT
247 cleanup = make_cleanup (mi_parse_cleanup, parse);
248
fb40c209
AC
249 /* Before starting, skip leading white space. */
250 while (isspace (*cmd))
251 cmd++;
252
253 /* Find/skip any token and then extract it. */
254 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
255 ;
305aeedc
TT
256 *token = xmalloc ((chp - cmd + 1) * sizeof (char *));
257 memcpy (*token, cmd, (chp - cmd));
258 (*token)[chp - cmd] = '\0';
fb40c209
AC
259
260 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
261 if (*chp != '-')
262 {
263 while (isspace (*chp))
264 chp++;
265 parse->command = xstrdup (chp);
266 parse->op = CLI_COMMAND;
305aeedc
TT
267
268 discard_cleanups (cleanup);
269
fb40c209
AC
270 return parse;
271 }
272
273 /* Extract the command. */
274 {
275 char *tmp = chp + 1; /* discard ``-'' */
102040f0 276
fb40c209
AC
277 for (; *chp && !isspace (*chp); chp++)
278 ;
279 parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *));
280 memcpy (parse->command, tmp, chp - tmp);
281 parse->command[chp - tmp] = '\0';
282 }
283
284 /* Find the command in the MI table. */
285 parse->cmd = mi_lookup (parse->command);
286 if (parse->cmd == NULL)
305aeedc 287 error (_("Undefined MI command: %s"), parse->command);
fb40c209
AC
288
289 /* Skip white space following the command. */
290 while (isspace (*chp))
291 chp++;
292
1e92afda
VP
293 /* Parse the --thread and --frame options, if present. At present,
294 some important commands, like '-break-*' are implemented by forwarding
295 to the CLI layer directly. We want to parse --thread and --frame
296 here, so as not to leave those option in the string that will be passed
297 to CLI. */
298 for (;;)
299 {
300 char *start = chp;
a79b8f6e
VP
301 size_t as = sizeof ("--all ") - 1;
302 size_t tgs = sizeof ("--thread-group ") - 1;
1e92afda
VP
303 size_t ts = sizeof ("--thread ") - 1;
304 size_t fs = sizeof ("--frame ") - 1;
102040f0 305
a79b8f6e
VP
306 if (strncmp (chp, "--all ", as) == 0)
307 {
308 parse->all = 1;
309 chp += as;
310 }
311 /* See if --all is the last token in the input. */
312 if (strcmp (chp, "--all") == 0)
313 {
314 parse->all = 1;
315 chp += strlen (chp);
316 }
317 if (strncmp (chp, "--thread-group ", tgs) == 0)
318 {
319 if (parse->thread_group != -1)
320 error (_("Duplicate '--thread-group' option"));
321 chp += tgs;
322 if (*chp != 'i')
323 error (_("Invalid thread group id"));
324 chp += 1;
325 parse->thread_group = strtol (chp, &chp, 10);
326 }
8e0e408a 327 else if (strncmp (chp, "--thread ", ts) == 0)
1e92afda
VP
328 {
329 if (parse->thread != -1)
a79b8f6e 330 error (_("Duplicate '--thread' option"));
1e92afda
VP
331 chp += ts;
332 parse->thread = strtol (chp, &chp, 10);
333 }
334 else if (strncmp (chp, "--frame ", fs) == 0)
335 {
336 if (parse->frame != -1)
a79b8f6e 337 error (_("Duplicate '--frame' option"));
1e92afda
VP
338 chp += fs;
339 parse->frame = strtol (chp, &chp, 10);
340 }
341 else
342 break;
343
344 if (*chp != '\0' && !isspace (*chp))
a79b8f6e 345 error (_("Invalid value for the '%s' option"),
1e92afda
VP
346 start[2] == 't' ? "--thread" : "--frame");
347 while (isspace (*chp))
348 chp++;
349 }
350
fb40c209
AC
351 /* For new argv commands, attempt to return the parsed argument
352 list. */
353 if (parse->cmd->argv_func != NULL)
354 {
355 mi_parse_argv (chp, parse);
356 if (parse->argv == NULL)
305aeedc 357 error (_("Problem parsing arguments: %s %s"), parse->command, chp);
fb40c209
AC
358 }
359
360 /* FIXME: DELETE THIS */
9e22b03a 361 /* For CLI commands, also return the remainder of the
fb40c209 362 command line as a single string. */
9e22b03a
VP
363 if (parse->cmd->cli.cmd != NULL)
364 parse->args = xstrdup (chp);
fb40c209 365
305aeedc
TT
366 discard_cleanups (cleanup);
367
fb40c209
AC
368 /* Fully parsed. */
369 parse->op = MI_COMMAND;
370 return parse;
371}
This page took 0.920721 seconds and 4 git commands to generate.