1 /* MI Command Set - MI parser. 2 3 Copyright (C) 2000-2013 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 #include "charset.h" 26 27 #include <ctype.h> 28 #include "gdb_string.h" 29 #include "cli/cli-utils.h" 30 31 /* Like parse_escape, but leave the results as a host char, not a 32 target char. */ 33 34 static int 35 mi_parse_escape (const char **string_ptr) 36 { 37 int c = *(*string_ptr)++; 38 39 switch (c) 40 { 41 case '\n': 42 return -2; 43 case 0: 44 (*string_ptr)--; 45 return 0; 46 47 case '0': 48 case '1': 49 case '2': 50 case '3': 51 case '4': 52 case '5': 53 case '6': 54 case '7': 55 { 56 int i = host_hex_value (c); 57 int count = 0; 58 59 while (++count < 3) 60 { 61 c = (**string_ptr); 62 if (isdigit (c) && c != '8' && c != '9') 63 { 64 (*string_ptr)++; 65 i *= 8; 66 i += host_hex_value (c); 67 } 68 else 69 { 70 break; 71 } 72 } 73 return i; 74 } 75 76 case 'a': 77 c = '\a'; 78 break; 79 case 'b': 80 c = '\b'; 81 break; 82 case 'f': 83 c = '\f'; 84 break; 85 case 'n': 86 c = '\n'; 87 break; 88 case 'r': 89 c = '\r'; 90 break; 91 case 't': 92 c = '\t'; 93 break; 94 case 'v': 95 c = '\v'; 96 break; 97 98 default: 99 break; 100 } 101 102 return c; 103 } 104 105 static void 106 mi_parse_argv (const char *args, struct mi_parse *parse) 107 { 108 const char *chp = args; 109 int argc = 0; 110 char **argv = xmalloc ((argc + 1) * sizeof (char *)); 111 112 argv[argc] = NULL; 113 while (1) 114 { 115 char *arg; 116 117 /* Skip leading white space. */ 118 chp = skip_spaces_const (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 { 128 /* A quoted string. */ 129 int len; 130 const char *start = chp + 1; 131 132 /* Determine the buffer size. */ 133 chp = start; 134 len = 0; 135 while (*chp != '\0' && *chp != '"') 136 { 137 if (*chp == '\\') 138 { 139 chp++; 140 if (mi_parse_escape (&chp) <= 0) 141 { 142 /* Do not allow split lines or "\000". */ 143 freeargv (argv); 144 return; 145 } 146 } 147 else 148 chp++; 149 len++; 150 } 151 /* Insist on a closing quote. */ 152 if (*chp != '"') 153 { 154 freeargv (argv); 155 return; 156 } 157 /* Insist on trailing white space. */ 158 if (chp[1] != '\0' && !isspace (chp[1])) 159 { 160 freeargv (argv); 161 return; 162 } 163 /* Create the buffer and copy characters in. */ 164 arg = xmalloc ((len + 1) * sizeof (char)); 165 chp = start; 166 len = 0; 167 while (*chp != '\0' && *chp != '"') 168 { 169 if (*chp == '\\') 170 { 171 chp++; 172 arg[len] = mi_parse_escape (&chp); 173 } 174 else 175 arg[len] = *chp++; 176 len++; 177 } 178 arg[len] = '\0'; 179 chp++; /* That closing quote. */ 180 break; 181 } 182 default: 183 { 184 /* An unquoted string. Accumulate all non-blank 185 characters into a buffer. */ 186 int len; 187 const char *start = chp; 188 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 } 200 /* Append arg to argv. */ 201 argv = xrealloc (argv, (argc + 2) * sizeof (char *)); 202 argv[argc++] = arg; 203 argv[argc] = NULL; 204 } 205 } 206 207 void 208 mi_parse_free (struct mi_parse *parse) 209 { 210 if (parse == NULL) 211 return; 212 if (parse->command != NULL) 213 xfree (parse->command); 214 if (parse->token != NULL) 215 xfree (parse->token); 216 if (parse->args != NULL) 217 xfree (parse->args); 218 if (parse->argv != NULL) 219 freeargv (parse->argv); 220 xfree (parse); 221 } 222 223 /* A cleanup that calls mi_parse_free. */ 224 225 static void 226 mi_parse_cleanup (void *arg) 227 { 228 mi_parse_free (arg); 229 } 230 231 struct mi_parse * 232 mi_parse (const char *cmd, char **token) 233 { 234 const char *chp; 235 struct mi_parse *parse = XMALLOC (struct mi_parse); 236 struct cleanup *cleanup; 237 238 memset (parse, 0, sizeof (*parse)); 239 parse->all = 0; 240 parse->thread_group = -1; 241 parse->thread = -1; 242 parse->frame = -1; 243 244 cleanup = make_cleanup (mi_parse_cleanup, parse); 245 246 /* Before starting, skip leading white space. */ 247 cmd = skip_spaces_const (cmd); 248 249 /* Find/skip any token and then extract it. */ 250 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++) 251 ; 252 *token = xmalloc (chp - cmd + 1); 253 memcpy (*token, cmd, (chp - cmd)); 254 (*token)[chp - cmd] = '\0'; 255 256 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */ 257 if (*chp != '-') 258 { 259 chp = skip_spaces_const (chp); 260 parse->command = xstrdup (chp); 261 parse->op = CLI_COMMAND; 262 263 discard_cleanups (cleanup); 264 265 return parse; 266 } 267 268 /* Extract the command. */ 269 { 270 const char *tmp = chp + 1; /* discard ``-'' */ 271 272 for (; *chp && !isspace (*chp); chp++) 273 ; 274 parse->command = xmalloc (chp - tmp + 1); 275 memcpy (parse->command, tmp, chp - tmp); 276 parse->command[chp - tmp] = '\0'; 277 } 278 279 /* Find the command in the MI table. */ 280 parse->cmd = mi_lookup (parse->command); 281 if (parse->cmd == NULL) 282 error (_("Undefined MI command: %s"), parse->command); 283 284 /* Skip white space following the command. */ 285 chp = skip_spaces_const (chp); 286 287 /* Parse the --thread and --frame options, if present. At present, 288 some important commands, like '-break-*' are implemented by 289 forwarding to the CLI layer directly. We want to parse --thread 290 and --frame here, so as not to leave those option in the string 291 that will be passed to CLI. */ 292 for (;;) 293 { 294 const char *option; 295 size_t as = sizeof ("--all ") - 1; 296 size_t tgs = sizeof ("--thread-group ") - 1; 297 size_t ts = sizeof ("--thread ") - 1; 298 size_t fs = sizeof ("--frame ") - 1; 299 300 if (strncmp (chp, "--all ", as) == 0) 301 { 302 parse->all = 1; 303 chp += as; 304 } 305 /* See if --all is the last token in the input. */ 306 if (strcmp (chp, "--all") == 0) 307 { 308 parse->all = 1; 309 chp += strlen (chp); 310 } 311 if (strncmp (chp, "--thread-group ", tgs) == 0) 312 { 313 char *endp; 314 315 option = "--thread-group"; 316 if (parse->thread_group != -1) 317 error (_("Duplicate '--thread-group' option")); 318 chp += tgs; 319 if (*chp != 'i') 320 error (_("Invalid thread group id")); 321 chp += 1; 322 parse->thread_group = strtol (chp, &endp, 10); 323 chp = endp; 324 } 325 else if (strncmp (chp, "--thread ", ts) == 0) 326 { 327 char *endp; 328 329 option = "--thread"; 330 if (parse->thread != -1) 331 error (_("Duplicate '--thread' option")); 332 chp += ts; 333 parse->thread = strtol (chp, &endp, 10); 334 chp = endp; 335 } 336 else if (strncmp (chp, "--frame ", fs) == 0) 337 { 338 char *endp; 339 340 option = "--frame"; 341 if (parse->frame != -1) 342 error (_("Duplicate '--frame' option")); 343 chp += fs; 344 parse->frame = strtol (chp, &endp, 10); 345 chp = endp; 346 } 347 else 348 break; 349 350 if (*chp != '\0' && !isspace (*chp)) 351 error (_("Invalid value for the '%s' option"), option); 352 chp = skip_spaces_const (chp); 353 } 354 355 /* For new argv commands, attempt to return the parsed argument 356 list. */ 357 if (parse->cmd->argv_func != NULL) 358 { 359 mi_parse_argv (chp, parse); 360 if (parse->argv == NULL) 361 error (_("Problem parsing arguments: %s %s"), parse->command, chp); 362 } 363 364 /* FIXME: DELETE THIS */ 365 /* For CLI commands, also return the remainder of the 366 command line as a single string. */ 367 if (parse->cmd->cli.cmd != NULL) 368 parse->args = xstrdup (chp); 369 370 discard_cleanups (cleanup); 371 372 /* Fully parsed, flag as an MI command. */ 373 parse->op = MI_COMMAND; 374 return parse; 375 } 376