The 1.4.x patch enables us to successfully split up a string
into an argv array of words to pass to execvp.
The 1.3.x patch backports this patch, backports also the 1.4.x
code for LibScriptSearch and backports the 1.4.x code to interpret
the $$s placeholder.
Both patches will result in output like this when execvp is invoked:
<command>
python
/home/angus/Program Files/LyX/share/lyx-1.3.6cvs/scripts/lyxpreview2ppm.py
/tmp/lyx_tmpdir6936exmZuO/lyx_tmpbuf0/0lyxpreview.tex
129
ppm
</command>
(So long as you get beyond the "LyX hands when running configure" problem.)
--
Angus
Index: src/support/forkedcall.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcall.C,v
retrieving revision 1.21
diff -u -p -r1.21 forkedcall.C
--- src/support/forkedcall.C 20 Jan 2005 15:38:14 -0000 1.21
+++ src/support/forkedcall.C 2 Feb 2005 12:32:23 -0000
@@ -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();
Index: lib/ChangeLog
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/lib/ChangeLog,v
retrieving revision 1.363.2.92
diff -u -p -r1.363.2.92 ChangeLog
--- lib/ChangeLog 28 Jan 2005 15:12:52 -0000 1.363.2.92
+++ lib/ChangeLog 2 Feb 2005 12:25:02 -0000
@@ -1,3 +1,7 @@
+2005-01-20 Angus Leeming <[EMAIL PROTECTED]>
+
+ * configure.m4: Invoke scripts as "python $$s/scripts/foo.py", etc.
+
2005-01-02 Kayvan A. Sylvan <[EMAIL PROTECTED]>
* configure.m4: add \cygwin_path_fix_needed to lyrxc.defaults.
Index: lib/configure.m4
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/lib/configure.m4,v
retrieving revision 1.60.2.13
diff -u -p -r1.60.2.13 configure.m4
--- lib/configure.m4 28 Jan 2005 15:12:53 -0000 1.60.2.13
+++ lib/configure.m4 2 Feb 2005 12:25:03 -0000
@@ -297,7 +297,7 @@ SEARCH_PROG([for a DVI to PDF converter]
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
Index: src/frontends/xforms/ChangeLog
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/xforms/ChangeLog,v
retrieving revision 1.661.2.26
diff -u -p -r1.661.2.26 ChangeLog
--- src/frontends/xforms/ChangeLog 28 Jan 2005 15:12:58 -0000 1.661.2.26
+++ src/frontends/xforms/ChangeLog 2 Feb 2005 12:25:16 -0000
@@ -1,3 +1,8 @@
+2005-01-20 Angus Leeming <[EMAIL PROTECTED]>
+
+ * FormPreferences.C: change the tooltip messages to reflect the
+ changed meaning of the $$s placeholder.
+
2005-01-15 Angus Leeming <[EMAIL PROTECTED]>
* FormPreferences.C, forms/form_preferences.fd: add an interface
Index: src/frontends/xforms/FormPreferences.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/xforms/FormPreferences.C,v
retrieving revision 1.147.2.6
diff -u -p -r1.147.2.6 FormPreferences.C
--- src/frontends/xforms/FormPreferences.C 28 Jan 2005 15:12:58 -0000 1.147.2.6
+++ src/frontends/xforms/FormPreferences.C 2 Feb 2005 12:25:20 -0000
@@ -993,9 +993,9 @@ FormPreferences::Converters::feedback(FL
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 "
Index: src/support/ChangeLog
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/ChangeLog,v
retrieving revision 1.149.2.34
diff -u -p -r1.149.2.34 ChangeLog
--- src/support/ChangeLog 30 Jan 2005 20:29:01 -0000 1.149.2.34
+++ src/support/ChangeLog 2 Feb 2005 12:25:23 -0000
@@ -1,3 +1,12 @@
+2005-01-20 Angus Leeming <[EMAIL PROTECTED]>
+
+ * 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 <[EMAIL PROTECTED]>
* os_cygwin.C (cygwin_path_fix):
Index: src/support/filetools.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/filetools.C,v
retrieving revision 1.146.2.13
diff -u -p -r1.146.2.13 filetools.C
--- src/support/filetools.C 28 Jan 2005 15:13:00 -0000 1.146.2.13
+++ src/support/filetools.C 2 Feb 2005 12:25:25 -0000
@@ -349,18 +349,36 @@ i18nLibFileSearch(string const & dir, st
}
-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;
- else if (args.empty())
- return script;
- else
- return script + ' ' + args;
+ // 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;
}
Index: src/support/filetools.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/filetools.h,v
retrieving revision 1.38.2.4
diff -u -p -r1.38.2.4 filetools.h
--- src/support/filetools.h 28 Jan 2005 15:13:00 -0000 1.38.2.4
+++ src/support/filetools.h 2 Feb 2005 12:25:25 -0000
@@ -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);
Index: src/support/forkedcall.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcall.C,v
retrieving revision 1.11.2.3
diff -u -p -r1.11.2.3 forkedcall.C
--- src/support/forkedcall.C 20 Jan 2005 10:47:29 -0000 1.11.2.3
+++ src/support/forkedcall.C 2 Feb 2005 12:25:25 -0000
@@ -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
// 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 = command_;
- int index = 0;
- for (; index < MAX_ARGV-1; ++index) {
- string word;
- line = split(line, word, ' ');
- if (word.empty())
- break;
-
- char * tmp = new char[word.length() + 1];
- word.copy(tmp, word.length());
- tmp[word.length()] = '\0';
-
- argv[index] = tmp;
+ string line = trim(command_);
+ if (line.empty())
+ return 1;
+
+ // 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);
+
+ // 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;
+ }
}
- argv[index] = 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,19 +325,12 @@ 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) {
// Error.
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;