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
This commit is contained in:
Angus Leeming 2005-02-02 12:57:20 +00:00
parent b1cc3aad86
commit 1ac3dbbaca
2 changed files with 51 additions and 33 deletions

View 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> 2005-02-01 Angus Leeming <leeming@lyx.org>
* fs_extras.C: #include <windows.h> * fs_extras.C: #include <windows.h>

View File

@ -257,48 +257,60 @@ int Forkedcall::generateChild()
return 1; return 1;
// Split the input command up into an array of words stored // Split the input command up into an array of words stored
// in a contiguous block of memory. // in a contiguous block of memory. The array contains pointers
char const * const c_str = line.c_str(); // to each word.
// Don't forget the terminating `\0' character. // 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); 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');
// Build an array of pointers to each word. // Splitting the command up into an array of words means replacing
vector<char>::iterator vit = vec.begin(); // the whitespace between words with '\0'. Life is complicated
vector<char>::iterator vend = vec.end(); // however, because words protected by quotes can contain whitespace.
vector<char *> argv; //
char prev = '\0'; // The strategy we adopt is:
for (; vit != vend; ++vit) { // 1. If we're not inside quotes, then replace white space with '\0'.
if (*vit != '\0' && prev == '\0') // 2. If we are inside quotes, then don't replace the white space
argv.push_back(&*vit); // but do remove the quotes themselves. We do this naively by
prev = *vit; // replacing the quote with '\0' which is fine if quotes
} // delimit the entire word.
// Strip quotes. Does so naively, assuming that the word begins char inside_quote = 0;
// and ends in quotes. vector<char>::iterator it = vec.begin();
vector<char *>::iterator ait = argv.begin(); vector<char>::iterator const end = vec.end();
vector<char *>::iterator const aend = argv.end(); for (; it != end; ++it) {
for (; ait != aend; ++ait) { char const c = *it;
char * word = *ait; if (!inside_quote) {
std::size_t const len = strlen(word); if (c == ' ')
if (len >= 2) { *it = '\0';
char & first = word[0]; else if (c == '\'' || c == '"') {
char & last = word[len-1]; *it = '\0';
inside_quote = c;
if (first == last &&
(first == '\'' || first == '"')) {
first = '\0';
last = '\0';
*ait += 1;
} }
} else if (c == inside_quote) {
*it = '\0';
inside_quote = 0;
} }
} }
ait = argv.begin(); // Build an array of pointers to each word.
for (; ait != aend; ++ait) it = vec.begin();
std::cout << *ait << std::endl; vector<char *> argv;
char prev = '\0';
for (; it != end; ++it) {
if (*it != '\0' && prev == '\0')
argv.push_back(&*it);
prev = *it;
}
argv.push_back(0); argv.push_back(0);
// Debug output.
vector<char *>::iterator ait = argv.begin();
vector<char *>::iterator const aend = argv.end();
lyxerr << "<command>\n";
for (; ait != aend; ++ait)
if (*ait)
lyxerr << '\t'<< *ait << '\n';
lyxerr << "</command>" << std::endl;
#ifndef __EMX__ #ifndef __EMX__
pid_t const cpid = ::fork(); pid_t const cpid = ::fork();
if (cpid == 0) { if (cpid == 0) {