1 /* MI Command Set - MI parser. 2 3 Copyright (C) 2000, 2001, 2002, 2007, 2008, 2009, 2010, 2011 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 #include "charset.h" 27 28 #include <ctype.h> 29 #include "gdb_string.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 (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 (char *args, struct mi_parse *parse) 107 { 108 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 while (isspace (*chp)) 119 chp++; 120 /* Three possibilities: EOF, quoted string, or other text. */ 121 switch (*chp) 122 { 123 case '\0': 124 parse->argv = argv; 125 parse->argc = argc; 126 return; 127 case '"': 128 { 129 /* A quoted string. */ 130 int len; 131 char *start = chp + 1; 132 133 /* Determine the buffer size. */ 134 chp = start; 135 len = 0; 136 while (*chp != '\0' && *chp != '"') 137 { 138 if (*chp == '\\') 139 { 140 chp++; 141 if (mi_parse_escape (&chp) <= 0) 142 { 143 /* Do not allow split lines or "\000" */ 144 freeargv (argv); 145 return; 146 } 147 } 148 else 149 chp++; 150 len++; 151 } 152 /* Insist on a closing quote. */ 153 if (*chp != '"') 154 { 155 freeargv (argv); 156 return; 157 } 158 /* Insist on trailing white space. */ 159 if (chp[1] != '\0' && !isspace (chp[1])) 160 { 161 freeargv (argv); 162 return; 163 } 164 /* create the buffer. */ 165 arg = xmalloc ((len + 1) * sizeof (char)); 166 /* And copy the characters in. */ 167 chp = start; 168 len = 0; 169 while (*chp != '\0' && *chp != '"') 170 { 171 if (*chp == '\\') 172 { 173 chp++; 174 arg[len] = mi_parse_escape (&chp); 175 } 176 else 177 arg[len] = *chp++; 178 len++; 179 } 180 arg[len] = '\0'; 181 chp++; /* that closing quote. */ 182 break; 183 } 184 default: 185 { 186 /* An unquoted string. Accumulate all non blank 187 characters into a buffer. */ 188 int len; 189 char *start = chp; 190 191 while (*chp != '\0' && !isspace (*chp)) 192 { 193 chp++; 194 } 195 len = chp - start; 196 arg = xmalloc ((len + 1) * sizeof (char)); 197 strncpy (arg, start, len); 198 arg[len] = '\0'; 199 break; 200 } 201 } 202 /* Append arg to argv. */ 203 argv = xrealloc (argv, (argc + 2) * sizeof (char *)); 204 argv[argc++] = arg; 205 argv[argc] = NULL; 206 } 207 } 208 209 210 void 211 mi_parse_free (struct mi_parse *parse) 212 { 213 if (parse == NULL) 214 return; 215 if (parse->command != NULL) 216 xfree (parse->command); 217 if (parse->token != NULL) 218 xfree (parse->token); 219 if (parse->args != NULL) 220 xfree (parse->args); 221 if (parse->argv != NULL) 222 freeargv (parse->argv); 223 xfree (parse); 224 } 225 226 /* A cleanup that calls mi_parse_free. */ 227 228 static void 229 mi_parse_cleanup (void *arg) 230 { 231 mi_parse_free (arg); 232 } 233 234 struct mi_parse * 235 mi_parse (char *cmd, char **token) 236 { 237 char *chp; 238 struct mi_parse *parse = XMALLOC (struct mi_parse); 239 struct cleanup *cleanup; 240 241 memset (parse, 0, sizeof (*parse)); 242 parse->all = 0; 243 parse->thread_group = -1; 244 parse->thread = -1; 245 parse->frame = -1; 246 247 cleanup = make_cleanup (mi_parse_cleanup, parse); 248 249 /* Before starting, skip leading white space. */ 250 while (isspace (*cmd)) 251 cmd++; 252 253 /* Find/skip any token and then extract it. */ 254 for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++) 255 ; 256 *token = xmalloc ((chp - cmd + 1) * sizeof (char *)); 257 memcpy (*token, cmd, (chp - cmd)); 258 (*token)[chp - cmd] = '\0'; 259 260 /* This wasn't a real MI command. Return it as a CLI_COMMAND. */ 261 if (*chp != '-') 262 { 263 while (isspace (*chp)) 264 chp++; 265 parse->command = xstrdup (chp); 266 parse->op = CLI_COMMAND; 267 268 discard_cleanups (cleanup); 269 270 return parse; 271 } 272 273 /* Extract the command. */ 274 { 275 char *tmp = chp + 1; /* discard ``-'' */ 276 277 for (; *chp && !isspace (*chp); chp++) 278 ; 279 parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *)); 280 memcpy (parse->command, tmp, chp - tmp); 281 parse->command[chp - tmp] = '\0'; 282 } 283 284 /* Find the command in the MI table. */ 285 parse->cmd = mi_lookup (parse->command); 286 if (parse->cmd == NULL) 287 error (_("Undefined MI command: %s"), parse->command); 288 289 /* Skip white space following the command. */ 290 while (isspace (*chp)) 291 chp++; 292 293 /* Parse the --thread and --frame options, if present. At present, 294 some important commands, like '-break-*' are implemented by forwarding 295 to the CLI layer directly. We want to parse --thread and --frame 296 here, so as not to leave those option in the string that will be passed 297 to CLI. */ 298 for (;;) 299 { 300 const char *option; 301 size_t as = sizeof ("--all ") - 1; 302 size_t tgs = sizeof ("--thread-group ") - 1; 303 size_t ts = sizeof ("--thread ") - 1; 304 size_t fs = sizeof ("--frame ") - 1; 305 306 if (strncmp (chp, "--all ", as) == 0) 307 { 308 parse->all = 1; 309 chp += as; 310 } 311 /* See if --all is the last token in the input. */ 312 if (strcmp (chp, "--all") == 0) 313 { 314 parse->all = 1; 315 chp += strlen (chp); 316 } 317 if (strncmp (chp, "--thread-group ", tgs) == 0) 318 { 319 option = "--thread-group"; 320 if (parse->thread_group != -1) 321 error (_("Duplicate '--thread-group' option")); 322 chp += tgs; 323 if (*chp != 'i') 324 error (_("Invalid thread group id")); 325 chp += 1; 326 parse->thread_group = strtol (chp, &chp, 10); 327 } 328 else if (strncmp (chp, "--thread ", ts) == 0) 329 { 330 option = "--thread"; 331 if (parse->thread != -1) 332 error (_("Duplicate '--thread' option")); 333 chp += ts; 334 parse->thread = strtol (chp, &chp, 10); 335 } 336 else if (strncmp (chp, "--frame ", fs) == 0) 337 { 338 option = "--frame"; 339 if (parse->frame != -1) 340 error (_("Duplicate '--frame' option")); 341 chp += fs; 342 parse->frame = strtol (chp, &chp, 10); 343 } 344 else 345 break; 346 347 if (*chp != '\0' && !isspace (*chp)) 348 error (_("Invalid value for the '%s' option"), option); 349 while (isspace (*chp)) 350 chp++; 351 } 352 353 /* For new argv commands, attempt to return the parsed argument 354 list. */ 355 if (parse->cmd->argv_func != NULL) 356 { 357 mi_parse_argv (chp, parse); 358 if (parse->argv == NULL) 359 error (_("Problem parsing arguments: %s %s"), parse->command, chp); 360 } 361 362 /* FIXME: DELETE THIS */ 363 /* For CLI commands, also return the remainder of the 364 command line as a single string. */ 365 if (parse->cmd->cli.cmd != NULL) 366 parse->args = xstrdup (chp); 367 368 discard_cleanups (cleanup); 369 370 /* Fully parsed. */ 371 parse->op = MI_COMMAND; 372 return parse; 373 } 374