Update years in copyright notice for the GDB files.
[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"
fb40c209 29
f870a310
TT
30/* Like parse_escape, but leave the results as a host char, not a
31 target char. */
32
33static int
34mi_parse_escape (char **string_ptr)
35{
36 int c = *(*string_ptr)++;
102040f0 37
f870a310
TT
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;
102040f0 57
f870a310
TT
58 while (++count < 3)
59 {
60 c = (**string_ptr);
61 if (isdigit (c) && c != '8' && c != '9')
62 {
63 (*string_ptr)++;
64 i *= 8;
65 i += host_hex_value (c);
66 }
67 else
68 {
69 break;
70 }
71 }
72 return i;
73 }
74
75 case 'a':
76 c = '\a';
77 break;
78 case 'b':
79 c = '\b';
80 break;
81 case 'f':
82 c = '\f';
83 break;
84 case 'n':
85 c = '\n';
86 break;
87 case 'r':
88 c = '\r';
89 break;
90 case 't':
91 c = '\t';
92 break;
93 case 'v':
94 c = '\v';
95 break;
96
97 default:
98 break;
99 }
100
101 return c;
102}
103
fb40c209
AC
104static void
105mi_parse_argv (char *args, struct mi_parse *parse)
106{
107 char *chp = args;
108 int argc = 0;
109 char **argv = xmalloc ((argc + 1) * sizeof (char *));
102040f0 110
fb40c209
AC
111 argv[argc] = NULL;
112 while (1)
113 {
114 char *arg;
102040f0 115
2b03b41d 116 /* Skip leading white space. */
fb40c209
AC
117 while (isspace (*chp))
118 chp++;
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
AC
129 int len;
130 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
AC
186 int len;
187 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 *
305aeedc 232mi_parse (char *cmd, char **token)
fb40c209
AC
233{
234 char *chp;
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. */
fb40c209
AC
247 while (isspace (*cmd))
248 cmd++;
249
2b03b41d 250 /* Find/skip any token and then extract it. */
fb40c209
AC
251 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
252 ;
38a714bb 253 *token = xmalloc (chp - cmd + 1);
305aeedc
TT
254 memcpy (*token, cmd, (chp - cmd));
255 (*token)[chp - cmd] = '\0';
fb40c209 256
2b03b41d 257 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
fb40c209
AC
258 if (*chp != '-')
259 {
260 while (isspace (*chp))
261 chp++;
262 parse->command = xstrdup (chp);
263 parse->op = CLI_COMMAND;
305aeedc
TT
264
265 discard_cleanups (cleanup);
266
fb40c209
AC
267 return parse;
268 }
269
2b03b41d 270 /* Extract the command. */
fb40c209
AC
271 {
272 char *tmp = chp + 1; /* discard ``-'' */
102040f0 273
fb40c209
AC
274 for (; *chp && !isspace (*chp); chp++)
275 ;
38a714bb 276 parse->command = xmalloc (chp - tmp + 1);
fb40c209
AC
277 memcpy (parse->command, tmp, chp - tmp);
278 parse->command[chp - tmp] = '\0';
279 }
280
2b03b41d 281 /* Find the command in the MI table. */
fb40c209
AC
282 parse->cmd = mi_lookup (parse->command);
283 if (parse->cmd == NULL)
305aeedc 284 error (_("Undefined MI command: %s"), parse->command);
fb40c209 285
2b03b41d 286 /* Skip white space following the command. */
fb40c209
AC
287 while (isspace (*chp))
288 chp++;
289
1e92afda 290 /* Parse the --thread and --frame options, if present. At present,
2b03b41d
SS
291 some important commands, like '-break-*' are implemented by
292 forwarding to the CLI layer directly. We want to parse --thread
293 and --frame here, so as not to leave those option in the string
294 that will be passed to CLI. */
1e92afda
VP
295 for (;;)
296 {
30a7f059 297 const char *option;
a79b8f6e
VP
298 size_t as = sizeof ("--all ") - 1;
299 size_t tgs = sizeof ("--thread-group ") - 1;
1e92afda
VP
300 size_t ts = sizeof ("--thread ") - 1;
301 size_t fs = sizeof ("--frame ") - 1;
102040f0 302
a79b8f6e
VP
303 if (strncmp (chp, "--all ", as) == 0)
304 {
305 parse->all = 1;
306 chp += as;
307 }
308 /* See if --all is the last token in the input. */
309 if (strcmp (chp, "--all") == 0)
310 {
311 parse->all = 1;
312 chp += strlen (chp);
313 }
314 if (strncmp (chp, "--thread-group ", tgs) == 0)
315 {
30a7f059 316 option = "--thread-group";
a79b8f6e
VP
317 if (parse->thread_group != -1)
318 error (_("Duplicate '--thread-group' option"));
319 chp += tgs;
320 if (*chp != 'i')
321 error (_("Invalid thread group id"));
322 chp += 1;
323 parse->thread_group = strtol (chp, &chp, 10);
324 }
8e0e408a 325 else if (strncmp (chp, "--thread ", ts) == 0)
1e92afda 326 {
30a7f059 327 option = "--thread";
1e92afda 328 if (parse->thread != -1)
a79b8f6e 329 error (_("Duplicate '--thread' option"));
1e92afda
VP
330 chp += ts;
331 parse->thread = strtol (chp, &chp, 10);
332 }
333 else if (strncmp (chp, "--frame ", fs) == 0)
334 {
30a7f059 335 option = "--frame";
1e92afda 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))
30a7f059 345 error (_("Invalid value for the '%s' option"), option);
1e92afda
VP
346 while (isspace (*chp))
347 chp++;
348 }
349
fb40c209 350 /* For new argv commands, attempt to return the parsed argument
2b03b41d 351 list. */
fb40c209
AC
352 if (parse->cmd->argv_func != NULL)
353 {
354 mi_parse_argv (chp, parse);
355 if (parse->argv == NULL)
305aeedc 356 error (_("Problem parsing arguments: %s %s"), parse->command, chp);
fb40c209
AC
357 }
358
359 /* FIXME: DELETE THIS */
9e22b03a 360 /* For CLI commands, also return the remainder of the
fb40c209 361 command line as a single string. */
9e22b03a
VP
362 if (parse->cmd->cli.cmd != NULL)
363 parse->args = xstrdup (chp);
fb40c209 364
305aeedc
TT
365 discard_cleanups (cleanup);
366
2b03b41d 367 /* Fully parsed, flag as an MI command. */
fb40c209
AC
368 parse->op = MI_COMMAND;
369 return parse;
370}
This page took 1.049791 seconds and 4 git commands to generate.