From 2ece43e3941ee011937b8f90a6878d62ffb5e3f1 Mon Sep 17 00:00:00 2001 From: Ian MacLarty Date: Tue, 13 Jun 2006 09:49:04 +0000 Subject: [PATCH] Add a new mdb command, 'shell', that allows users to execute shell commands Estimated hours taken: 5 Branches: main Add a new mdb command, 'shell', that allows users to execute shell commands from within the debugger. Allow the user to give up to nine additional arguments to the 'source' command. Occurrences of the strings "$1" through "$9" in the sourced file are replaced by the corresponding additional arguments, allowing for parameterised scripts. Use the two new features mentioned above to add two more mdb commands: one to open a term, goal or exception in an external editor another command to perform a grep on a term, goal or exception (useful for seeing if a value occurs in a big map, for example). NEWS Mention the new commands. doc/mdb_categories: doc/user_guide.texi: Document the new commands. scripts/Mmakefile: scripts/mdb_open: scripts/mdb_vim: Add scripts for the new commands. scripts/mdbrc.in: Add aliases for the new shell, emacs, grep and vim commands. tests/debugger/completion.exp: tests/debugger/mdb_command_test.inp: Adjust for new commands. tests/debugger/save.exp: tests/debugger/save.exp2: Adjust for new commands. Replace system dependent strings with ZZZ instead of XXX. tests/debugger/Mmakefile: tests/debugger/shell.exp: tests/debugger/shell.inp: tests/debugger/shell.m: tests/debugger/shell_test_script: Test the shell and source commands. trace/mercury_trace_cmd_misc.c: Check if there are extra arguments to the source mdb command and pass them to MR_trace_source if there are. trace/mercury_trace_cmd_misc.h: Add shell command handling function prototype. trace/mercury_trace_declarative.c: Call MR_trace_call_system_display_error_on_failure instead of system when displaying benchmarking statistics for the declarative debugger. trace/mercury_trace_internal.c: trace/mercury_trace_internal.h: Implement the shell command and extend the source command to handle the optional extra arguments. trace/mercury_trace_readline.c: trace/mercury_trace_readline.h: Add a new function to read a line and replace all the occurrences of "$[1-9]" with the corresponding value from an array. Delete comments in the .c file that are duplicated in the .h file. trace/mercury_trace_util.c: trace/mercury_trace_util.h: Implement MR_trace_call_system_display_error_on_failure that executes a system call and displays an error message if the system call terminates abnormally. --- NEWS | 51 ++++++++++++++++++- doc/mdb_categories | 6 +-- doc/user_guide.texi | 22 ++++++++- scripts/Mmakefile | 8 ++- scripts/mdb_grep | 3 ++ scripts/mdb_open | 3 ++ scripts/mdbrc.in | 3 ++ tests/debugger/Mmakefile | 12 +++-- tests/debugger/completion.exp | 76 +++++++++++++++-------------- tests/debugger/mdb_command_test.inp | 2 + tests/debugger/save.exp | 3 ++ tests/debugger/save.exp2 | 7 ++- tests/debugger/shell.exp | 16 ++++++ tests/debugger/shell.inp | 6 +++ tests/debugger/shell.m | 12 +++++ tests/debugger/shell_test_script | 3 ++ trace/mercury_trace_cmd_misc.c | 11 ++++- trace/mercury_trace_cmd_misc.h | 1 + trace/mercury_trace_declarative.c | 2 +- trace/mercury_trace_internal.c | 44 ++++++++++++++--- trace/mercury_trace_internal.h | 5 +- trace/mercury_trace_readline.c | 74 ++++++++++++++++++++++------ trace/mercury_trace_readline.h | 14 +++++- trace/mercury_trace_util.c | 18 +++++++ trace/mercury_trace_util.h | 9 ++++ 25 files changed, 334 insertions(+), 77 deletions(-) create mode 100644 scripts/mdb_grep create mode 100644 scripts/mdb_open create mode 100644 tests/debugger/shell.exp create mode 100644 tests/debugger/shell.inp create mode 100644 tests/debugger/shell.m create mode 100644 tests/debugger/shell_test_script diff --git a/NEWS b/NEWS index 8f6f39560..ca8035ce8 100644 --- a/NEWS +++ b/NEWS @@ -69,6 +69,12 @@ Changes to the Mercury debugger: left the goal at which the term was available as the value of a program variable. * Users can now see the set of places where two terms differ from each other. +* Users can now execute system shell commands from within the debugger. +* The source command now accepts optional additional arguments which + are substituted into the sourced file, allowing for parameterised + scripts. +* Users can now open terms in their favorite editor, or + perform a grep on a term. * The `set' command has been replaced by several other commands: the `format', `format_param', `list_context_lines', `list_path', `xml_browser_cmd', `xml_tmp_filename', `fail_trace_counts', `pass_trace_counts' and @@ -77,8 +83,9 @@ Changes to the Mercury debugger: * The `save' command now saves the entire persistent state of the debugger (with one small exception that cannot be reestablished by an mdb command from an arbitrary point of execution). -* The declarative debugger now supports an `undo' command, and allows users to - select the search algorithm. +* The declarative debugger now supports an `undo' command. +* The declarative debugger now allows users to + change the search algorithm mid-session. * The declarative debugger can now exploit information from the "code footprints" of passed and failed test cases to find bugs with fewer questions. We have also added two tools, mslice and mdice, to manipulate @@ -314,6 +321,46 @@ Changes to the Mercury compiler: in which the format string or the structure of the list of values to be printed are not statically available. +Changes to the Mercury debugger: + +* A `list' command has ben added that displays a listing of the source code + lines referred to by the current environment. To supporting commands + `pop_list_dir' and `push_list_dir' have also been added. + +* Users can now keep hold of a term, referring to it even when execution has + left the goal at which the term was available as the value of a program + variable. The name of the new command is `hold'. + +* A `diff' command has been added that allows users to see the set of places + where two terms differ from each other. + +* A `shell' (or `!' for short) command has been added that allows users to + execute system shell commands from within the debugger. + +* The `source' command now accepts optional additional arguments which + are substituted into the sourced file, allowing for parameterised + scripts. The strings "$1" through "$9" in the sourced file are replaced with + the corresponding argument of the `source' command. + +* The above two features have been used to create two additional commands: an + `open' command that lets users open a term in their favorite editor for + browsing and a `grep' command that can be used to check if a term contains + a particular pattern. + +* The declarative debugger now allows users to take back answers they gave + by means of an multi-level `undo' command. + +* The declarative debugger now allows users to change the search algorithm + mid-session by means of a `mode' command. + +* The declarative debugger can now exploit information from the "code + footprints" of passed and failed test cases to find bugs with fewer + questions. We have also added two tools, mslice and mdice, to manipulate + files containing such footprints. + +* Subterm dependency tracking in the declarative debugger is now significantly + faster. + Changes to the extras distribution: * We've added a library of data structures designed to work for solver types. diff --git a/doc/mdb_categories b/doc/mdb_categories index 987a38138..bbce75534 100644 --- a/doc/mdb_categories +++ b/doc/mdb_categories @@ -27,7 +27,7 @@ document_category 400 browsing browsing - Commands that let users explore the state of the computation. The browsing commands are `vars', `held_vars', `print', `browse', `stack', `up', `down', `level', `current', `view', `hold', - `diff', `dump', and `list'. + `diff', `dump', `grep', `list' and `open'. end document_category 500 breakpoint @@ -70,8 +70,8 @@ decl - Commands available from within the declarative debugger. These end document_category 900 misc misc - Commands that are of interest to most users but do not fit into - other categories. The misc commands are `source', `save' and - `quit'. + other categories. The misc commands are `source', `save', `shell' + and `quit'. end document_category 1000 exp diff --git a/doc/user_guide.texi b/doc/user_guide.texi index f9a28246a..3017c779f 100644 --- a/doc/user_guide.texi +++ b/doc/user_guide.texi @@ -2870,6 +2870,22 @@ Writes the value of the variable in the current environment with the given ordinal number or with the given name to the specified file. The option @samp{-x} (or @samp{--xml}) causes the output to be in XML. +@sp 1 +@item open @var{term} +Save @var{term} to a temporary file and open the file in an editor. +The environment variable EDITOR is consulted to determine what editor to +use. +If this environment variable is not set then @samp{vi} is used. +@var{term} may be any term that can be saved to a file with the +@samp{save_to_file} command. +@sp 1 +@item grep @var{pattern} @var{term} +Save the given term to a temporary file and perform a grep on the +file using @var{pattern}. +@var{term} may be any term that can be saved to a file with the +@samp{save_to_file} command. +The unix `grep' command must be available from the shell for this command +to work. @c @sp 1 @c @item dump [-x] proc_body @var{filename} @c Writes the representation of the body of the current procedure, @@ -3799,9 +3815,13 @@ and its submodules, if any. @sp 1 @table @code -@item source [-i] @var{filename} +@item source [-i] @var{filename} [@var{args}] @kindex source (mdb command) Executes the commands in the file named @var{filename}. +Optionally a list of at most nine arguments can be given. +Occurrences of the strings "$1" to "$9" in the sourced file +will be replaced by the corresponding arguments given in the source +command before the commands in the sourced file are executed. @sp 1 The option @samp{-i} or @samp{--ignore-errors} tells @samp{mdb} not to complain if the named file does not exist or is not readable. diff --git a/scripts/Mmakefile b/scripts/Mmakefile index 67f86d6b0..addb2c407 100644 --- a/scripts/Mmakefile +++ b/scripts/Mmakefile @@ -45,10 +45,14 @@ CONF_FILES = \ Mmake.vars \ parse_ml_options.sh-subr -CONF_DEBUG_SCRIPTS = \ +CONF_DEBUG_SCRIPTS = \ mdbrc -DEBUGGER_SCRIPTS = $(CONF_DEBUG_SCRIPTS) xul_tree.xsl +DEBUGGER_SCRIPTS = $(CONF_DEBUG_SCRIPTS) \ + xul_tree.xsl \ + mdb_open \ + mdb_grep + EMACS_SCRIPTS = gud.el #-----------------------------------------------------------------------------# diff --git a/scripts/mdb_grep b/scripts/mdb_grep new file mode 100644 index 000000000..961f15c17 --- /dev/null +++ b/scripts/mdb_grep @@ -0,0 +1,3 @@ +save_to_file $2 .mdb_grep_tmp +shell grep $1 .mdb_grep_tmp +shell rm .mdb_grep_tmp diff --git a/scripts/mdb_open b/scripts/mdb_open new file mode 100644 index 000000000..c22b2013e --- /dev/null +++ b/scripts/mdb_open @@ -0,0 +1,3 @@ +save_to_file $1 .mdb_open_tmp +shell ${EDITOR-vi} .mdb_open_tmp +shell rm .mdb_open_tmp diff --git a/scripts/mdbrc.in b/scripts/mdbrc.in index 8dc39cf3a..2e83e18e2 100644 --- a/scripts/mdbrc.in +++ b/scripts/mdbrc.in @@ -15,5 +15,8 @@ alias excp exception alias e exception alias EMPTY step alias NUMBER step +alias ! shell +alias open source @DEFAULT_MERCURY_DEBUGGER_INIT_DIR@/mdb_open +alias grep source @DEFAULT_MERCURY_DEBUGGER_INIT_DIR@/mdb_grep xml_browser_cmd '@DEFAULT_XML_BROWSER_CMD@' xml_tmp_filename '@DEFAULT_XML_TMP_FILENAME@' diff --git a/tests/debugger/Mmakefile b/tests/debugger/Mmakefile index a923df855..a4e489691 100644 --- a/tests/debugger/Mmakefile +++ b/tests/debugger/Mmakefile @@ -47,6 +47,7 @@ NONRETRY_PROGS = \ print_table \ queens_rep \ resume_typeinfos \ + shell \ save \ solver_test \ type_desc_test \ @@ -469,13 +470,18 @@ retry.out: retry retry.inp # with a known character sequence. save.out: save save.inp $(MDB) ./save < save.inp 2>&1 | \ - sed 's/xml_browser_cmd.*/xml_browser_cmd XXX/g' | \ - sed 's/xml_tmp_filename.*/xml_tmp_filename XXX/g' \ - > save.out 2>&1 + sed 's/xml_browser_cmd.*/xml_browser_cmd ZZZ/g' | \ + sed 's/xml_tmp_filename.*/xml_tmp_filename ZZZ/g' | \ + sed 's/^alias grep source.*$$/alias grep source ZZZ\/mdb_grep/' | \ + sed 's/^alias open source.*$$/alias open source ZZZ\/mdb_open/' \ + > save.out 2>&1 shallow.out: shallow shallow.inp $(MDB) ./shallow < shallow.inp > shallow.out 2>&1 +shell.out: shell shell.inp + $(MDB_STD) ./shell < shell.inp > shell.out 2>&1 + solver_test.out: solver_test solver_test.inp $(MDB_STD) ./solver_test < solver_test.inp > solver_test.out 2>&1 diff --git a/tests/debugger/completion.exp b/tests/debugger/completion.exp index fc46f508b..4e000fd7f 100644 --- a/tests/debugger/completion.exp +++ b/tests/debugger/completion.exp @@ -3,43 +3,45 @@ mdb> echo on Command echo enabled. mdb> register --quiet mdb> -? excp print_optionals -P f printlevel -alias fail_trace_counts procedures -all_class_decls finish push_list_dir -all_procedures flag query -all_regs format quit -all_type_ctors format_param r -ambiguity forward register -b g retry -break gen_stack return -break_print goal_paths s -browse goto save -c h scope -cc_query held_vars scroll -class_decl help source -clear_histogram histogram_all stack -condition histogram_exp stack_default_limit -consumer hold stack_regs -context ignore stats -continue io_query step -current level subgoal -cut_stack list table -d list_context_lines table_io -dd list_path term_size -debug_vars max_io_actions trust -delete maxdepth trusted -dice mindepth type_ctor -diff mm_stacks unalias -disable mmc_options unhide_events -document modules untrust -document_category next up -down nondet_stack v -dump p var_details -e pass_trace_counts vars -echo pneg_stack view -enable pop_list_dir xml_browser_cmd -exception print xml_tmp_filename +! f printlevel +? fail_trace_counts procedures +P finish push_list_dir +alias flag query +all_class_decls format quit +all_procedures format_param r +all_regs forward register +all_type_ctors g retry +ambiguity gen_stack return +b goal_paths s +break goto save +break_print grep scope +browse h scroll +c held_vars shell +cc_query help source +class_decl histogram_all stack +clear_histogram histogram_exp stack_default_limit +condition hold stack_regs +consumer ignore stats +context io_query step +continue level subgoal +current list table +cut_stack list_context_lines table_io +d list_path term_size +dd max_io_actions trust +debug_vars maxdepth trusted +delete mindepth type_ctor +dice mm_stacks unalias +diff mmc_options unhide_events +disable modules untrust +document next up +document_category nondet_stack v +down open var_details +dump p vars +e pass_trace_counts view +echo pneg_stack xml_browser_cmd +enable pop_list_dir xml_tmp_filename +exception print +excp print_optionals h help histogram_exp held_vars histogram_all hold var_details vars view diff --git a/tests/debugger/mdb_command_test.inp b/tests/debugger/mdb_command_test.inp index 5b98779bb..9d44c380b 100644 --- a/tests/debugger/mdb_command_test.inp +++ b/tests/debugger/mdb_command_test.inp @@ -46,6 +46,8 @@ view xyzzy xyzzy xyzzy xyzzy xyzzy hold xyzzy xyzzy xyzzy xyzzy xyzzy diff xyzzy xyzzy xyzzy xyzzy xyzzy dump xyzzy xyzzy xyzzy xyzzy xyzzy +open xyzzy xyzzy xyzzy xyzzy xyzzy +grep xyzzy xyzzy xyzzy xyzzy xyzzy list xyzzy xyzzy xyzzy xyzzy xyzzy break xyzzy xyzzy xyzzy xyzzy xyzzy condition xyzzy xyzzy xyzzy xyzzy xyzzy diff --git a/tests/debugger/save.exp b/tests/debugger/save.exp index 7cdc9238a..827a01689 100644 --- a/tests/debugger/save.exp +++ b/tests/debugger/save.exp @@ -21,6 +21,7 @@ mdb> save save_file Debugger state saved to save_file. mdb> continue -n -S [1, 3, 5, 2, 4] +alias ! shell alias ? help alias EMPTY step alias NUMBER step @@ -32,7 +33,9 @@ alias e exception alias excp exception alias f finish alias g goto +alias grep source ZZZ/mdb_grep alias h help +alias open source ZZZ/mdb_open alias p print alias r retry alias s step diff --git a/tests/debugger/save.exp2 b/tests/debugger/save.exp2 index 0f07d9b4c..78a5cc01a 100644 --- a/tests/debugger/save.exp2 +++ b/tests/debugger/save.exp2 @@ -21,6 +21,7 @@ mdb> save save_file Debugger state saved to save_file. mdb> continue -n -S [1, 3, 5, 2, 4] +alias ! shell alias ? help alias EMPTY step alias NUMBER step @@ -32,7 +33,9 @@ alias e exception alias excp exception alias f finish alias g goto +alias grep source ZZZ/mdb_grep alias h help +alias open source ZZZ/mdb_open alias p print alias r retry alias s step @@ -101,8 +104,8 @@ format_param -A -p size 10 format_param -A -p width 80 format_param -A -p lines 2 max_io_actions 20 -xml_browser_cmd XXX -xml_tmp_filename XXX +xml_browser_cmd ZZZ +xml_tmp_filename ZZZ trust save trust std lib list_context_lines 2 diff --git a/tests/debugger/shell.exp b/tests/debugger/shell.exp new file mode 100644 index 000000000..b23bbdc3c --- /dev/null +++ b/tests/debugger/shell.exp @@ -0,0 +1,16 @@ + E1: C1 CALL pred shell.main/2-0 (det) shell.m:11 +mdb> echo on +Command echo enabled. +mdb> shell echo hello +hello +mdb> alias test source shell_test_script +test => source shell_test_script +mdb> test value1 value2 3 'value 4' "a" '' 'b' file_name.ext 9 +value1 value2 +value2 value1 +value1 value2 $ $abc 3 value 4 a b file_name.ext 9 $0 $b $ +mdb> test only_one_value +only_one_value +only_one_value +only_one_value $ $abc $0 $b $ +mdb> quit -y diff --git a/tests/debugger/shell.inp b/tests/debugger/shell.inp new file mode 100644 index 000000000..a6f58d277 --- /dev/null +++ b/tests/debugger/shell.inp @@ -0,0 +1,6 @@ +echo on +shell echo hello +alias test source shell_test_script +test value1 value2 3 'value 4' "a" '' 'b' file_name.ext 9 +test only_one_value +quit -y diff --git a/tests/debugger/shell.m b/tests/debugger/shell.m new file mode 100644 index 000000000..2d6869f8a --- /dev/null +++ b/tests/debugger/shell.m @@ -0,0 +1,12 @@ +:- module shell. + +:- interface. + +:- import_module io. + +:- pred main(io::di, io::uo) is det. + +:- implementation. + +main(!IO) :- + nl(!IO). diff --git a/tests/debugger/shell_test_script b/tests/debugger/shell_test_script new file mode 100644 index 000000000..cbf7199fe --- /dev/null +++ b/tests/debugger/shell_test_script @@ -0,0 +1,3 @@ +shell echo $1 $2 +shell echo $2 $1 +shell echo $1 $2 $ \\$abc $3 $4 $5 $6 $7 $8 $9 \\$0 \\$b $ diff --git a/trace/mercury_trace_cmd_misc.c b/trace/mercury_trace_cmd_misc.c index f2993e230..b81b8a99e 100644 --- a/trace/mercury_trace_cmd_misc.c +++ b/trace/mercury_trace_cmd_misc.c @@ -47,17 +47,24 @@ MR_trace_cmd_source(char **words, int word_count, MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info, MR_Code **jumpaddr) { MR_bool ignore_errors; + char **args; ignore_errors = MR_FALSE; if (! MR_trace_options_ignore(&ignore_errors, &words, &word_count)) { ; /* the usage message has already been printed */ - } else if (word_count == 2) { + } else if (word_count >= 2) { /* ** If the source fails, the error message ** will have already been printed by MR_trace_source ** (unless ignore_errors suppresses the message). */ - (void) MR_trace_source(words[1], ignore_errors); + if (word_count == 2) { + args = NULL; + } else { + args = &words[2]; + } + (void) MR_trace_source(words[1], ignore_errors, args, + word_count - 2); } else { MR_trace_usage_cur_cmd(); } diff --git a/trace/mercury_trace_cmd_misc.h b/trace/mercury_trace_cmd_misc.h index 3737dcbd7..edf7983fa 100644 --- a/trace/mercury_trace_cmd_misc.h +++ b/trace/mercury_trace_cmd_misc.h @@ -11,6 +11,7 @@ extern MR_TraceCmdFunc MR_trace_cmd_source; extern MR_TraceCmdFunc MR_trace_cmd_save; +extern MR_TraceCmdFunc MR_trace_cmd_shell; extern MR_TraceCmdFunc MR_trace_cmd_quit; extern const char *const MR_trace_source_cmd_args[]; diff --git a/trace/mercury_trace_declarative.c b/trace/mercury_trace_declarative.c index 0bf816d51..e1e1343c5 100644 --- a/trace/mercury_trace_declarative.c +++ b/trace/mercury_trace_declarative.c @@ -2434,7 +2434,7 @@ MR_decl_print_edt_stats(void) pid = getpid(); sprintf(cmdstr, "ps -p %i -o rss,vsz | tail -1 |" "awk '{print \"RSS = \" $1 \"\\nVSZ = \" $2}' 1>&2", pid); - system(cmdstr); + MR_trace_call_system_display_error_on_failure(stderr, cmdstr); MR_debug_enabled = MR_FALSE; MR_update_trace_func_enabled(); diff --git a/trace/mercury_trace_internal.c b/trace/mercury_trace_internal.c index bff333369..309a3473d 100644 --- a/trace/mercury_trace_internal.c +++ b/trace/mercury_trace_internal.c @@ -634,7 +634,7 @@ MR_trace_internal_init_from_env(void) init = getenv("MERCURY_DEBUGGER_INIT"); if (init != NULL) { - (void) MR_trace_source(init, MR_FALSE); + (void) MR_trace_source(init, MR_FALSE, NULL, 0); /* If the source failed, the error message has been printed. */ } } @@ -647,7 +647,7 @@ MR_trace_internal_init_from_local(void) init = MDBRC_FILENAME; if ((fp = fopen(init, "r")) != NULL) { - MR_trace_source_from_open_file(fp); + MR_trace_source_from_open_file(fp, NULL, 0); fclose(fp); } } @@ -671,7 +671,7 @@ MR_trace_internal_init_from_home_dir(void) (void) strcat(buf, "/"); (void) strcat(buf, MDBRC_FILENAME); if ((fp = fopen(buf, "r")) != NULL) { - MR_trace_source_from_open_file(fp); + MR_trace_source_from_open_file(fp, NULL, 0); fclose(fp); } @@ -679,12 +679,13 @@ MR_trace_internal_init_from_home_dir(void) } MR_bool -MR_trace_source(const char *filename, MR_bool ignore_errors) +MR_trace_source(const char *filename, MR_bool ignore_errors, + char** args, int num_args) { FILE *fp; if ((fp = fopen(filename, "r")) != NULL) { - MR_trace_source_from_open_file(fp); + MR_trace_source_from_open_file(fp, args, num_args); fclose(fp); return MR_TRUE; } @@ -698,7 +699,7 @@ MR_trace_source(const char *filename, MR_bool ignore_errors) } void -MR_trace_source_from_open_file(FILE *fp) +MR_trace_source_from_open_file(FILE *fp, char **args, int num_args) { char *contents; MR_Line *line; @@ -713,7 +714,9 @@ MR_trace_source_from_open_file(FILE *fp) ** preserving their order in the sourced file. */ - while ((contents = MR_trace_readline_raw(fp)) != NULL) { + while ((contents = MR_trace_readline_expand_args(fp, args, num_args)) + != NULL) + { line = MR_NEW(MR_Line); line->MR_line_contents = MR_copy_string(contents); @@ -751,6 +754,31 @@ MR_trace_do_noop(void) ** MR_process_matching_procedures(). */ +static MR_Next +MR_trace_cmd_shell(char **words, int word_count, MR_Trace_Cmd_Info *cmd, + MR_Event_Info *event_info, MR_Code **jumpaddr) +{ + char* command_string; + size_t command_string_length; + int word_num; + + command_string_length = 1; + for (word_num = 1; word_num < word_count; word_num++) { + command_string_length += strlen(words[word_num]) + 1; + } + command_string = (char*) MR_malloc(sizeof(char) * command_string_length); + command_string[0] = '\0'; + for (word_num = 1; word_num < word_count; word_num++) { + strcat(command_string, words[word_num]); + strcat(command_string, " "); + } + + MR_trace_call_system_display_error_on_failure(MR_mdb_err, command_string); + MR_free(command_string); + + return KEEP_INTERACTING; +} + static void MR_mdb_print_proc_id_and_nl(void *data, const MR_Proc_Layout *entry_layout) { @@ -1628,6 +1656,8 @@ static const MR_Trace_Command_Info MR_trace_command_infos[] = NULL, MR_trace_filename_completer }, { "misc", "quit", MR_trace_cmd_quit, MR_trace_quit_cmd_args, MR_trace_null_completer }, + { "misc", "shell", MR_trace_cmd_shell, + NULL, MR_trace_null_completer }, { "exp", "histogram_all", MR_trace_cmd_histogram_all, NULL, MR_trace_filename_completer }, diff --git a/trace/mercury_trace_internal.h b/trace/mercury_trace_internal.h index 83a1201d0..5ba70703a 100644 --- a/trace/mercury_trace_internal.h +++ b/trace/mercury_trace_internal.h @@ -83,13 +83,14 @@ extern MR_Trace_Source_Server MR_trace_source_server; */ extern MR_bool MR_trace_source(const char *filename, - MR_bool ignore_errors); + MR_bool ignore_errors, char** args, int num_args); /* ** Source commands from the given file. */ -extern void MR_trace_source_from_open_file(FILE *fp); +extern void MR_trace_source_from_open_file(FILE *fp, + char **args, int num_args); /* ** Print a usage message for the currently executing command. diff --git a/trace/mercury_trace_readline.c b/trace/mercury_trace_readline.c index cf61f3f7f..c66ae9596 100644 --- a/trace/mercury_trace_readline.c +++ b/trace/mercury_trace_readline.c @@ -1,5 +1,5 @@ /* -** Copyright (C) 1998-2002, 2005 The University of Melbourne. +** Copyright (C) 1998-2002, 2005-2006 The University of Melbourne. ** This file may only be copied under the terms of the GNU Library General ** Public License - see the file COPYING.LIB in the Mercury distribution. */ @@ -50,13 +50,6 @@ static void MR_dummy_prep_term_function(int ignored); static void MR_dummy_deprep_term_function(void); -/* -** Print the prompt to the `out' file, read a line from the `in' file, -** and return it in a MR_malloc'd buffer holding the line (without the -** final newline). -** If EOF occurs on a nonempty line, treat the EOF as a newline; if EOF -** occurs on an empty line, return NULL. -*/ char * MR_trace_readline(const char *prompt, FILE *in, FILE *out) { @@ -147,12 +140,6 @@ MR_trace_readline(const char *prompt, FILE *in, FILE *out) return MR_trace_readline_raw(in); } -/* -** Read a line from a file, and return a pointer to a MR_malloc'd buffer -** holding the line (without the final newline). If EOF occurs on a -** nonempty line, treat the EOF as a newline; if EOF occurs on an empty -** line, return NULL. -*/ char * MR_trace_readline_raw(FILE *fp) { @@ -180,6 +167,65 @@ MR_trace_readline_raw(FILE *fp) } } +char * +MR_trace_readline_expand_args(FILE *fp, char **args, int num_args) +{ + char *line; + size_t line_length; + int line_index; + size_t expanded_line_length; + char *expanded_line; + int expanded_line_index; + int arg_num; + size_t arg_length; + char *arg; + + line = MR_trace_readline_raw(fp); + if (line == NULL) { + return NULL; + } + line_length = strlen(line); + + expanded_line_length = line_length; + expanded_line = (char*) MR_malloc(line_length + 1); + expanded_line[0] = '\0'; + expanded_line_index = 0; + + for (line_index = 0; line_index < line_length; line_index++) { + if ((line[line_index] == '$') && + (line_index < (line_length - 1)) && + (line[line_index + 1] >= '1') && + (line[line_index + 1] <= '9')) + { + arg_num = (int)(line[line_index + 1] - '1'); + if (arg_num < num_args) { + arg = args[arg_num]; + arg_length = strlen(arg); + /* + ** Subtract 2 for the "$n" which will + ** not occur in the expanded string. + */ + expanded_line_length += arg_length - 2; + expanded_line = MR_realloc(expanded_line, + expanded_line_length + 1); + expanded_line[expanded_line_index] = '\0'; + strcat(expanded_line, arg); + expanded_line_index += arg_length; + } + /* Skip the digit after the '$'. */ + line_index++; + } else { + expanded_line[expanded_line_index] = line[line_index]; + expanded_line_index++; + } + } + + MR_free(line); + expanded_line[expanded_line_index] = '\0'; + + return expanded_line; +} + static void MR_dummy_prep_term_function(int ignored) { diff --git a/trace/mercury_trace_readline.h b/trace/mercury_trace_readline.h index 78c3a20a1..c7458a6fd 100644 --- a/trace/mercury_trace_readline.h +++ b/trace/mercury_trace_readline.h @@ -1,5 +1,5 @@ /* -** Copyright (C) 1998-1999 The University of Melbourne. +** Copyright (C) 1998-1999, 2006 The University of Melbourne. ** This file may only be copied under the terms of the GNU Library General ** Public License - see the file COPYING.LIB in the Mercury distribution. */ @@ -28,3 +28,15 @@ char * MR_trace_readline(const char *prompt, FILE *in, FILE *out); ** line, return NULL. Don't use GNU readline. */ char * MR_trace_readline_raw(FILE *in); + +/* +** Read a line from a file and replace occurrences of the strings "$1" to +** "$9" with the corresponding values in the args array. If there is no +** value in the args array, then the "$n" string is replaced by the empty +** string. +** Return a pointer to a MR_malloc'd buffer holding the new string (without +** the final newline). If EOF occurs on a nonempty line, treat the EOF as a +** newline; if EOF occurs on an empty line, return NULL. +** Don't use GNU readline. +*/ +char * MR_trace_readline_expand_args(FILE *fp, char **args, int num_args); diff --git a/trace/mercury_trace_util.c b/trace/mercury_trace_util.c index 042076fed..1a7a042a4 100644 --- a/trace/mercury_trace_util.c +++ b/trace/mercury_trace_util.c @@ -207,3 +207,21 @@ MR_trace_proc_layout_is_builtin_catch(const MR_Proc_Layout *layout) } return MR_FALSE; } + +void +MR_trace_call_system_display_error_on_failure(FILE *err_stream, char *command) +{ + int system_rv; + + if (system(NULL)) { + system_rv = system(command); + if (system_rv != 0) { + fprintf(err_stream, + "mdb: the shell command returned a non-zero exit code or was" + " terminated abnormally.\n", + system_rv); + } + } else { + fprintf(err_stream, "mdb: no shell found.\n"); + } +} diff --git a/trace/mercury_trace_util.h b/trace/mercury_trace_util.h index 0556022c9..1a3e82186 100644 --- a/trace/mercury_trace_util.h +++ b/trace/mercury_trace_util.h @@ -78,4 +78,13 @@ extern void MR_print_debug_vars(FILE *fp, MR_Event_Info *event_info); extern MR_bool MR_trace_proc_layout_is_builtin_catch( const MR_Proc_Layout *layout); +/* +** MR_trace_call_system_display_error_on_failure executes the given command +** and displays an error message if the command returned a non-zero exit +** status, there was a problem executing the command, or no usable shell was +** available. +*/ +extern void MR_trace_call_system_display_error_on_failure( + FILE *err_stream, char *command); + #endif /* MERCURY_TRACE_UTIL_H */