This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

small enhancements to gdb here..


Hi,

I originally sent this email to gnu-gdb@gnu.org before I saw the CONTRIBUTE file.  I reformatted the diff output to your specifications.  The diff's are based on 5.0 distribution at GNU's ftp site.

I have patches for 3 small enhancements to improve convenience:

- allow O/S commands directly from gdb when no match for internal command.
- additional arg syntax in user-defined commands:
    $#        number of args
    $*        all args
    $N        specific arg (where N is a number from 1 to 9).  $1 is the first
              arg (same as $arg0).
    ${NN}     NN can be any number between 1 and MAXUSERARGS (10 currently).
    ${ENV}    environment variable
- a user command referencing an argument not provided on the command returns
  an empty string, not an error.

Example .gdbinit:
define sh
   shell $*
end
define host
   shell $*
end
define pa
   echo args = $*, count = $#\n
   echo arg1 = $1\n
   echo arg2 = $2\n
   echo arg10 = ${10}\n
   echo arg0=$arg0\n
   echo arg1=$arg1\n
end
define c
   if strcmp("$1", "at") == 0
      printf "continuing at %d\n", $2
      jump $2
   else
      continue $*
   end
end

ChangeLog entry:

2000-11-20  Don Beusee     <Don.Beusee@oracle.com>

        * gdb/command.c, gdb/top.c: If a command entered in gdb is not
        internal, execute as a shell command.

        * gdb/top.c: Enhance user-defined command argument parsing to accept
        $# (number of args), $* (all args), $N (where N is a number from 1 to
        9), ${NN} where NN is any number from 1 to MAXUSERARGS (10 currently),
        and ${ENV} where ENV is an environment variable.

        * gdb/doc/gdb.info-9: document above arg parsing in user-defined
        commands.

Here are the patches in rcsdiff -up format:

$ rcsdiff -up gdb/command.c
--- 1.1	2000/11/20 11:49:09
+++ gdb/command.c	2000/11/20 11:53:35
@@ -43,7 +43,7 @@ static void show_user_1 (struct cmd_list
 
 static void make_command PARAMS ((char *, int));
 
-static void shell_escape PARAMS ((char *, int));
+void shell_escape PARAMS ((char *, int));
 
 static int parse_binary_operation PARAMS ((char *));
 
@@ -512,7 +512,7 @@ help_cmd (command, stream)
 
   c = lookup_cmd (&command, cmdlist, "", 0, 0);
 
-  if (c == 0)
+  if (c == 0 || c == -1 || c == -2)
     return;
 
   /* There are three cases here.
@@ -901,8 +901,8 @@ undef_cmd_error (cmdtype, q)
    LIST is a chain of struct cmd_list_element's.
    If it is found, return the struct cmd_list_element for that command
    and update *LINE to point after the command name, at the first argument.
-   If not found, call error if ALLOW_UNKNOWN is zero
-   otherwise (or if error returns) return zero.
+   If not found, return -2 to signal caller to run shell if ALLOW_UNKNOWN is
+   zero otherwise (or if error returns) return zero.
    Call error if specified command is ambiguous,
    unless ALLOW_UNKNOWN is negative.
    CMDTYPE precedes the word "command" in the error message.
@@ -948,7 +948,10 @@ lookup_cmd (line, list, cmdtype, allow_u
 	      q = (char *) alloca (p - *line + 1);
 	      strncpy (q, *line, p - *line);
 	      q[p - *line] = '\0';
-	      undef_cmd_error (cmdtype, q);
+	      if (!*cmdtype)
+                 return (struct cmd_list_element *) -2; /* invoke shell */
+              else
+                 undef_cmd_error (cmdtype, q);
 	    }
 	}
       else
@@ -1861,7 +1864,7 @@ cmd_show_list (list, from_tty, prefix)
 }
 
 /* ARGSUSED */
-static void
+void
 shell_escape (arg, from_tty)
      char *arg;
      int from_tty;


