]> git.lyx.org Git - lyx.git/commitdiff
Refactor the code to split a string into an argv array of words to pass
authorAngus Leeming <leeming@lyx.org>
Wed, 2 Feb 2005 12:57:20 +0000 (12:57 +0000)
committerAngus Leeming <leeming@lyx.org>
Wed, 2 Feb 2005 12:57:20 +0000 (12:57 +0000)
to execvp.

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

src/support/ChangeLog
src/support/forkedcall.C

index fd7759a8f9d3484fc92e00d8d508ec92d41fe821..fb71ade2aa35d9006c86b3e46d07ed669fca2b02 100644 (file)
@@ -1,3 +1,9 @@
+2005-02-02  Angus Leeming  <leeming@lyx.org>
+
+       * forkedcall.C (generateChild): overhaul the code to split a string
+       into an argv array of words. Now respects simple quoting reasonably
+       well.
+
 2005-02-01  Angus Leeming  <leeming@lyx.org>
 
        * fs_extras.C: #include <windows.h>
index 8e4736fb3f4b32cfa49c33ba04396087f5731c3a..5fb660e76132684c9edb14d34b587decc22a6c8c 100644 (file)
@@ -257,47 +257,59 @@ int Forkedcall::generateChild()
                return 1;
 
        // Split the input command up into an array of words stored
-       // in a contiguous block of memory.
-       char const * const c_str = line.c_str();
+       // in a contiguous block of memory. The array contains pointers
+       // to each word.
        // Don't forget the terminating `\0' character.
+       char const * const c_str = line.c_str();
        vector<char> vec(c_str, c_str + line.size() + 1);
-       // Turn the string into an array of words, each terminated with '\0'.
-       std::replace(vec.begin(), vec.end(), ' ', '\0');
+
+       // Splitting the command up into an array of words means replacing
+       // the whitespace between words with '\0'. Life is complicated
+       // however, because words protected by quotes can contain whitespace.
+       //
+       // The strategy we adopt is:
+       // 1. If we're not inside quotes, then replace white space with '\0'.
+       // 2. If we are inside quotes, then don't replace the white space
+       //    but do remove the quotes themselves. We do this naively by
+       //    replacing the quote with '\0' which is fine if quotes
+       //    delimit the entire word.
+       char inside_quote = 0;
+       vector<char>::iterator it = vec.begin();
+       vector<char>::iterator const end = vec.end();
+       for (; it != end; ++it) {
+               char const c = *it;
+               if (!inside_quote) {
+                       if (c == ' ')
+                               *it = '\0';
+                       else if (c == '\'' || c == '"') {
+                               *it = '\0';
+                               inside_quote = c;
+                       }
+               } else if (c == inside_quote) {
+                       *it = '\0';
+                       inside_quote = 0;
+               }
+       }
 
        // Build an array of pointers to each word.
-       vector<char>::iterator vit = vec.begin();
-       vector<char>::iterator vend = vec.end();
+       it = vec.begin();
        vector<char *> argv;
        char prev = '\0';
-       for (; vit != vend; ++vit) {
-               if (*vit != '\0' && prev == '\0')
-                       argv.push_back(&*vit);
-               prev = *vit;
+       for (; it != end; ++it) {
+               if (*it != '\0' && prev == '\0')
+                       argv.push_back(&*it);
+               prev = *it;
        }
-       // Strip quotes. Does so naively, assuming that the word begins
-       // and ends in quotes.
+       argv.push_back(0);
+
+       // Debug output.
        vector<char *>::iterator ait = argv.begin();
        vector<char *>::iterator const aend = argv.end();
-       for (; ait != aend; ++ait) {
-               char * word = *ait;
-               std::size_t const len = strlen(word);
-               if (len >= 2) {
-                       char & first = word[0];
-                       char & last = word[len-1];
-
-                       if (first == last &&
-                           (first == '\'' || first == '"')) {
-                               first = '\0';
-                               last = '\0';
-                               *ait += 1;
-                       }
-               }
-       }
-
-       ait = argv.begin();
+       lyxerr << "<command>\n";
        for (; ait != aend; ++ait)
-               std::cout << *ait << std::endl;
-       argv.push_back(0);
+               if (*ait)
+                       lyxerr << '\t'<< *ait << '\n';
+       lyxerr << "</command>" << std::endl;
 
 #ifndef __EMX__
        pid_t const cpid = ::fork();