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]
Other format: [Raw text]

Re: [RFA] error-catching mechanism for scripts


Don,

This is a cool command.  Have you ever had the time to address
Andrew's and Eli's suggestions (and a couple of tests)?

Best regards,
Fernando


Don Howard wrote:
> 
> Here is an implementation of the error-catcher that I mentioned a few
> weeks ago.  I chose "try" and "except" as the keywords:
> 
>         try
>            some commands that might error
>         end
> 
>                 -- or --
> 
>         try
>           some commands that might error
>         except
>           some commands to recover from error
>           (errors in this block will not be caught)
>         end
> 
> I've included a quick write-up for the gdb manual.  I'll submit new tests
> for the testsuite shortly.
> 
> 2001-12-18  Don Howard  <dhoward@redhat.com>
> 
>         * cli/cli-script.h: New function.
>         * cli/cli-script.c (build_command_line): Add support for try
>         command.
>         (print_command_lines): Ditto.
>         (print_command_line): Ditto.
>         (execute_control_command): Ditto.
>         (read_next_line): Ditto.
>         (recurse_read_control_structure): Ditto.
>         (captured_execute_control_command): New function.
>         (try_command): Ditto.
>         * cli/cli-cmds.c (init_cli_cmds): Add try command.
>         * defs.h (enum misc_command_type): Added enum except_command.
>          (enum command_control_type): Exclude zero from the range of
>          command_control_type. Added enum try_control.
> 
> 2001-12-18  Don Howard  <dhoward@redhat.com>
> 
>         * gdb.texinfo (User-defined commands): New section, documenting
>         try/except feature.
> 
> Index: defs.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/defs.h,v
> retrieving revision 1.68
> diff -p -u -w -r1.68 defs.h
> --- defs.h      2001/12/15 16:53:22     1.68
> +++ defs.h      2001/12/18 23:45:33
> @@ -811,16 +811,18 @@ enum misc_command_type
>      ok_command,
>      end_command,
>      else_command,
> +    except_command,
>      nop_command
>    };
> 
>  enum command_control_type
>    {
> -    simple_control,
> +    simple_control = 1,
>      break_control,
>      continue_control,
>      while_control,
>      if_control,
> +    try_control,
>      invalid_control
>    };
> 
> Index: cli/cli-cmds.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v
> retrieving revision 1.10
> diff -p -u -w -r1.10 cli-cmds.c
> --- cli-cmds.c  2001/09/01 21:38:05     1.10
> +++ cli-cmds.c  2001/12/18 23:45:34
> @@ -721,6 +721,12 @@ The conditional expression must follow t
>  followed by a new line.  The nested commands must be entered one per line,\n\
>  and should be terminated by the word `end'.");
> 
> +  add_com ("try", class_support, try_command,
> +"Execute nested commands. On error, terminate execution of the 'try' block\n\
> +and execute the optional 'except' block. Commands must be entered one per line,\n\
> +terminating with the word 'end'.");
> +
> +
>    add_com ("if", class_support, if_command,
>            "Execute nested commands once IF the conditional expression is non zero.\n\
>  The conditional expression must follow the word `if' and must in turn be\n\
> Index: cli/cli-script.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/cli/cli-script.c,v
> retrieving revision 1.8
> diff -p -u -w -r1.8 cli-script.c
> --- cli-script.c        2001/12/13 22:42:23     1.8
> +++ cli-script.c        2001/12/18 23:45:34
> @@ -83,7 +83,7 @@ build_command_line (enum command_control
>  {
>    struct command_line *cmd;
> 
> -  if (args == NULL)
> +  if (args == NULL && type != try_control)
>      error ("if/while commands require arguments.\n");
> 
>    cmd = (struct command_line *) xmalloc (sizeof (struct command_line));
> @@ -95,7 +95,12 @@ build_command_line (enum command_control
>      = (struct command_line **) xmalloc (sizeof (struct command_line *)
>                                         * cmd->body_count);
>    memset (cmd->body_list, 0, sizeof (struct command_line *) * cmd->body_count);
> +
> +  if (type != try_control)
>    cmd->line = savestring (args, strlen (args));
> +  else
> +    cmd->line = savestring ("", strlen (""));
> +
>    return cmd;
>  }
> 
> @@ -208,6 +213,33 @@ print_command_lines (struct ui_out *uiou
>           continue;
>         }
> 
> +      /* A try command.  Recursively print the try and catch blocks
> +        before continuing.  */
> +      if (list->control_type == try_control)
> +       {
> +        ui_out_field_string (uiout, NULL, "try");
> +         ui_out_text (uiout, "\n");
> +         /* The true arm. */
> +         print_command_lines (uiout, list->body_list[0], depth + 1);
> +
> +         /* Show the except arm if it exists.  */
> +         if (list->body_count == 2)
> +           {
> +             if (depth)
> +               ui_out_spaces (uiout, 2 * depth);
> +             ui_out_field_string (uiout, NULL, "except");
> +             ui_out_text (uiout, "\n");
> +             print_command_lines (uiout, list->body_list[1], depth + 1);
> +           }
> +
> +         if (depth)
> +           ui_out_spaces (uiout, 2 * depth);
> +         ui_out_field_string (uiout, NULL, "end");
> +         ui_out_text (uiout, "\n");
> +         list = list->next;
> +         continue;
> +       }
> +
>        /* ignore illegal command type and try next */
>        list = list->next;
>      }                          /* while (list) */
> @@ -290,7 +322,33 @@ print_command_line (struct command_line
>         }
>        fputs_filtered ("end\n", stream);
>      }
> +
> +  /* A try command.  Recursively print both try and catch blocks.  */
> +  if (cmd->control_type == try_control)
> +    {
> +      fputs_filtered ("try\n", stream);
> +      /* The true arm. */
> +      print_command_line (cmd->body_list[0], depth + 1, stream);
> +
> +      /* Show the catch block if it exists.  */
> +      if (cmd->body_count == 2)
> +       {
> +         if (depth)
> +           {
> +             for (i = 0; i < depth; i++)
> +               fputs_filtered ("  ", stream);
> +           }
> +         fputs_filtered ("except\n", stream);
> +         print_command_line (cmd->body_list[1], depth + 1, stream);
> +       }
> +      if (depth)
> +       {
> +         for (i = 0; i < depth; i++)
> +           fputs_filtered ("  ", stream);
>  }
> +      fputs_filtered ("end\n", stream);
> +    }
> +}
>  #endif
> 
>  /* Execute the command in CMD.  */
> @@ -326,6 +384,13 @@ execute_user_command (struct cmd_list_el
>    do_cleanups (old_chain);
>  }
> 
> +static int
> +captured_execute_control_command (PTR arg)
> +{
> +  struct command_line * cmd = (struct command_line *) arg;
> +  return execute_control_command (cmd);
> +}
> +
>  enum command_control_type
>  execute_control_command (struct command_line *cmd)
>  {
> @@ -459,6 +524,30 @@ execute_control_command (struct command_
>         break;
>        }
> 
> +    case try_control:
> +      {
> +       current = cmd->body_list[0];
> +
> +       while (current)
> +         {
> +           ret = catch_errors (captured_execute_control_command, current,
> +                               "", RETURN_MASK_ALL);
> +
> +           if (ret == 0 || ret == invalid_control)
> +             {
> +               if (cmd->body_count == 2)
> +                 current = cmd->body_list[1];
> +               else
> +                 current = NULL;
> +             }
> +           else
> +             {
> +               current = current->next;
> +             }
> +         }
> +       break;
> +      }
> +
>      default:
>        warning ("Invalid control type in command structure.");
>        return invalid_control;
> @@ -506,6 +595,21 @@ if_command (char *arg, int from_tty)
>    free_command_lines (&command);
>  }
> 
> +void
> +try_command (char *block, int from_tty)
> +{
> +  struct command_line *command = NULL;
> +
> +  control_level = 1;
> +  command = get_command_line (try_control, block);
> +
> +  if (command == NULL)
> +    return;
> +
> +  execute_control_command (command);
> +  free_command_lines (&command);
> +}
> +
>  /* Cleanup */
>  static void
>  arg_cleanup (void *ignore)
> @@ -758,12 +862,18 @@ read_next_line (struct command_line **co
>    if (p1 - p == 4 && !strncmp (p, "else", 4))
>      return else_command;
> 
> +  /* Is the except clause of an if try structure?  */
> +  if (p1 - p == 6 && !strncmp (p, "except", 6))
> +    return except_command;
> +
>    /* Check for while, if, break, continue, etc and build a new command
>       line structure for them.  */
>    if (p1 - p > 5 && !strncmp (p, "while", 5))
>      *command = build_command_line (while_control, p + 6);
>    else if (p1 - p > 2 && !strncmp (p, "if", 2))
>      *command = build_command_line (if_control, p + 3);
> +  else if (p1 - p == 3 && !strncmp (p, "try", 3))
> +    *command = build_command_line (try_control, p + 4);
>    else if (p1 - p == 10 && !strncmp (p, "loop_break", 10))
>      {
>        *command = (struct command_line *)
> @@ -845,7 +955,8 @@ recurse_read_control_structure (struct c
>        if (val == end_command)
>         {
>           if (current_cmd->control_type == while_control
> -             || current_cmd->control_type == if_control)
> +             || current_cmd->control_type == if_control
> +              || current_cmd->control_type == try_control)
>             {
>               /* Success reading an entire control structure.  */
>               ret = simple_control;
> @@ -876,6 +987,23 @@ recurse_read_control_structure (struct c
>             }
>         }
> 
> +      if (val == except_command)
> +        {
> +          if (current_cmd->control_type == try_control
> +              && current_body == 1)
> +            {
> +              realloc_body_list (current_cmd, 2);
> +              current_body = 2;
> +              child_tail = NULL;
> +              continue;
> +            }
> +          else
> +            {
> +              ret = invalid_control;
> +              break;
> +            }
> +        }
> +
>        if (child_tail)
>         {
>           child_tail->next = next;
> @@ -895,7 +1023,8 @@ recurse_read_control_structure (struct c
>        /* If the latest line is another control structure, then recurse
>           on it.  */
>        if (next->control_type == while_control
> -         || next->control_type == if_control)
> +          || next->control_type == if_control
> +          || next->control_type == try_control)
>         {
>           control_level++;
>           ret = recurse_read_control_structure (next);
> @@ -962,7 +1091,8 @@ read_command_lines (char *prompt_arg, in
>         }
> 
>        if (next->control_type == while_control
> -         || next->control_type == if_control)
> +          || next->control_type == if_control
> +          || next->control_type == try_control)
>         {
>           control_level++;
>           ret = recurse_read_control_structure (next);
> Index: cli/cli-script.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/cli/cli-script.h,v
> retrieving revision 1.2
> diff -p -u -w -r1.2 cli-script.h
> --- cli-script.h        2001/03/06 08:21:20     1.2
> +++ cli-script.h        2001/12/18 23:45:34
> @@ -31,6 +31,8 @@ extern void while_command (char *arg, in
> 
>  extern void if_command (char *arg, int from_tty);
> 
> +extern void try_command (char *block, int from_tty);
> +
>  extern void show_user_1 (struct cmd_list_element *c, struct ui_file *stream);
> 
>  /* Exported to gdb/breakpoint.c */
> Index: doc/gdb.texinfo
> ===================================================================
> RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
> retrieving revision 1.59
> diff -p -u -w -r1.59 gdb.texinfo
> --- gdb.texinfo 2001/11/30 23:03:09     1.59
> +++ gdb.texinfo 2001/12/18 23:45:47
> @@ -13323,6 +13323,17 @@ execute, one per line, terminated by an
>  The commands are executed repeatedly as long as the expression
>  evaluates to true.
> 
> +@kindex try
> +@kindex except
> +@item try
> +Takes no arguments and must be followed by a series of commands to be
> +executed, one per line.  Errors in the series of commands will terminate
> +execution of the series, but not the entire script.  There can be and
> +optional @code{except} line, which must also be followed by a series of
> +commands, one per line.  Commands in the @code{except} block are
> +executed if an error is encountered in the corresponding @code{try}
> +block.
> +
>  @kindex document
>  @item document @var{commandname}
>  Document the user-defined command @var{commandname}, so that it can be
> 
> --
> dhoward@redhat.com
> gdb engineering

-- 
Fernando Nasser
Red Hat - Toronto                       E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9


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