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