The \input@path mechanism (already used by LyX) is not always sufficient
and there are cases where a file can be found by LaTeX and also by other
ancillary programs (such as dvi previewers) only if the document dir is
placed in the TEXINPUTS environment variable.

The attached patch adds the document dir and all of its subdirs to
TEXINPUTS, such that the attached example in the tar archive works in LyX.
I would like to start a discussion on this issue, more precisely on what
LyX should do. The options are:
1) Add the document dir and all of its subdirs to TEXINPUTS (done by the patch)
2) Add the document dir but not the subdirs to TEXINPUTS
3) Make user configurable the path to add to TEXINPUTS (à la Path prefix)

The disadvantage of option 1) is that a whole tree is then scanned by TeX.
If you load a document placed at the root of your home directory, then all
subdirectories are scanned.

The disadvantage of option 2) is that it does not always work. For example,
it would not work with the attached example.

Maybe option 3) is the most flexible and can avoid problems. For example,
I discovered that MiKTeX is really upset if one of the subdirectories has
asian characters in its name and stops compilation with a strange error,
even if nothing would be loaded from there (i.e., its mere presence in
TEXINPUTS causes problems).

Note that the attached example is not supposed to work with pdflatex even
with the patch applied, because a postscript image is loaded behind the
scenes and this doesn't work (the ps2pdf or dvipdfm routes are Ok, of course).

Comments?

