From: Angus Leeming Date: Wed, 2 Feb 2005 12:57:20 +0000 (+0000) Subject: Refactor the code to split a string into an argv array of words to pass X-Git-Tag: 1.6.10~14585 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=1ac3dbbacaac5f4aa0ef06c25fddeea99f32ba5d;p=features.git Refactor the code to split a string into an argv array of words to pass to execvp. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@9568 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/src/support/ChangeLog b/src/support/ChangeLog index fd7759a8f9..fb71ade2aa 100644 --- a/src/support/ChangeLog +++ b/src/support/ChangeLog @@ -1,3 +1,9 @@ +2005-02-02 Angus Leeming + + * 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 * fs_extras.C: #include diff --git a/src/support/forkedcall.C b/src/support/forkedcall.C index 8e4736fb3f..5fb660e761 100644 --- a/src/support/forkedcall.C +++ b/src/support/forkedcall.C @@ -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 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::iterator it = vec.begin(); + vector::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::iterator vit = vec.begin(); - vector::iterator vend = vec.end(); + it = vec.begin(); vector 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::iterator ait = argv.begin(); vector::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 << "\n"; for (; ait != aend; ++ait) - std::cout << *ait << std::endl; - argv.push_back(0); + if (*ait) + lyxerr << '\t'<< *ait << '\n'; + lyxerr << "" << std::endl; #ifndef __EMX__ pid_t const cpid = ::fork();