198944Sobrien/* MI Command Set - MI parser.
2130803Smarcel
3130803Smarcel   Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
4130803Smarcel
598944Sobrien   Contributed by Cygnus Solutions (a Red Hat company).
698944Sobrien
798944Sobrien   This file is part of GDB.
898944Sobrien
998944Sobrien   This program is free software; you can redistribute it and/or modify
1098944Sobrien   it under the terms of the GNU General Public License as published by
1198944Sobrien   the Free Software Foundation; either version 2 of the License, or
1298944Sobrien   (at your option) any later version.
1398944Sobrien
1498944Sobrien   This program is distributed in the hope that it will be useful,
1598944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1698944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1798944Sobrien   GNU General Public License for more details.
1898944Sobrien
1998944Sobrien   You should have received a copy of the GNU General Public License
2098944Sobrien   along with this program; if not, write to the Free Software
2198944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2298944Sobrien   Boston, MA 02111-1307, USA.  */
2398944Sobrien
2498944Sobrien#include "defs.h"
2598944Sobrien#include "mi-cmds.h"
2698944Sobrien#include "mi-parse.h"
2798944Sobrien
2898944Sobrien#include <ctype.h>
2998944Sobrien#include "gdb_string.h"
3098944Sobrien
3198944Sobrienstatic void
3298944Sobrienmi_parse_argv (char *args, struct mi_parse *parse)
3398944Sobrien{
3498944Sobrien  char *chp = args;
3598944Sobrien  int argc = 0;
3698944Sobrien  char **argv = xmalloc ((argc + 1) * sizeof (char *));
3798944Sobrien  argv[argc] = NULL;
3898944Sobrien  while (1)
3998944Sobrien    {
4098944Sobrien      char *arg;
4198944Sobrien      /* skip leading white space */
4298944Sobrien      while (isspace (*chp))
4398944Sobrien	chp++;
4498944Sobrien      /* Three possibilities: EOF, quoted string, or other text. */
4598944Sobrien      switch (*chp)
4698944Sobrien	{
4798944Sobrien	case '\0':
4898944Sobrien	  parse->argv = argv;
4998944Sobrien	  parse->argc = argc;
5098944Sobrien	  return;
5198944Sobrien	case '"':
5298944Sobrien	  {
5398944Sobrien	    /* A quoted string. */
5498944Sobrien	    int len;
5598944Sobrien	    char *start = chp + 1;
5698944Sobrien	    /* Determine the buffer size. */
5798944Sobrien	    chp = start;
5898944Sobrien	    len = 0;
5998944Sobrien	    while (*chp != '\0' && *chp != '"')
6098944Sobrien	      {
6198944Sobrien		if (*chp == '\\')
6298944Sobrien		  {
6398944Sobrien		    chp++;
6498944Sobrien		    if (parse_escape (&chp) <= 0)
6598944Sobrien		      {
6698944Sobrien			/* Do not allow split lines or "\000" */
6798944Sobrien			freeargv (argv);
6898944Sobrien			return;
6998944Sobrien		      }
7098944Sobrien		  }
7198944Sobrien		else
7298944Sobrien		  chp++;
7398944Sobrien		len++;
7498944Sobrien	      }
7598944Sobrien	    /* Insist on a closing quote. */
7698944Sobrien	    if (*chp != '"')
7798944Sobrien	      {
7898944Sobrien		freeargv (argv);
7998944Sobrien		return;
8098944Sobrien	      }
8198944Sobrien	    /* Insist on trailing white space. */
8298944Sobrien	    if (chp[1] != '\0' && !isspace (chp[1]))
8398944Sobrien	      {
8498944Sobrien		freeargv (argv);
8598944Sobrien		return;
8698944Sobrien	      }
8798944Sobrien	    /* create the buffer. */
8898944Sobrien	    arg = xmalloc ((len + 1) * sizeof (char));
8998944Sobrien	    /* And copy the characters in. */
9098944Sobrien	    chp = start;
9198944Sobrien	    len = 0;
9298944Sobrien	    while (*chp != '\0' && *chp != '"')
9398944Sobrien	      {
9498944Sobrien		if (*chp == '\\')
9598944Sobrien		  {
9698944Sobrien		    chp++;
9798944Sobrien		    arg[len] = parse_escape (&chp);
9898944Sobrien		  }
9998944Sobrien		else
10098944Sobrien		  arg[len] = *chp++;
10198944Sobrien		len++;
10298944Sobrien	      }
10398944Sobrien	    arg[len] = '\0';
10498944Sobrien	    chp++;		/* that closing quote. */
10598944Sobrien	    break;
10698944Sobrien	  }
10798944Sobrien	default:
10898944Sobrien	  {
10998944Sobrien	    /* An unquoted string.  Accumulate all non blank
11098944Sobrien	       characters into a buffer. */
11198944Sobrien	    int len;
11298944Sobrien	    char *start = chp;
11398944Sobrien	    while (*chp != '\0' && !isspace (*chp))
11498944Sobrien	      {
11598944Sobrien		chp++;
11698944Sobrien	      }
11798944Sobrien	    len = chp - start;
11898944Sobrien	    arg = xmalloc ((len + 1) * sizeof (char));
11998944Sobrien	    strncpy (arg, start, len);
12098944Sobrien	    arg[len] = '\0';
12198944Sobrien	    break;
12298944Sobrien	  }
12398944Sobrien	}
12498944Sobrien      /* Append arg to argv. */
12598944Sobrien      argv = xrealloc (argv, (argc + 2) * sizeof (char *));
12698944Sobrien      argv[argc++] = arg;
12798944Sobrien      argv[argc] = NULL;
12898944Sobrien    }
12998944Sobrien}
13098944Sobrien
13198944Sobrien
13298944Sobrienvoid
13398944Sobrienmi_parse_free (struct mi_parse *parse)
13498944Sobrien{
13598944Sobrien  if (parse == NULL)
13698944Sobrien    return;
13798944Sobrien  if (parse->command != NULL)
13898944Sobrien    xfree (parse->command);
13998944Sobrien  if (parse->token != NULL)
14098944Sobrien    xfree (parse->token);
14198944Sobrien  if (parse->args != NULL)
14298944Sobrien    xfree (parse->args);
14398944Sobrien  if (parse->argv != NULL)
14498944Sobrien    freeargv (parse->argv);
14598944Sobrien  xfree (parse);
14698944Sobrien}
14798944Sobrien
14898944Sobrien
14998944Sobrienstruct mi_parse *
15098944Sobrienmi_parse (char *cmd)
15198944Sobrien{
15298944Sobrien  char *chp;
15398944Sobrien  struct mi_parse *parse = XMALLOC (struct mi_parse);
15498944Sobrien  memset (parse, 0, sizeof (*parse));
15598944Sobrien
15698944Sobrien  /* Before starting, skip leading white space. */
15798944Sobrien  while (isspace (*cmd))
15898944Sobrien    cmd++;
15998944Sobrien
16098944Sobrien  /* Find/skip any token and then extract it. */
16198944Sobrien  for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
16298944Sobrien    ;
16398944Sobrien  parse->token = xmalloc ((chp - cmd + 1) * sizeof (char *));
16498944Sobrien  memcpy (parse->token, cmd, (chp - cmd));
16598944Sobrien  parse->token[chp - cmd] = '\0';
16698944Sobrien
16798944Sobrien  /* This wasn't a real MI command.  Return it as a CLI_COMMAND. */
16898944Sobrien  if (*chp != '-')
16998944Sobrien    {
17098944Sobrien      while (isspace (*chp))
17198944Sobrien	chp++;
17298944Sobrien      parse->command = xstrdup (chp);
17398944Sobrien      parse->op = CLI_COMMAND;
17498944Sobrien      return parse;
17598944Sobrien    }
17698944Sobrien
17798944Sobrien  /* Extract the command. */
17898944Sobrien  {
17998944Sobrien    char *tmp = chp + 1;	/* discard ``-'' */
18098944Sobrien    for (; *chp && !isspace (*chp); chp++)
18198944Sobrien      ;
18298944Sobrien    parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *));
18398944Sobrien    memcpy (parse->command, tmp, chp - tmp);
18498944Sobrien    parse->command[chp - tmp] = '\0';
18598944Sobrien  }
18698944Sobrien
18798944Sobrien  /* Find the command in the MI table. */
18898944Sobrien  parse->cmd = mi_lookup (parse->command);
18998944Sobrien  if (parse->cmd == NULL)
19098944Sobrien    {
19198944Sobrien      /* FIXME: This should be a function call. */
19298944Sobrien      fprintf_unfiltered
19398944Sobrien	(raw_stdout,
19498944Sobrien	 "%s^error,msg=\"Undefined MI command: %s\"\n",
19598944Sobrien	 parse->token, parse->command);
19698944Sobrien      mi_parse_free (parse);
19798944Sobrien      return NULL;
19898944Sobrien    }
19998944Sobrien
20098944Sobrien  /* Skip white space following the command. */
20198944Sobrien  while (isspace (*chp))
20298944Sobrien    chp++;
20398944Sobrien
20498944Sobrien  /* For new argv commands, attempt to return the parsed argument
20598944Sobrien     list. */
20698944Sobrien  if (parse->cmd->argv_func != NULL)
20798944Sobrien    {
20898944Sobrien      mi_parse_argv (chp, parse);
20998944Sobrien      if (parse->argv == NULL)
21098944Sobrien	{
21198944Sobrien	  /* FIXME: This should be a function call. */
21298944Sobrien	  fprintf_unfiltered
21398944Sobrien	    (raw_stdout,
21498944Sobrien	     "%s^error,msg=\"Problem parsing arguments: %s %s\"\n",
21598944Sobrien	     parse->token, parse->command, chp);
21698944Sobrien	  mi_parse_free (parse);
21798944Sobrien	  return NULL;
21898944Sobrien	}
21998944Sobrien    }
22098944Sobrien
22198944Sobrien  /* FIXME: DELETE THIS */
22298944Sobrien  /* For CLI and old ARGS commands, also return the remainder of the
22398944Sobrien     command line as a single string. */
22498944Sobrien  if (parse->cmd->args_func != NULL
225130803Smarcel      || parse->cmd->cli.cmd != NULL)
22698944Sobrien    {
22798944Sobrien      parse->args = xstrdup (chp);
22898944Sobrien    }
22998944Sobrien
23098944Sobrien  /* Fully parsed. */
23198944Sobrien  parse->op = MI_COMMAND;
23298944Sobrien  return parse;
23398944Sobrien}
234