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