Backport the 1.4.x code to

* Split a string into an argv array of words to pass to execvp;
* handle the $$s placeholder in converter definitions.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/branches/BRANCH_1_3_X@9569 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Angus Leeming 2005-02-02 12:58:07 +00:00
parent 44cbcdb6aa
commit 18d5578a5f
8 changed files with 116 additions and 44 deletions

View File

@ -1,3 +1,7 @@
2005-01-20 Angus Leeming <leeming@lyx.org>
* configure.m4: Invoke scripts as "python $$s/scripts/foo.py", etc.
2005-01-02 Kayvan A. Sylvan <kayvan@sylvan.com>
* configure.m4: add \cygwin_path_fix_needed to lyrxc.defaults.

View File

@ -297,7 +297,7 @@ SEARCH_PROG([for a DVI to PDF converter],dvi_to_pdf_command,dvipdfm)
test $dvi_to_pdf_command = "dvipdfm" && dvi_to_pdf_command="dvipdfm \$\$i"
# We have a script to convert previewlyx to ppm
lyxpreview_to_bitmap_command="lyxpreview2ppm.py"
lyxpreview_to_bitmap_command="python \$\$s/scripts/lyxpreview2ppm.py"
# Search a *roff program (used to translate tables in ASCII export)
LYXRC_PROG([for a *roff formatter], \ascii_roff_command, dnl

View File

@ -1,3 +1,8 @@
2005-01-20 Angus Leeming <leeming@lyx.org>
* FormPreferences.C: change the tooltip messages to reflect the
changed meaning of the $$s placeholder.
2005-01-15 Angus Leeming <leeming@lyx.org>
* FormPreferences.C, forms/form_preferences.fd: add an interface

View File

@ -993,9 +993,9 @@ FormPreferences::Converters::feedback(FL_OBJECT const * const ob) const
if (ob == dialog_->input_converter)
return _("The conversion command. $$i is the input file name, "
"$$b is the file name without its extension and $$o is "
"the name of the output file. $$s can be used as path to "
"LyX's own collection of conversion scripts.");
"$$b is the file name without its extension and $$o "
"is the name of the output file. $$s can be used "
"as the path to LyX's support directory.");
if (ob == dialog_->input_flags)
return _("Extra information for the Converter class, whether and "

View File

@ -1,3 +1,12 @@
2005-01-20 Angus Leeming <leeming@lyx.org>
* filetools.[Ch] (LibScriptSearch): backport the 1.4.x code so
that the function now substitutes the $$s placeholder for the
path to the appropriate LyX support directory.
* forkedcall.C (generateChild): backport the 1.4.x code to split
the input command up into an array of words and to strip any quotes.
2005-01-30 Angus Leeming <leeming@lyx.org>
* os_cygwin.C (cygwin_path_fix):

View File

@ -349,18 +349,36 @@ i18nLibFileSearch(string const & dir, string const & name,
}
string const LibScriptSearch(string const & command)
string const LibScriptSearch(string const & command_in)
{
string script;
string args = command;
args = split(args, script, ' ');
script = LibFileSearch("scripts", script);
if (script.empty())
string const token_scriptpath("$$s/");
string command = command_in;
// Find the starting position of "$$s/"
string::size_type const pos1 = command.find(token_scriptpath);
if (pos1 == string::npos)
return command;
// Find the end of the "$$s/some_script" word within command.
// Assumes that the script name does not contain spaces.
string::size_type const start_script = pos1 + 4;
string::size_type const pos2 = command.find(' ', start_script);
string::size_type const size_script = pos2 == string::npos?
(command.size() - start_script) : pos2 - start_script;
// Does this script file exist?
string const script =
LibFileSearch(".", command.substr(start_script, size_script));
if (script.empty()) {
// Replace "$$s/" with ""
command.erase(pos1, 4);
} else {
// Replace "$$s/foo/some_script" with "<path to>/some_script".
string::size_type const size_replace = size_script + 4;
command.replace(pos1, size_replace, QuoteName(script));
}
return command;
else if (args.empty())
return script;
else
return script + ' ' + args;
}

View File

@ -96,11 +96,13 @@ string const
i18nLibFileSearch(string const & dir, string const & name,
string const & ext = string());
/** Takes a command with arguments as input and tries to see whether
the command itself can be found in one of the scripts/ directories.
If it is found, return the command with fully qualified script name,
either return it unchanged */
string const LibScriptSearch(string const & command);
/** Takes a command such as "sh $$s/scripts/convertDefault.sh file.in file.out"
* and replaces "$$s/" with the path to the LyX support directory containing
* this script. If the script is not found, "$$s/" is removed. Executing the
* command will still fail, but the error message will make some sort of
* sense ;-)
*/
std::string const LibScriptSearch(std::string const & command);
///
string const GetEnv(string const & envname);

View File

@ -35,6 +35,7 @@
#include <boost/bind.hpp>
#include <vector>
#include <cerrno>
#include <sys/types.h>
#include <sys/wait.h>
@ -45,6 +46,7 @@
#endif
using std::endl;
using std::vector;
#ifndef CXX_GLOBAL_CSTD
using std::strerror;
@ -251,31 +253,70 @@ int Forkedcall::startscript(string const & what, SignalTypePtr signal)
// generate child in background
int Forkedcall::generateChild()
{
// Split command_ up into a char * array
int const MAX_ARGV = 255;
char *argv[MAX_ARGV];
string line = trim(command_);
if (line.empty())
return 1;
string line = command_;
int index = 0;
for (; index < MAX_ARGV-1; ++index) {
string word;
line = split(line, word, ' ');
if (word.empty())
break;
// Split the input command up into an array of words stored
// 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);
char * tmp = new char[word.length() + 1];
word.copy(tmp, word.length());
tmp[word.length()] = '\0';
argv[index] = tmp;
// 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;
}
argv[index] = 0;
} else if (c == inside_quote) {
*it = '\0';
inside_quote = 0;
}
}
// Build an array of pointers to each word.
it = vec.begin();
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);
// 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__
pid_t const cpid = ::fork();
if (cpid == 0) {
// Child
execvp(argv[0], argv);
execvp(argv[0], &*argv.begin());
// If something goes wrong, we end up here
lyxerr << "execvp of \"" << command_ << "\" failed: "
@ -284,7 +325,7 @@ int Forkedcall::generateChild()
}
#else
pid_t const cpid = spawnvp(P_SESSION|P_DEFAULT|P_MINIMIZE|P_BACKGROUND,
argv[0], argv);
argv[0], &*argv.begin());
#endif
if (cpid < 0) {
@ -292,12 +333,5 @@ int Forkedcall::generateChild()
lyxerr << "Could not fork: " << strerror(errno) << endl;
}
// Clean-up.
for (int i = 0; i < MAX_ARGV; ++i) {
if (argv[i] == 0)
break;
delete [] argv[i];
}
return cpid;
}