Update copyright year in most headers.
[deliverable/binutils-gdb.git] / gdb / mi / mi-parse.c
1 /* MI Command Set - MI parser.
2
3 Copyright (C) 2000, 2001, 2002, 2007, 2008, 2009, 2010
4 Free Software Foundation, Inc.
5
6 Contributed by Cygnus Solutions (a Red Hat company).
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
12 the Free Software Foundation; either version 3 of the License, or
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
21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22
23 #include "defs.h"
24 #include "mi-cmds.h"
25 #include "mi-parse.h"
26
27 #include <ctype.h>
28 #include "gdb_string.h"
29
30 static void
31 mi_parse_argv (char *args, struct mi_parse *parse)
32 {
33 char *chp = args;
34 int argc = 0;
35 char **argv = xmalloc ((argc + 1) * sizeof (char *));
36 argv[argc] = NULL;
37 while (1)
38 {
39 char *arg;
40 /* skip leading white space */
41 while (isspace (*chp))
42 chp++;
43 /* Three possibilities: EOF, quoted string, or other text. */
44 switch (*chp)
45 {
46 case '\0':
47 parse->argv = argv;
48 parse->argc = argc;
49 return;
50 case '"':
51 {
52 /* A quoted string. */
53 int len;
54 char *start = chp + 1;
55 /* Determine the buffer size. */
56 chp = start;
57 len = 0;
58 while (*chp != '\0' && *chp != '"')
59 {
60 if (*chp == '\\')
61 {
62 chp++;
63 if (parse_escape (&chp) <= 0)
64 {
65 /* Do not allow split lines or "\000" */
66 freeargv (argv);
67 return;
68 }
69 }
70 else
71 chp++;
72 len++;
73 }
74 /* Insist on a closing quote. */
75 if (*chp != '"')
76 {
77 freeargv (argv);
78 return;
79 }
80 /* Insist on trailing white space. */
81 if (chp[1] != '\0' && !isspace (chp[1]))
82 {
83 freeargv (argv);
84 return;
85 }
86 /* create the buffer. */
87 arg = xmalloc ((len + 1) * sizeof (char));
88 /* And copy the characters in. */
89 chp = start;
90 len = 0;
91 while (*chp != '\0' && *chp != '"')
92 {
93 if (*chp == '\\')
94 {
95 chp++;
96 arg[len] = parse_escape (&chp);
97 }
98 else
99 arg[len] = *chp++;
100 len++;
101 }
102 arg[len] = '\0';
103 chp++; /* that closing quote. */
104 break;
105 }
106 default:
107 {
108 /* An unquoted string. Accumulate all non blank
109 characters into a buffer. */
110 int len;
111 char *start = chp;
112 while (*chp != '\0' && !isspace (*chp))
113 {
114 chp++;
115 }
116 len = chp - start;
117 arg = xmalloc ((len + 1) * sizeof (char));
118 strncpy (arg, start, len);
119 arg[len] = '\0';
120 break;
121 }
122 }
123 /* Append arg to argv. */
124 argv = xrealloc (argv, (argc + 2) * sizeof (char *));
125 argv[argc++] = arg;
126 argv[argc] = NULL;
127 }
128 }
129
130
131 void
132 mi_parse_free (struct mi_parse *parse)
133 {
134 if (parse == NULL)
135 return;
136 if (parse->command != NULL)
137 xfree (parse->command);
138 if (parse->token != NULL)
139 xfree (parse->token);
140 if (parse->args != NULL)
141 xfree (parse->args);
142 if (parse->argv != NULL)
143 freeargv (parse->argv);
144 xfree (parse);
145 }
146
147
148 struct mi_parse *
149 mi_parse (char *cmd)
150 {
151 char *chp;
152 struct mi_parse *parse = XMALLOC (struct mi_parse);
153 memset (parse, 0, sizeof (*parse));
154 parse->thread = -1;
155 parse->frame = -1;
156
157 /* Before starting, skip leading white space. */
158 while (isspace (*cmd))
159 cmd++;
160
161 /* Find/skip any token and then extract it. */
162 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
163 ;
164 parse->token = xmalloc ((chp - cmd + 1) * sizeof (char *));
165 memcpy (parse->token, cmd, (chp - cmd));
166 parse->token[chp - cmd] = '\0';
167
168 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */
169 if (*chp != '-')
170 {
171 while (isspace (*chp))
172 chp++;
173 parse->command = xstrdup (chp);
174 parse->op = CLI_COMMAND;
175 return parse;
176 }
177
178 /* Extract the command. */
179 {
180 char *tmp = chp + 1; /* discard ``-'' */
181 for (; *chp && !isspace (*chp); chp++)
182 ;
183 parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *));
184 memcpy (parse->command, tmp, chp - tmp);
185 parse->command[chp - tmp] = '\0';
186 }
187
188 /* Find the command in the MI table. */
189 parse->cmd = mi_lookup (parse->command);
190 if (parse->cmd == NULL)
191 {
192 /* FIXME: This should be a function call. */
193 fprintf_unfiltered
194 (raw_stdout,
195 "%s^error,msg=\"Undefined MI command: %s\"\n",
196 parse->token, parse->command);
197 mi_parse_free (parse);
198 return NULL;
199 }
200
201 /* Skip white space following the command. */
202 while (isspace (*chp))
203 chp++;
204
205 /* Parse the --thread and --frame options, if present. At present,
206 some important commands, like '-break-*' are implemented by forwarding
207 to the CLI layer directly. We want to parse --thread and --frame
208 here, so as not to leave those option in the string that will be passed
209 to CLI. */
210 for (;;)
211 {
212 char *start = chp;
213 size_t ts = sizeof ("--thread ") - 1;
214 size_t fs = sizeof ("--frame ") - 1;
215 if (strncmp (chp, "--thread ", ts) == 0)
216 {
217 if (parse->thread != -1)
218 error ("Duplicate '--thread' option");
219 chp += ts;
220 parse->thread = strtol (chp, &chp, 10);
221 }
222 else if (strncmp (chp, "--frame ", fs) == 0)
223 {
224 if (parse->frame != -1)
225 error ("Duplicate '--frame' option");
226 chp += fs;
227 parse->frame = strtol (chp, &chp, 10);
228 }
229 else
230 break;
231
232 if (*chp != '\0' && !isspace (*chp))
233 error ("Invalid value for the '%s' option",
234 start[2] == 't' ? "--thread" : "--frame");
235 while (isspace (*chp))
236 chp++;
237 }
238
239 /* For new argv commands, attempt to return the parsed argument
240 list. */
241 if (parse->cmd->argv_func != NULL)
242 {
243 mi_parse_argv (chp, parse);
244 if (parse->argv == NULL)
245 {
246 /* FIXME: This should be a function call. */
247 fprintf_unfiltered
248 (raw_stdout,
249 "%s^error,msg=\"Problem parsing arguments: %s %s\"\n",
250 parse->token, parse->command, chp);
251 mi_parse_free (parse);
252 return NULL;
253 }
254 }
255
256 /* FIXME: DELETE THIS */
257 /* For CLI commands, also return the remainder of the
258 command line as a single string. */
259 if (parse->cmd->cli.cmd != NULL)
260 parse->args = xstrdup (chp);
261
262 /* Fully parsed. */
263 parse->op = MI_COMMAND;
264 return parse;
265 }
This page took 0.058991 seconds and 4 git commands to generate.