$ rcsdiff -up gdb/top.c
--- 1.1	2000/11/20 11:49:13
+++ gdb/top.c	2000/11/20 12:02:39
@@ -97,7 +97,9 @@ recurse_read_control_structure PARAMS ((
 
 static struct cleanup *setup_user_args PARAMS ((char *));
 
-static char *locate_arg PARAMS ((char *));
+static char *locate_arg PARAMS ((char *, int *, char **, char **, char *));
+
+static char *itoa PARAMS ((int));
 
 static char *insert_args PARAMS ((char *));
 
@@ -144,6 +146,8 @@ static void complete_command PARAMS ((ch
 
 static void do_nothing PARAMS ((int));
 
+extern void shell_escape PARAMS ((char *, int));
+
 static void show_debug PARAMS ((char *, int));
 
 static void set_debug PARAMS ((char *, int));
@@ -360,6 +364,7 @@ struct user_args
 	int len;
       }
     a[MAXUSERARGS];
+    char args[256];
     int count;
   }
  *user_args;
@@ -1296,6 +1301,8 @@ setup_user_args (p)
   if (p == NULL)
     return old_chain;
 
+  strcpy(args->args, p);
+
   while (*p)
     {
       char *start_arg;
@@ -1357,20 +1364,87 @@ setup_user_args (p)
   return old_chain;
 }
 
-/* Given character string P, return a point to the first argument ($arg),
-   or NULL if P contains no arguments.  */
+/*
+ * Given character string P, return a point to the substitution argument
+ * or variable; or NULL if P contains no arguments or variable tokens.
+ * num will contain one of the following values:
+ *    -1 (all arguments should replace this token)
+ *    -2 (argument count should replace this token)
+ *    -3 (string stored in newstr should replace this token)
+ *    the argument number,
+ */
 
 static char *
-locate_arg (p)
-     char *p;
+locate_arg (p, num, start, after, newstr)
+     char *p, **start, **after, *newstr;
+     int *num;
 {
+  *start = NULL;
+  *newstr = '\0';
   while ((p = strchr (p, '$')))
     {
       if (strncmp (p, "$arg", 4) == 0 && isdigit (p[4]))
-	return p;
+	{
+	  *num = p[4]-'0';
+	  *start = p;
+	  *after = p+5;
+	  return *start;
+	}
+      if (p[0] == '$' && isdigit (p[1]))
+	{
+	  *num = p[1] - '0' - 1;
+	  *start = p;
+	  *after = p+2;
+	  return *start;
+	}
+      if (p[0] == '$' && p[1] == '#')
+	{
+	  *num = -2; /* indicates to replace with count */
+	  *start = p;
+	  *after = p+2;
+	  return *start;
+	}
+      if (p[0] == '$' && p[1] == '*')
+	{
+	  *num = -1; /* indicates to use all args */
+	  *start = p;
+	  *after = p+2;
+	  return *start;
+	}
+      if (p[0] == '$' && p[1] == '{' && isdigit(p[2]))
+	{
+	  *num = atoi(p+2) - 1;
+	  *start = p;
+	  *after = strchr(p, '}')+1;
+	  return *start;
+	}
+      if (p[0] == '$' && p[1] == '{')
+        {
+          char env[256], *e;
+          memset(env, '\0', sizeof(env));
+          *num = -3; /* environment variable */
+          *start = p;
+          *after = strchr(p, '}')+1;
+          memcpy(env, p+2, (*after) - p - 3);
+          if (e = getenv(env))
+            {
+              strcpy(newstr, e);
+            }
+          return *start;
+        }
       p++;
     }
-  return NULL;
+  return *start;
+}
+
+static char *
+itoa(i)
+        int i;
+{
+        static char a[12];
+        *a = '\0';
+        sprintf(a, "%0d", i);
+        return(a);
 }
 
 /* Insert the user defined arguments stored in user_arg into the $arg
@@ -1380,24 +1454,33 @@ static char *
 insert_args (line)
      char *line;
 {
-  char *p, *save_line, *new_line;
-  unsigned len, i;
+  char *p, *save_line, *new_line, *afterarg;
+  char envstr[256];
+  unsigned len;
+  int i;
 
   /* First we need to know how much memory to allocate for the new line.  */
   save_line = line;
   len = 0;
-  while ((p = locate_arg (line)))
+  while (locate_arg (line, &i/*argnum*/, &p/*startarg*/, &afterarg, envstr))
     {
-      len += p - line;
-      i = p[4] - '0';
-
-      if (i >= user_args->count)
-	{
-	  error ("Missing argument %d in user function.\n", i);
-	  return NULL;
+      len += p - line; /* add portion before arg token */
+      if (i == -1 && user_args)
+        len += strlen(user_args->args);
+      else if (i == -2 && user_args)
+        len += strlen(itoa(user_args->count));
+      else if (i == -3)
+        len += strlen(envstr);
+      else if (user_args && i < user_args->count)
+        len += user_args->a[i].len;
+/*
+      else
+        {
+             error ("Missing argument %d in user function.\n", i);
+             return NULL;
 	}
-      len += user_args->a[i].len;
-      line = p + 5;
+*/
+      line = afterarg;
     }
 
   /* Don't forget the tail.  */
@@ -1406,7 +1489,10 @@ insert_args (line)
   /* Allocate space for the new line and fill it in.  */
   new_line = (char *) xmalloc (len + 1);
   if (new_line == NULL)
-    return NULL;
+    {
+      error ("could not allocate memory for argument substitution.\n");
+      return NULL;
+    }
 
   /* Restore pointer to beginning of old line.  */
   line = save_line;
@@ -1414,21 +1500,36 @@ insert_args (line)
   /* Save pointer to beginning of new line.  */
   save_line = new_line;
 
-  while ((p = locate_arg (line)))
+  while (locate_arg (line, &i/*argnum*/, &p/*startarg*/, &afterarg, envstr))
     {
-      int i, len;
-
-      memcpy (new_line, line, p - line);
-      new_line += p - line;
-      i = p[4] - '0';
-
-      len = user_args->a[i].len;
-      if (len)
-	{
+      memcpy (new_line, line, p - line); /* copy line before arg token */
+      new_line += p - line; /* point new_line at end */
+      if (i == -1 && user_args)
+        {
+          len = strlen(user_args->args);
+	  memcpy (new_line, user_args->args, len);
+        }
+      else if (i == -2 && user_args)
+        {
+          len = strlen(itoa(user_args->count));
+	  memcpy (new_line, itoa(user_args->count), len);
+        }
+      else if (i == -3)
+        {
+          len = strlen(envstr);
+	  memcpy (new_line, envstr, len);
+        }
+      else if (user_args && i < user_args->count)
+        {
+          len = user_args->a[i].len;
 	  memcpy (new_line, user_args->a[i].arg, len);
-	  new_line += len;
-	}
-      line = p + 5;
+        }
+      else
+        {
+	  len = 0; /* arg not present - add nothing */
+        }
+      new_line += len;
+      line = afterarg;
     }
   /* Don't forget the tail.  */
   strcpy (new_line, line);
@@ -1505,6 +1606,14 @@ execute_command (p, from_tty)
       line = p;
 
       c = lookup_cmd (&p, cmdlist, "", 0, 1);
+      if (c == (struct cmd_list_element *)-2) /* invoke shell? */
+        {
+          char *shellcmd;
+          shellcmd = malloc(strlen(p)+7);
+          sprintf(shellcmd, "shell %s", p);
+          execute_command(shellcmd, from_tty);
+          return;
+        }
 
       /* If the target is running, we allow only a limited set of
          commands. */
@@ -1517,6 +1626,10 @@ execute_command (p, from_tty)
 
       /* Pass null arg rather than an empty one.  */
       arg = *p ? p : 0;
+      if (arg && c->function.cfunc != define_command
+              && c->function.cfunc != shell_escape   )
+         arg=insert_args(arg); /* replace environment variables in command with
+                                  their values */
 
       /* Clear off trailing whitespace, except for set and complete command.  */
       if (arg && c->type != set_cmd && c->function.cfunc != complete_command)

$ rcsdiff -up gdb/doc/gdb.info-9
--- 1.1	2000/11/21 07:35:46
+++ gdb/doc/gdb.info-9	2000/11/21 07:41:39
@@ -250,12 +250,22 @@ User-defined commands
 
    A "user-defined command" is a sequence of GDB commands to which you
 assign a new name as a command.  This is done with the `define'
-command.  User commands may accept up to 10 arguments separated by
+command.
+
+User commands may accept up to 10 arguments separated by
 whitespace.  Arguments are accessed within the user command via
-$ARG0...$ARG9.  A trivial example:
+$ARG0...$ARG9 or $1...$9 and the 10th as ${10} or (${1}..${10}).
+$# is the number of arguments given to the user-defined command.
+A reference to an argument that is not given will be returned as an
+empty string.
+
+You may also reference environment variables with ${ENV}, where ENV
+is the name of the environment variable.
+
+A trivial example:
 
      define adder
-       print $arg0 + $arg1 + $arg2
+       print $1 + $2 + $3
 
 To execute the command use:
 
-Don


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]