-- 
Enrico
Index: src/LaTeX.cpp
===================================================================
--- src/LaTeX.cpp       (revisione 38627)
+++ src/LaTeX.cpp       (copia locale)
@@ -93,8 +93,8 @@ bool operator!=(AuxInfo const & a, AuxIn
  */
 
 LaTeX::LaTeX(string const & latex, OutputParams const & rp,
-            FileName const & f)
-       : cmd(latex), file(f), runparams(rp)
+            FileName const & f, string const & p)
+       : cmd(latex), file(f), path(p), runparams(rp)
 {
        num_errors = 0;
        if (prefixIs(cmd, "pdf")) { // Do we use pdflatex ?
@@ -421,7 +421,7 @@ int LaTeX::startscript()
                     + quoteName(onlyFileName(file.toFilesystemEncoding()))
                     + " > " + os::nulldev();
        Systemcall one;
-       return one.startscript(Systemcall::Wait, tmp);
+       return one.startscript(Systemcall::Wait, tmp, path);
 }
 
 
@@ -448,7 +448,7 @@ bool LaTeX::runMakeIndex(string const &
        tmp += quoteName(f);
        tmp += params;
        Systemcall one;
-       one.startscript(Systemcall::Wait, tmp);
+       one.startscript(Systemcall::Wait, tmp, path);
        return true;
 }
 
@@ -464,7 +464,7 @@ bool LaTeX::runMakeIndexNomencl(FileName
        tmp += " -o "
                + onlyFileName(changeExtension(file.toFilesystemEncoding(), 
nls));
        Systemcall one;
-       one.startscript(Systemcall::Wait, tmp);
+       one.startscript(Systemcall::Wait, tmp, path);
        return true;
 }
 
@@ -604,7 +604,7 @@ bool LaTeX::runBibTeX(vector<AuxInfo> co
                tmp += quoteName(onlyFileName(removeExtension(
                                it->aux_file.absFileName())));
                Systemcall one;
-               one.startscript(Systemcall::Wait, tmp);
+               one.startscript(Systemcall::Wait, tmp, path);
        }
        // Return whether bibtex was run
        return result;
Index: src/Converter.cpp
===================================================================
--- src/Converter.cpp   (revisione 38627)
+++ src/Converter.cpp   (copia locale)
@@ -307,7 +307,7 @@ bool Converters::convert(Buffer const *
                        LYXERR(Debug::FILES, "No converter defined! "
                                   "I use convertDefault.py:\n\t" << command);
                        Systemcall one;
-                       one.startscript(Systemcall::Wait, command);
+                       one.startscript(Systemcall::Wait, command, 
buffer->filePath());
                        if (to_file.isReadableFile()) {
                                if (conversionflags & try_cache)
                                        ConverterCache::get().add(orig_from,
@@ -443,12 +443,14 @@ bool Converters::convert(Buffer const *
                        int res;
                        if (dummy) {
                                res = one.startscript(Systemcall::DontWait,
-                                       to_filesystem8bit(from_utf8(command)));
+                                       to_filesystem8bit(from_utf8(command)),
+                                       buffer->filePath());
                                // We're not waiting for the result, so we 
can't do anything
                                // else here.
                        } else {
                                res = one.startscript(Systemcall::Wait,
-                                               
to_filesystem8bit(from_utf8(command)));
+                                               
to_filesystem8bit(from_utf8(command)),
+                                               buffer->filePath());
                                if (!real_outfile.empty()) {
                                        Mover const & mover = getMover(conv.to);
                                        if (!mover.rename(outfile, 
real_outfile))
@@ -468,7 +470,8 @@ bool Converters::convert(Buffer const *
                                                " < " + quoteName(infile2 + 
".out") +
                                                " > " + quoteName(logfile);
                                        one.startscript(Systemcall::Wait,
-                                               
to_filesystem8bit(from_utf8(command2)));
+                                               
to_filesystem8bit(from_utf8(command2)),
+                                               buffer->filePath());
                                        if (!scanLog(*buffer, command, 
makeAbsPath(logfile, path), errorList))
                                                return false;
                                }
@@ -612,7 +615,8 @@ bool Converters::runLaTeX(Buffer const &
 
        // do the LaTeX run(s)
        string const name = buffer.latexName();
-       LaTeX latex(command, runparams, FileName(makeAbsPath(name)));
+       LaTeX latex(command, runparams, FileName(makeAbsPath(name)),
+                   buffer.filePath());
        TeXErrors terr;
        ShowMessage show(buffer);
        latex.message.connect(show);
Index: src/support/os_cygwin.cpp
===================================================================
--- src/support/os_cygwin.cpp   (revisione 38627)
+++ src/support/os_cygwin.cpp   (copia locale)
@@ -17,6 +17,7 @@
 
 #include "support/os.h"
 
+#include "support/environment.h"
 #include "support/FileName.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
@@ -415,13 +416,28 @@ bool canAutoOpenFile(string const & ext,
 }
 
 
-bool autoOpenFile(string const & filename, auto_open_mode const mode)
+bool autoOpenFile(string const & filename, auto_open_mode const mode,
+                 string const & path)
 {
+       string const sep = windows_style_tex_paths_ ? ";" : ":";
+       string const oldval = getEnv("TEXINPUTS");
+       string const newval = "." + sep + latex_path(path) + "/" + sep + oldval;
+       if (!path.empty()) {
+               setEnv("TEXINPUTS", newval);
+               cygwin_internal(CW_SYNC_WINENV);
+       }
+
        // reference: http://msdn.microsoft.com/en-us/library/bb762153.aspx
        string const win_path = to_local8bit(from_utf8(convert_path(filename, 
PathStyle(windows))));
        char const * action = (mode == VIEW) ? "open" : "edit";
-       return reinterpret_cast<int>(ShellExecute(NULL, action,
-               win_path.c_str(), NULL, NULL, 1)) > 32;
+       bool success = reinterpret_cast<int>(ShellExecute(NULL, action,
+                                       win_path.c_str(), NULL, NULL, 1)) > 32;
+
+       if (!path.empty()) {
+               setEnv("TEXINPUTS", oldval);
+               cygwin_internal(CW_SYNC_WINENV);
+       }
+       return success;
 }
 
 
Index: src/support/Systemcall.cpp
===================================================================
--- src/support/Systemcall.cpp  (revisione 38627)
+++ src/support/Systemcall.cpp  (copia locale)
@@ -14,6 +14,7 @@
 #include <config.h>
 
 #include "support/debug.h"
+#include "support/environment.h"
 #include "support/lstrings.h"
 #include "support/qstring_helpers.h"
 #include "support/Systemcall.h"
@@ -21,6 +22,7 @@
 #include "support/os.h"
 #include "support/ProgressInterface.h"
 
+#include "LyXRC.h"
 
 #include <cstdlib>
 #include <iostream>
@@ -96,9 +98,24 @@ ProgressInterface* ProgressInterface::in
 // Reuse of instance
 #ifndef USE_QPROCESS
 int Systemcall::startscript(Starttype how, string const & what,
-                                                       bool /*process_events*/)
+                           std::string const & path, bool /*process_events*/)
 {
-       string command = what;
+       string command;
+       string const sep = lyxrc.windows_style_tex_paths ? ";" : ":";
+       string const env = getEnv("TEXINPUTS");
+
+       switch (os::shell()) {
+       case os::UNIX:
+               command = path.empty() ? what
+                       : "env TEXINPUTS='." + sep + os::latex_path(path)
+                               + "/" + sep + env + "' " + what;
+               break;
+       case os::CMD_EXE:
+               command = path.empty() ? what
+                       : "set TEXINPUTS=." + sep + os::latex_path(path)
+                               + "/" + sep + env + " & " + what;
+               break;
+       }
 
        if (how == DontWait) {
                switch (os::shell()) {
@@ -204,7 +221,8 @@ string const parsecmd(string const & inp
 
 
 
-int Systemcall::startscript(Starttype how, string const & what, bool 
process_events)
+int Systemcall::startscript(Starttype how, string const & what,
+                           string const & path, bool process_events)
 {
        string outfile;
        QString cmd = toqstr(parsecmd(what, outfile));
@@ -212,7 +230,7 @@ int Systemcall::startscript(Starttype ho
        SystemcallPrivate d(outfile);
 
 
-       d.startProcess(cmd);
+       d.startProcess(cmd, path);
        if (!d.waitWhile(SystemcallPrivate::Starting, process_events, -1)) {
                LYXERR0("Systemcall: '" << cmd << "' did not start!");
                LYXERR0("error " << d.errorMessage());
@@ -264,10 +282,22 @@ SystemcallPrivate::SystemcallPrivate(con
 
 
 
-void SystemcallPrivate::startProcess(const QString& cmd)
+void SystemcallPrivate::startProcess(QString const & cmd, string const & path)
 {
        cmd_ = cmd;
        if (process_) {
+               if (!path.empty()) {
+                       QChar const sep = lyxrc.windows_style_tex_paths ? ';' : 
':';
+                       QString const prefix = QLatin1String("TEXINPUTS=.")
+                               + sep + toqstr(os::latex_path(path)) + "/" + 
sep;
+                       QStringList env = QProcess::systemEnvironment();
+                       if (env.filter("TEXINPUTS=").isEmpty())
+                               env << prefix;
+                       else
+                               env.replaceInStrings(QRegExp("^TEXINPUTS=(.*)"),
+                                                    prefix + "\\1");
+                       process_->setEnvironment(env);
+               }
                state = SystemcallPrivate::Starting;
                process_->start(cmd_);
        }
Index: src/support/os_unix.cpp
===================================================================
--- src/support/os_unix.cpp     (revisione 38627)
+++ src/support/os_unix.cpp     (copia locale)
@@ -14,6 +14,7 @@
 
 #include "support/os.h"
 #include "support/docstring.h"
+#include "support/environment.h"
 #include "support/FileName.h"
 #include "support/lstrings.h"
 #include "support/lassert.h"
@@ -258,7 +259,8 @@ bool canAutoOpenFile(string const & ext,
 }
 
 
-bool autoOpenFile(string const & filename, auto_open_mode const mode)
+bool autoOpenFile(string const & filename, auto_open_mode const mode,
+                 string const & path)
 {
 #ifdef __APPLE__
 // Reference: 
http://developer.apple.com/documentation/Carbon/Reference/LaunchServicesReference/
@@ -279,6 +281,11 @@ bool autoOpenFile(string const & filenam
        if (status == kLSApplicationNotFoundErr)
                return false;
 
+       string const oldval = getEnv("TEXINPUTS");
+       string const newval = ".:" + path + "/:" + oldval;
+       if (!path.empty())
+               setEnv("TEXINPUTS", newval);
+
        LSLaunchFSRefSpec inLaunchSpec;
        inLaunchSpec.appRef = &outAppRef;
        inLaunchSpec.numDocs = 1;
@@ -288,11 +295,15 @@ bool autoOpenFile(string const & filenam
        inLaunchSpec.asyncRefCon = NULL;
        status = LSOpenFromRefSpec(&inLaunchSpec, NULL);
 
+       if (!path.empty())
+               setEnv("TEXINPUTS", oldval);
+
        return status != kLSApplicationNotFoundErr;
 #else
        // silence compiler warnings
        (void)filename;
        (void)mode;
+       (void)path;
 
        // currently, no default viewer is tried for non-windows system
        // support for KDE/Gnome/Macintosh may be added later
Index: src/support/os.h
===================================================================
--- src/support/os.h    (revisione 38627)
+++ src/support/os.h    (copia locale)
@@ -133,14 +133,15 @@ enum auto_open_mode {
  *  \param mode can be opened in VIEW or EDIT mode
  *  \returns whether or not the format can be opened according to \p mode
  */
-bool canAutoOpenFile(std::string const & ext, auto_open_mode const mode = 
VIEW);
+bool canAutoOpenFile(std::string const & ext, auto_open_mode const mode);
 
 /** View or edit a file with the default viewer or editor.
  *  \param filename file to open (encoded in utf8)
  *  \param mode open in VIEW or EDIT mode
  *  \returns whether or not the file is viewed (or edited) successfully.
  */
-bool autoOpenFile(std::string const & filename, auto_open_mode const mode = 
VIEW);
+bool autoOpenFile(std::string const & filename, auto_open_mode const mode,
+                 std::string const & path = empty_string());
 
 /** Resolves a path such that it does not contain '.', '..', or symbolic links.
   * \p path and the return value are encoded in utf8.
Index: src/support/Systemcall.h
===================================================================
--- src/support/Systemcall.h    (revisione 38627)
+++ src/support/Systemcall.h    (copia locale)
@@ -40,10 +40,13 @@ public:
 
        /** Start child process.
         *  The string "what" contains a commandline with arguments separated
-        *  by spaces. Unset "process_events" in case UI should be blocked while
-        *  processing the external command.
+        *  by spaces. The string "path" contains the path to be prepended to
+        *  the TEXINPUTS environment variable. Unset "process_events" in
+        *  case UI should be blocked while processing the external command.
         */
-       int startscript(Starttype how, std::string const & what, bool 
process_events = false);
+       int startscript(Starttype how, std::string const & what,
+                       std::string const & path = empty_string(),
+                       bool process_events = false);
 };
 
 } // namespace support
Index: src/support/os_win32.cpp
===================================================================
--- src/support/os_win32.cpp    (revisione 38627)
+++ src/support/os_win32.cpp    (copia locale)
@@ -19,6 +19,7 @@
 #include "support/os_win32.h"
 
 #include "support/debug.h"
+#include "support/environment.h"
 #include "support/FileName.h"
 #include "support/gettext.h"
 #include "support/filetools.h"
@@ -507,12 +508,23 @@ bool canAutoOpenFile(string const & ext,
 }
 
 
-bool autoOpenFile(string const & filename, auto_open_mode const mode)
+bool autoOpenFile(string const & filename, auto_open_mode const mode,
+                 string const & path)
 {
+       string const sep = windows_style_tex_paths_ ? ";" : ":";
+       string const oldval = getEnv("TEXINPUTS");
+       string const newval = "." + sep + latex_path(path) + "/" + sep + oldval;
+       if (!path.empty())
+               setEnv("TEXINPUTS", newval);
+
        // reference: http://msdn.microsoft.com/en-us/library/bb762153.aspx
        char const * action = (mode == VIEW) ? "open" : "edit";
-       return reinterpret_cast<int>(ShellExecute(NULL, action,
+       bool success = reinterpret_cast<int>(ShellExecute(NULL, action,
                to_local8bit(from_utf8(filename)).c_str(), NULL, NULL, 1)) > 32;
+
+       if (!path.empty())
+               setEnv("TEXINPUTS", oldval);
+       return success;
 }
 
 
Index: src/support/SystemcallPrivate.h
===================================================================
--- src/support/SystemcallPrivate.h     (revisione 38627)
+++ src/support/SystemcallPrivate.h     (copia locale)
@@ -44,7 +44,7 @@ public:
        State state;
 
        bool waitWhile(State, bool processEvents, int timeout = -1);
-       void startProcess(const QString& cmd);
+       void startProcess(QString const & cmd, std::string const & path);
        
        int exitCode();
 
Index: src/VCBackend.cpp
===================================================================
--- src/VCBackend.cpp   (revisione 38627)
+++ src/VCBackend.cpp   (copia locale)
@@ -43,7 +43,7 @@ int VCS::doVCCommandCall(string const &
        LYXERR(Debug::LYXVC, "doVCCommandCall: " << cmd);
        Systemcall one;
        support::PathChanger p(path);
-       return one.startscript(Systemcall::Wait, cmd, false);
+       return one.startscript(Systemcall::Wait, cmd, string(), false);
 }
 
 
Index: src/LaTeX.h
===================================================================
--- src/LaTeX.h (revisione 38627)
+++ src/LaTeX.h (copia locale)
@@ -151,7 +151,8 @@ public:
           path = name of the files original path.
        */
        LaTeX(std::string const & cmd, OutputParams const &,
-             support::FileName const & file);
+             support::FileName const & file,
+             std::string const & path = empty_string());
 
        /// runs LaTeX several times
        int run(TeXErrors &);
@@ -210,6 +211,9 @@ private:
        ///
        support::FileName file;
 
+       ///
+       std::string path;
+
        /// used by scanLogFile
        int num_errors;
 
Index: src/Format.cpp
===================================================================
--- src/Format.cpp      (revisione 38627)
+++ src/Format.cpp      (copia locale)
@@ -285,7 +285,7 @@ bool Formats::view(Buffer const & buffer
        }
        // viewer is 'auto'
        if (format->viewer() == "auto") {
-               if (os::autoOpenFile(filename.absFileName(), os::VIEW))
+               if (os::autoOpenFile(filename.absFileName(), os::VIEW, 
buffer.filePath()))
                        return true;
                else {
                        Alert::error(_("Cannot view file"),
@@ -320,7 +320,7 @@ bool Formats::view(Buffer const & buffer
        buffer.message(_("Executing command: ") + from_utf8(command));
 
        Systemcall one;
-       one.startscript(Systemcall::DontWait, command);
+       one.startscript(Systemcall::DontWait, command, buffer.filePath());
 
        // we can't report any sort of error, since we aren't waiting
        return true;
@@ -364,7 +364,7 @@ bool Formats::edit(Buffer const & buffer
 
        // editor is 'auto'
        if (format->editor() == "auto") {
-               if (os::autoOpenFile(filename.absFileName(), os::EDIT))
+               if (os::autoOpenFile(filename.absFileName(), os::EDIT, 
buffer.filePath()))
                        return true;
                else {
                        Alert::error(_("Cannot edit file"),
@@ -387,7 +387,7 @@ bool Formats::edit(Buffer const & buffer
        buffer.message(_("Executing command: ") + from_utf8(command));
 
        Systemcall one;
-       one.startscript(Systemcall::DontWait, command);
+       one.startscript(Systemcall::DontWait, command, buffer.filePath());
 
        // we can't report any sort of error, since we aren't waiting
        return true;
Index: src/Buffer.cpp
===================================================================
--- src/Buffer.cpp      (revisione 38627)
+++ src/Buffer.cpp      (copia locale)
@@ -2083,7 +2083,7 @@ void Buffer::dispatch(FuncRequest const
 
                // Execute the command in the background
                Systemcall call;
-               call.startscript(Systemcall::DontWait, command);
+               call.startscript(Systemcall::DontWait, command, filePath());
                break;
        }
 
@@ -2261,7 +2261,8 @@ void Buffer::dispatch(FuncRequest const
                                command2 += quoteName(psname);
                                // First run dvips.
                                // If successful, then spool command
-                               res = one.startscript(Systemcall::Wait, 
command);
+                               res = one.startscript(Systemcall::Wait, command,
+                                                     filePath());
 
                                if (res == 0) {
                                        // If there's no GUI, we have to wait 
on this command. Otherwise,
@@ -2269,7 +2270,8 @@ void Buffer::dispatch(FuncRequest const
                                        // file, before it can be printed!!
                                        Systemcall::Starttype stype = use_gui ?
                                                Systemcall::DontWait : 
Systemcall::Wait;
-                                       res = one.startscript(stype, command2);
+                                       res = one.startscript(stype, command2,
+                                                             filePath());
                                }
                        } else {
                                // case 2: print directly to a printer
@@ -2278,7 +2280,8 @@ void Buffer::dispatch(FuncRequest const
                                // as above....
                                Systemcall::Starttype stype = use_gui ?
                                        Systemcall::DontWait : Systemcall::Wait;
-                               res = one.startscript(stype, command + 
quoteName(dviname));
+                               res = one.startscript(stype, command +
+                                               quoteName(dviname), filePath());
                        }
 
                } else {
@@ -2301,7 +2304,7 @@ void Buffer::dispatch(FuncRequest const
                        // as above....
                        Systemcall::Starttype stype = use_gui ?
                                Systemcall::DontWait : Systemcall::Wait;
-                       res = one.startscript(stype, command);
+                       res = one.startscript(stype, command, filePath());
                }
 
                if (res == 0) 

Attachment: example.tar.gz
Description: application/tar-gz

Reply via email to