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 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 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 * 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