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.
This commit is contained in:
Ian MacLarty
2006-06-13 09:49:04 +00:00
parent fc94027616
commit 2ece43e394
25 changed files with 334 additions and 77 deletions

51
NEWS
View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -48,7 +48,11 @@ CONF_FILES = \
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
#-----------------------------------------------------------------------------#

3
scripts/mdb_grep Normal file
View File

@@ -0,0 +1,3 @@
save_to_file $2 .mdb_grep_tmp
shell grep $1 .mdb_grep_tmp
shell rm .mdb_grep_tmp

3
scripts/mdb_open Normal file
View File

@@ -0,0 +1,3 @@
save_to_file $1 .mdb_open_tmp
shell ${EDITOR-vi} .mdb_open_tmp
shell rm .mdb_open_tmp

View File

@@ -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@'

View File

@@ -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' \
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

16
tests/debugger/shell.exp Normal file
View File

@@ -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

6
tests/debugger/shell.inp Normal file
View File

@@ -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

12
tests/debugger/shell.m Normal file
View File

@@ -0,0 +1,12 @@
:- module shell.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
main(!IO) :-
nl(!IO).

View File

@@ -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 $

View File

@@ -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();
}

View File

@@ -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[];

View File

@@ -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();

View File

@@ -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 },

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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");
}
}

View File

@@ -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 */