]> git.lyx.org Git - features.git/commitdiff
Improve the command-line parser meant to be used for QProcess.
authorEnrico Forestieri <forenr@lyx.org>
Sat, 19 Dec 2009 17:26:09 +0000 (17:26 +0000)
committerEnrico Forestieri <forenr@lyx.org>
Sat, 19 Dec 2009 17:26:09 +0000 (17:26 +0000)
Now, both single- and double-quotes posix-like quoting styles are implemented,
such that a command-line meant for the shell can also be used for QProcess.
However, only redirecting the output to a file is supported. Supporting piping
would require a (major?) rewrite of the Systemcall class.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@32590 a592a061-630c-0410-9148-cb99ea01b6c8

src/support/Systemcall.cpp
src/support/filetools.cpp

index 4ea084028de7b478b45e259a26196d705c2a21e6..13a000157973ba8e59a66ee54894205902b616fe 100644 (file)
@@ -75,22 +75,83 @@ int Systemcall::startscript(Starttype how, string const & what,
 
 namespace {
 
-string const parsecmd(string const & cmd, string & outfile)
+/*
+ * This is a parser that (mostly) mimics the behavior of a posix shell but
+ * its output is tailored for being processed by QProcess.
+ *
+ * The escape character is the backslash.
+ * A backslash that is not quoted preserves the literal value of the following
+ * character, with the exception of a double-quote '"'. If a double-quote
+ * follows a backslash, it will be replaced by three consecutive double-quotes
+ * (this is how the QProcess parser recognizes a '"' as a simple character
+ * instead of a quoting character). Thus, for example:
+ *     \\  ->  \
+ *     \a  ->  a
+ *     \"  ->  """
+ *
+ * Single-quotes.
+ * Characters enclosed in single-quotes ('') have their literal value preserved.
+ * A single-quote cannot occur within single-quotes. Indeed, a backslash cannot
+ * be used to escape a single-quote in a single-quoted string. In other words,
+ * anything enclosed in single-quotes is passed as is, but the single-quotes
+ * themselves are eliminated. Thus, for example:
+ *    '\'    ->  \
+ *    '\\'   ->  \\
+ *    '\a'   ->  \a
+ *    'a\"b' ->  a\"b
+ *
+ * Double-quotes.
+ * Characters enclosed in double-quotes ("") have their literal value preserved,
+ * with the exception of the backslash. The backslash retains its special
+ * meaning as an escape character only when followed by a double-quote.
+ * Contrarily to the behavior of a posix shell, the double-quotes themselves
+ * are *not* eliminated. Thus, for example:
+ *    "\\"   ->  "\\"
+ *    "\a"   ->  "\a"
+ *    "a\"b" ->  "a"""b"
+ */
+string const parsecmd(string const & inputcmd, string & outfile)
 {
-       bool inquote = false;
+       bool in_single_quote = false;
+       bool in_double_quote = false;
        bool escaped = false;
-
-       for (size_t i = 0; i < cmd.length(); ++i) {
-               char c = cmd[i];
-               if (c == '"' && !escaped)
-                       inquote = !inquote;
-               else if (c == '\\' && !escaped)
+       string cmd;
+
+       for (size_t i = 0; i < inputcmd.length(); ++i) {
+               char c = inputcmd[i];
+               if (c == '\'') {
+                       if (in_double_quote || escaped) {
+                               if (in_double_quote && escaped)
+                                       cmd += '\\';
+                               cmd += c;
+                       } else
+                               in_single_quote = !in_single_quote;
+                       escaped = false;
+                       continue;
+               }
+               if (in_single_quote) {
+                       cmd += c;
+                       continue;
+               }
+               if (c == '"') {
+                       if (escaped) {
+                               cmd += "\"\"\"";
+                               escaped = false;
+                       } else {
+                               cmd += c;
+                               in_double_quote = !in_double_quote;
+                       }
+               } else if (c == '\\' && !escaped) {
                        escaped = !escaped;
-               else if (c == '>' && !(inquote || escaped)) {
-                       outfile = trim(cmd.substr(i + 1), " \"");
-                       return trim(cmd.substr(0, i));
-               } else
+               } else if (c == '>' && !(in_double_quote || escaped)) {
+                       outfile = trim(inputcmd.substr(i + 1), " \"");
+                       return trim(cmd);
+               } else {
+                       if (escaped && in_double_quote)
+                               cmd += '\\';
+                       cmd += c;
                        escaped = false;
+               }
        }
        outfile.erase();
        return cmd;
index ae9437f5296bb5abf578a468cb996d1b885f904b..a0c8f9759e072999a907a6b3d715c2dc8932c31d 100644 (file)
@@ -144,7 +144,9 @@ string const quoteName(string const & name, quote_style style)
 #else
                // According to the QProcess parser, a single double
                // quote is represented by three consecutive ones.
-               return '"' + subst(name, "\"", "\"\"\"") + '"';
+               // Here we simply escape the double quote and let our
+               // simple parser in Systemcall.cpp do the substitution.
+               return '"' + subst(name, "\"", "\\\"") + '"';
 #endif
        case quote_python:
                return "\"" + subst(subst(name, "\\", "\\\\"), "\"", "\\\"")