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