[m-rev.] incomplete diff: allow quotes in mdb commands
Mark Brown
dougl at cs.mu.OZ.AU
Fri Feb 22 17:52:27 AEDT 2002
On 21-Feb-2002, Mark Brown <dougl at cs.mu.OZ.AU> wrote:
> This is in response to David Overton's bug report. I've only written
> the documentation so far, but I thought I'd invite comment on that
> now before starting on the code.
>
Here is the full diff for review.
Cheers,
Mark.
Estimated hours taken: 2.5
Branches: main
Allow mdb commands to quote words so that they can contain whitespace,
and allow characters with special meaning to mdb to be escaped.
trace/mercury_trace_internal.c:
Implement the new feature.
doc/user_guide.texi:
Document the new feature.
tests/debugger/Mmakefile:
tests/debugger/cmd_quote.exp:
tests/debugger/cmd_quote.inp:
tests/debugger/cmd_quote.m:
Test case.
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.292
diff -u -r1.292 user_guide.texi
--- doc/user_guide.texi 12 Feb 2002 16:36:10 -0000 1.292
+++ doc/user_guide.texi 21 Feb 2002 13:32:59 -0000
@@ -1820,10 +1820,21 @@
When the debugger (as opposed to the program being debugged) is interacting
with the user, the debugger prints a prompt and reads in a line of text,
-which it will interpret as its next command. Each command line consists
-of several words separated by white space. The first word is the name of
-the command, while any other words give options and/or parameters to the
-command.
+which it will interpret as its next command line.
+A command line consists of a single command,
+or several commands separated by semicolons.
+Each command consists of several words separated by white space.
+The first word is the name of the command,
+while any other words give options and/or parameters to the command.
+
+A word may itself contain semicolons or whitespace if it is
+enclosed in single quotes (').
+This is useful for commands that have other commands as parameters,
+for example @samp{view -w 'xterm -e'}.
+Characters that have special meaning to @samp{mdb} will be treated like
+ordinary charaters if they are escaped with a backslash (\).
+It is possible to escape single quotes, whitespace, semicolons, newlines
+and the escape character itself.
Some commands take a number as their first parameter.
For such commands, users can type `@var{number} @var{command}'
Index: tests/debugger/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/debugger/Mmakefile,v
retrieving revision 1.62
diff -u -r1.62 Mmakefile
--- tests/debugger/Mmakefile 20 Feb 2002 03:14:44 -0000 1.62
+++ tests/debugger/Mmakefile 21 Feb 2002 20:35:35 -0000
@@ -27,6 +27,7 @@
NONRETRY_PROGS = \
breakpoints \
browse_pretty \
+ cmd_quote \
debugger_regs \
exception_cmd \
exception_value \
@@ -120,6 +121,12 @@
browser_test.out: browser_test browser_test.inp
$(MDB) ./browser_test < browser_test.inp 2>&1 | \
sed 's/io.m:[0-9]*/io.m:NNNN/g' > browser_test.out 2>&1
+
+# We need to pipe the output through sed to avoid hard-coding dependencies on
+# particular line numbers in the standard library source code.
+cmd_quote.out: cmd_quote cmd_quote.inp
+ $(MDB) ./cmd_quote < cmd_quote.inp 2>&1 | \
+ sed 's/io.m:[0-9]*/io.m:NNNN/g' > cmd_quote.out 2>&1
debugger_regs.out: debugger_regs debugger_regs.inp
$(MDB) ./debugger_regs < debugger_regs.inp > debugger_regs.out 2>&1
Index: tests/debugger/cmd_quote.exp
===================================================================
RCS file: tests/debugger/cmd_quote.exp
diff -N tests/debugger/cmd_quote.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/cmd_quote.exp 21 Feb 2002 20:54:02 -0000
@@ -0,0 +1,41 @@
+ 1: 1 1 CALL pred cmd_quote:main/2-0 (det) cmd_quote.m:7
+mdb> echo on
+Command echo enabled.
+mdb> print \ foo
+mdb: there is no such variable.
+mdb> print \\
+mdb: there is no such variable.
+mdb> print 'foo'
+mdb: there is no such variable.
+mdb> print '\''
+mdb: there is no such variable.
+mdb> print ''''
+mdb: there is no such variable.
+mdb> print \
+> foo \
+> bar \
+> baz
+mdb: print: usage error -- type `help print' for help.
+mdb> print 'foo
+> bar
+> baz '
+mdb: there is no such variable.
+mdb> print '
+> foo \
+> bar \'
+> '
+mdb: there is no such variable.
+mdb> \\\
+> \\\\
+Unknown command `\'. Give the command `help' for help.
+mdb> \\\\\\\\
+Unknown command `\\\\'. Give the command `help' for help.
+mdb> \'\'\'\'
+Unknown command `'''''. Give the command `help' for help.
+mdb> 'foo\''
+Unknown command `foo''. Give the command `help' for help.
+mdb> \ \ \ .
+Unknown command ` .'. Give the command `help' for help.
+mdb> '\ \\\''
+Unknown command ` \''. Give the command `help' for help.
+mdb> quit -y
Index: tests/debugger/cmd_quote.inp
===================================================================
RCS file: tests/debugger/cmd_quote.inp
diff -N tests/debugger/cmd_quote.inp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/cmd_quote.inp 21 Feb 2002 20:54:02 -0000
@@ -0,0 +1,25 @@
+echo on
+print \ foo
+print \\
+print 'foo'
+print '\''
+print ''''
+print \
+foo \
+bar \
+baz
+print 'foo
+bar
+baz '
+print '
+foo \
+bar \'
+'
+\\\
+\\\\
+\\\\\\\\
+\'\'\'\'
+'foo\''
+\ \ \ .
+'\ \\\''
+quit -y
Index: tests/debugger/cmd_quote.m
===================================================================
RCS file: tests/debugger/cmd_quote.m
diff -N tests/debugger/cmd_quote.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/debugger/cmd_quote.m 21 Feb 2002 20:37:49 -0000
@@ -0,0 +1,9 @@
+:- module cmd_quote.
+:- interface.
+:- import_module io.
+:- pred main(io__state::di, io__state::uo) is det.
+:- implementation.
+
+main -->
+ io__write_string("Hello world!\n").
+
Index: trace/mercury_trace_internal.c
===================================================================
RCS file: /home/mercury1/repository/mercury/trace/mercury_trace_internal.c,v
retrieving revision 1.116
diff -u -r1.116 mercury_trace_internal.c
--- trace/mercury_trace_internal.c 21 Feb 2002 01:53:29 -0000 1.116
+++ trace/mercury_trace_internal.c 22 Feb 2002 06:45:06 -0000
@@ -68,6 +68,10 @@
#include <sys/stropts.h>
#endif
+/* Special characters used in mdb commands. */
+#define MR_MDB_QUOTE_CHAR '\''
+#define MR_MDB_ESCAPE_CHAR '\\'
+
/* The initial size of arrays of words. */
#define MR_INIT_WORD_COUNT 20
@@ -270,11 +274,13 @@
char ***words, int *word_max, int *word_count);
static int MR_trace_break_into_words(char *line,
char ***words_ptr, int *word_max_ptr);
+static int MR_trace_break_off_one_word(char *line, int char_pos);
static void MR_trace_expand_aliases(char ***words,
int *word_max, int *word_count);
static MR_bool MR_trace_source(const char *filename, MR_bool ignore_errors);
static void MR_trace_source_from_open_file(FILE *fp);
static char *MR_trace_getline_queue(void);
+static MR_bool MR_trace_continue_line(char *ptr, MR_bool *quoted);
static void MR_insert_line_at_head(const char *line);
static void MR_insert_line_at_tail(const char *line);
@@ -3600,9 +3606,11 @@
}
/*
-** Given a text line, break it up into words composed of non-space characters
-** separated by space characters. Make each word a NULL-terminated string,
-** overwriting some spaces in the line array in the process.
+** Given a text line, break it up into words. Words are composed of
+** non-space characters separated by space characters, except where
+** quotes (') or escapes (\) change the treatment of characters. Make
+** each word a NULL-terminated string, and remove the quotes and escapes,
+** overwriting some parts of the line array in the process.
**
** On return *words will point to an array of strings, with space for
** *words_max strings. The number of strings filled in will be given by
@@ -3639,18 +3647,57 @@
MR_ensure_big_enough(token_number, word, char *,
MR_INIT_WORD_COUNT);
words[token_number] = line + char_pos;
+ char_pos = MR_trace_break_off_one_word(line, char_pos);
- while (line[char_pos] != '\0' && !MR_isspace(line[char_pos])) {
- char_pos++;
+ token_number++;
+ }
+}
+
+static int
+MR_trace_break_off_one_word(char *line, int char_pos)
+{
+ int lag = 0;
+ MR_bool quoted = MR_FALSE;
+ MR_bool another = MR_FALSE;
+
+ while (line[char_pos] != '\0')
+ {
+ if (!quoted && MR_isspace(line[char_pos])) {
+ another = MR_TRUE;
+ break;
}
+ if (line[char_pos] == MR_MDB_QUOTE_CHAR) {
+ lag++;
+ char_pos++;
+ quoted = !quoted;
+ } else {
+ if (line[char_pos] == MR_MDB_ESCAPE_CHAR) {
+ lag++;
+ char_pos++;
+ if (line[char_pos] == '\0') {
+ MR_fatal_error(
+ "MR_trace_break_off_one_word: "
+ "unhandled backslash");
+ }
+ }
- if (line[char_pos] != '\0') {
- line[char_pos] = '\0';
+ if (lag) {
+ line[char_pos - lag] = line[char_pos];
+ }
char_pos++;
}
+ }
- token_number++;
+ if (quoted) {
+ MR_fatal_error("MR_trace_break_off_one_word: unmatched quote");
+ }
+
+ line[char_pos - lag] = '\0';
+ if (another) {
+ char_pos++;
}
+
+ return char_pos;
}
static void
@@ -3726,15 +3773,20 @@
** Call MR_trace_getline to get the next line of input, then do some
** further processing. If the input has reached EOF, return the command
** "quit". If the line contains multiple commands then split it and
-** only return the first one. The command is returned in a MR_malloc'd
-** buffer.
+** only return the first one. If the newline at the end is either quoted
+** or escaped, read another line (using the prompt '>') and append it to
+** the first. The command is returned in a MR_malloc'd buffer.
*/
char *
MR_trace_get_command(const char *prompt, FILE *mdb_in, FILE *mdb_out)
{
char *line;
- char *semicolon;
+ char *ptr;
+ char *cmd_chars;
+ int cmd_char_max;
+ MR_bool quoted;
+ int len, extra_len;
line = MR_trace_getline(prompt, mdb_in, mdb_out);
@@ -3745,19 +3797,31 @@
** specially in the command interpreter.
*/
line = MR_copy_string("quit");
+ return line;
}
- if ((semicolon = strchr(line, ';')) != NULL) {
+ len = strlen(line);
+ ptr = line;
+ cmd_chars = line;
+ cmd_char_max = len + 1;
+ quoted = MR_FALSE;
+ while (MR_trace_continue_line(ptr, "ed)) {
/*
- ** The line contains at least two commands.
- ** Return only the first command now; put the others
- ** back in the input to be processed later.
+ ** We were inside quotes when the end of the line was
+ ** reached, or the newline was escaped, so input continues
+ ** on the next line. We append it to the first line,
+ ** allocating more space if necessary.
*/
- *semicolon = '\0';
- MR_insert_line_at_head(MR_copy_string(semicolon + 1));
+ line = MR_trace_getline("> ", mdb_in, mdb_out);
+ extra_len = strlen(line);
+ /* cmd_char_max is always > 0 */
+ MR_ensure_big_enough(len + extra_len + 1, cmd_char, char, 0);
+ ptr = cmd_chars + len;
+ strcpy(ptr, line);
+ len = len + extra_len;
}
- return line;
+ return cmd_chars;
}
/*
@@ -3855,6 +3919,51 @@
MR_line_tail->MR_line_next = line;
MR_line_tail = line;
}
+}
+
+/*
+** This returns MR_TRUE iff the given line continues on to the next line,
+** because the newline is in quotes or escaped. The second parameter
+** indicates whether we are inside quotes or not, and is updated by
+** this function. If an unquoted and unescaped semicolon is encountered,
+** the line is split at that point.
+*/
+
+static MR_bool
+MR_trace_continue_line(char *ptr, MR_bool *quoted)
+{
+ MR_bool escaped = MR_FALSE;
+
+ while (*ptr != '\0') {
+ if (escaped) {
+ /* do nothing special */
+ escaped = MR_FALSE;
+ } else if (*ptr == MR_MDB_ESCAPE_CHAR) {
+ escaped = MR_TRUE;
+ } else if (*ptr == MR_MDB_QUOTE_CHAR) {
+ *quoted = !(*quoted);
+ } else if (!(*quoted) && *ptr == ';') {
+ /*
+ ** The line contains at least two commands.
+ ** Return only the first command now; put the
+ ** others back in the input to be processed later.
+ */
+ *ptr = '\0';
+ MR_insert_line_at_head(MR_copy_string(ptr + 1));
+ return MR_FALSE;
+ }
+
+ ++ptr;
+ }
+
+ if (escaped) {
+ /*
+ ** Replace the escaped newline with a space.
+ */
+ *(ptr - 1) = ' ';
+ }
+
+ return (*quoted || escaped);
}
MR_Code *
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list