summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-06-02 18:48:40 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-06-02 18:48:40 +0200
commit51dc9396d8bd8f0971a59f4e3aa11e8315c394cd (patch)
treed24a2258506584644e0b74468ac22bbdad9af8ab
parented60746355044dd39acd82b8f42c4d9886914567 (diff)
Add support for quoting in option file scanner
-rw-r--r--cli/runtime-header.cxx21
-rw-r--r--cli/runtime-inline.cxx21
-rw-r--r--cli/runtime-source.cxx36
-rw-r--r--doc/guide/index.xhtml38
-rw-r--r--tests/file/makefile18
-rw-r--r--tests/file/test-004.ops6
-rw-r--r--tests/file/test-004.std12
-rw-r--r--tests/file/test-005.ops1
-rw-r--r--tests/file/test-005.std1
-rw-r--r--tests/file/test-006.ops1
-rw-r--r--tests/file/test-006.std1
-rw-r--r--tests/file/test-007.ops1
-rw-r--r--tests/file/test-007.std1
13 files changed, 146 insertions, 12 deletions
diff --git a/cli/runtime-header.cxx b/cli/runtime-header.cxx
index f25d64c..5a2905c 100644
--- a/cli/runtime-header.cxx
+++ b/cli/runtime-header.cxx
@@ -180,6 +180,27 @@ generate_runtime_header (context& ctx)
<< "private:" << endl
<< "std::string file_;"
<< "};";
+
+ os << "class unmatched_quote: public exception"
+ << "{"
+ << "public:" << endl
+ << "virtual" << endl
+ << "~unmatched_quote () throw ();"
+ << endl
+ << "unmatched_quote (const std::string& argument);"
+ << endl
+ << "const std::string&" << endl
+ << "argument () const;"
+ << endl
+ << "virtual void" << endl
+ << "print (std::ostream&) const;"
+ << endl
+ << "virtual const char*" << endl
+ << "what () const throw ();"
+ << endl
+ << "private:" << endl
+ << "std::string argument_;"
+ << "};";
}
// scanner
diff --git a/cli/runtime-inline.cxx b/cli/runtime-inline.cxx
index cc54b5e..da2decf 100644
--- a/cli/runtime-inline.cxx
+++ b/cli/runtime-inline.cxx
@@ -115,10 +115,10 @@ generate_runtime_inline (context& ctx)
<< "return value_;"
<< "}";
- // file_io_failure
- //
if (ctx.options.generate_file_scanner ())
{
+ // file_io_failure
+ //
os << "// file_io_failure" << endl
<< "//" << endl
@@ -133,6 +133,23 @@ generate_runtime_inline (context& ctx)
<< "{"
<< "return file_;"
<< "}";
+
+ // unmatched_option
+ //
+ os << "// unmatched_quote" << endl
+ << "//" << endl
+
+ << inl << "unmatched_quote::" << endl
+ << "unmatched_quote (const std::string& argument)" << endl
+ << ": argument_ (argument)"
+ << "{"
+ << "}"
+
+ << inl << "const std::string& unmatched_quote::" << endl
+ << "argument () const"
+ << "{"
+ << "return argument_;"
+ << "}";
}
// argv_scanner
diff --git a/cli/runtime-source.cxx b/cli/runtime-source.cxx
index fea0347..348d7b7 100644
--- a/cli/runtime-source.cxx
+++ b/cli/runtime-source.cxx
@@ -129,10 +129,10 @@ generate_runtime_source (context& ctx)
<< "return \"end of argument stream reached\";"
<< "}";
- // file_io_failure
- //
if (ctx.options.generate_file_scanner ())
{
+ // file_io_failure
+ //
os << "// file_io_failure" << endl
<< "//" << endl
<< "file_io_failure::" << endl
@@ -151,6 +151,27 @@ generate_runtime_source (context& ctx)
<< "{"
<< "return \"unable to open file or read failure\";"
<< "}";
+
+ // unmatched_argument
+ //
+ os << "// unmatched_quote" << endl
+ << "//" << endl
+ << "unmatched_quote::" << endl
+ << "~unmatched_quote () throw ()"
+ << "{"
+ << "}"
+
+ << "void unmatched_quote::" << endl
+ << "print (std::ostream& os) const"
+ << "{"
+ << "os << \"unmatched quote in argument '\" << argument () << \"'\";"
+ << "}"
+
+ << "const char* unmatched_quote::" << endl
+ << "what () const throw ()"
+ << "{"
+ << "return \"unmatched quote\";"
+ << "}";
}
// scanner
@@ -368,6 +389,17 @@ generate_runtime_source (context& ctx)
<< "}"
<< "string s2 (line, p);"
<< endl
+ << "// If the string is wrapped in quotes, remove them." << endl
+ << "//" << endl
+ << "n = s2.size ();"
+ << endl
+ << "if (s2[0] == '\"' || s2[n - 1] == '\"')"
+ << "{"
+ << "if (n == 1 || s2[0] != s2[n - 1])" << endl
+ << "throw unmatched_quote (s2);"
+ << endl
+ << "s2 = string (s2, 1, n - 2);"
+ << "}"
<< "if (" << (sep ? "!skip_ && " : "") << "s1 == option_)" << endl
<< "load (s2.c_str ());"
<< "else"
diff --git a/doc/guide/index.xhtml b/doc/guide/index.xhtml
index 2ae7f1e..098fcd7 100644
--- a/doc/guide/index.xhtml
+++ b/doc/guide/index.xhtml
@@ -749,12 +749,19 @@ namespace cli
that should be recognized as specifying the file containing additional
options. Such a file contains a set of options, each appearing on a
separate line optionally followed by space and an option value. Empty lines
- and lines starting with <code>#</code> are ignored. The semantics
- of providing options in a file is equivalent to providing the same set
- of options in the same order on the command line at the point where the
- options file is specified, except that shell escaping and quoting is not
- required. Multiple files can be specified by including several file
- options on the command line or inside other files.</p>
+ and lines starting with <code>#</code> are ignored. Option values can
+ be enclosed in double quotes (<code>" "</code>) to preserve leading
+ and trailing whitespaces as well as to specify empty values. If the
+ value itself contains trailing or leading double quote, enclose
+ it into an extra pair of double quotes, for example <code>""x""</code>.
+ Non-leading and non-trailing quotes are interpreted as being part of
+ the option value.</p>
+
+ <p>The semantics of providing options in a file is equivalent to providing
+ the same set of options in the same order on the command line at the
+ point where the options file is specified, except that shell escaping
+ and quoting is not required. Multiple files can be specified by including
+ several file options on the command line or inside other files.</p>
<p>The parsing constructor (those with the <code>argc/argv</code> or
<code>cli::scanner</code> arguments) can throw the following exceptions: <code>cli::unknown_option</code>,
@@ -774,7 +781,9 @@ namespace cli
error in an option parser implementation. The <code>argv_file_scanner</code>
class can also throw the <code>cli::file_io_failure</code> exception
which indicates that a file could not be opened or there was a reading
- error.</p>
+ error as well as the <code>cli::unmatched_quote</code> exception
+ which indicates that an unmatched leading or trailing quote was
+ found in an option value.</p>
<p>All CLI exceptions are derived from the common <code>cli::exception</code>
class which implements the polymorphic <code>std::ostream</code> insertion.
@@ -893,6 +902,21 @@ namespace cli
virtual const char*
what () const throw ();
};
+
+ class unmatched_quote: public exception
+ {
+ public:
+ unmatched_quote (const std::string&amp; argument);
+
+ const std::string&amp;
+ argument () const;
+
+ virtual void
+ print (std::ostream&amp;) const;
+
+ virtual const char*
+ what () const throw ();
+ };
}
</pre>
diff --git a/tests/file/makefile b/tests/file/makefile
index 011582a..2029d83 100644
--- a/tests/file/makefile
+++ b/tests/file/makefile
@@ -8,7 +8,7 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make
cxx_tun := driver.cxx
cli_tun := test.cli
-tests := 000 001 002 003
+tests := 000 001 002 003 004 005 006 007
#
#
@@ -63,6 +63,22 @@ $(out_base)/.test-003: $(driver)
$(call message,test $(out_base)/003,$(driver) -a 1 --file \
$(src_base)/base.ops --file test-003.ops b | diff -u $(src_base)/test-003.std -)
+$(out_base)/.test-004: $(driver) $(src_base)/test-004.ops
+ $(call message,test $(out_base)/004,$(driver) --file \
+$(src_base)/test-004.ops | diff -u $(src_base)/test-004.std -)
+
+$(out_base)/.test-005: $(driver) $(src_base)/test-005.ops
+ $(call message,test $(out_base)/005,$(driver) --file \
+$(src_base)/test-005.ops | diff -u $(src_base)/test-005.std -)
+
+$(out_base)/.test-006: $(driver) $(src_base)/test-006.ops
+ $(call message,test $(out_base)/006,$(driver) --file \
+$(src_base)/test-006.ops | diff -u $(src_base)/test-006.std -)
+
+$(out_base)/.test-007: $(driver) $(src_base)/test-007.ops
+ $(call message,test $(out_base)/007,$(driver) --file \
+$(src_base)/test-007.ops | diff -u $(src_base)/test-007.std -)
+
# Clean.
#
$(clean): \
diff --git a/tests/file/test-004.ops b/tests/file/test-004.ops
new file mode 100644
index 0000000..3246233
--- /dev/null
+++ b/tests/file/test-004.ops
@@ -0,0 +1,6 @@
+-a a"b"c
+-a "abc"
+-a "a"b"
+-a ""
+-a " abc "
+-a " "
diff --git a/tests/file/test-004.std b/tests/file/test-004.std
new file mode 100644
index 0000000..01114a0
--- /dev/null
+++ b/tests/file/test-004.std
@@ -0,0 +1,12 @@
+-a
+a"b"c
+-a
+abc
+-a
+a"b
+-a
+
+-a
+ abc
+-a
+
diff --git a/tests/file/test-005.ops b/tests/file/test-005.ops
new file mode 100644
index 0000000..c9acf33
--- /dev/null
+++ b/tests/file/test-005.ops
@@ -0,0 +1 @@
+-a "
diff --git a/tests/file/test-005.std b/tests/file/test-005.std
new file mode 100644
index 0000000..52b6e89
--- /dev/null
+++ b/tests/file/test-005.std
@@ -0,0 +1 @@
+unmatched quote in argument '"'
diff --git a/tests/file/test-006.ops b/tests/file/test-006.ops
new file mode 100644
index 0000000..454366d
--- /dev/null
+++ b/tests/file/test-006.ops
@@ -0,0 +1 @@
+-a "abc
diff --git a/tests/file/test-006.std b/tests/file/test-006.std
new file mode 100644
index 0000000..903f7a7
--- /dev/null
+++ b/tests/file/test-006.std
@@ -0,0 +1 @@
+unmatched quote in argument '"abc'
diff --git a/tests/file/test-007.ops b/tests/file/test-007.ops
new file mode 100644
index 0000000..8012af9
--- /dev/null
+++ b/tests/file/test-007.ops
@@ -0,0 +1 @@
+-a abc"
diff --git a/tests/file/test-007.std b/tests/file/test-007.std
new file mode 100644
index 0000000..fff8f85
--- /dev/null
+++ b/tests/file/test-007.std
@@ -0,0 +1 @@
+unmatched quote in argument 'abc"'