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)
example.tar.gz
Description: application/tar-gz