The attached patch
* backports the name mangling code from the 1.4 tree and extends it
slightly so that the mangled path is never longer than about 160 characters.
* Uses this mangled path in the graphics inset to ensure that YAP does not
crash when attempting to view your graphics files.
* Copies any BibTeX databases to the temp directory, mangling their names
in the process. This ensures that any "files with spaces" that cause BibTeX
to fail can be processed successfully.
Jean-Marc, OK to apply to the 1.3.x tree?
Angus
Index: src/insets/insetbib.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/Attic/insetbib.C,v
retrieving revision 1.97.2.4
diff -u -a -u -r1.97.2.4 insetbib.C
--- src/insets/insetbib.C 18 Apr 2005 17:44:04 -0000 1.97.2.4
+++ src/insets/insetbib.C 13 Jul 2005 16:16:00 -0000
@@ -28,6 +28,8 @@
#include "support/lstrings.h"
#include "support/LAssert.h"
+#include <boost/tokenizer.hpp>
+
#include <fstream>
#include <cstdlib>
@@ -150,12 +152,12 @@
string const fname = MakeAbsPath(name, buffer->filePath());
if (AbsolutePath(name) || !IsFileReadable(fname + ext))
return name;
- else if (!buffer->niceFile)
+ else if (!buffer->niceFile)
return fname;
- else
+ else
return MakeRelPath(fname,
buffer->getMasterBuffer()->filePath());
}
-
+
}
@@ -209,21 +211,67 @@
}
// database
- // If we generate in a temp dir, we might need to give an
- // absolute path there. This is a bit complicated since we can
- // have a comma-separated list of bibliographies
- string adb, db_out;
- string db_in = getContents();
- db_in = split(db_in, adb, ',');
- while (!adb.empty()) {
- db_out += latex_path(normalize_name(buffer, adb, ".bib"));
- db_out += ',';
- db_in= split(db_in, adb,',');
+ // If we are processing the LaTeX file in a temp directory then
+ // copy the .bib databases to this temp directory, mangling their
+ // names in the process. Store this mangled name in the list of
+ // all databases.
+ // (We need to do all this because BibTeX *really*, *really*
+ // can't handle "files with spaces" and Windows users tend to
+ // use such filenames.)
+ // Otherwise, store the (maybe absolute) path to the original,
+ // unmangled database name.
+ typedef boost::char_separator<char> Separator;
+ typedef boost::tokenizer<Separator> Tokenizer;
+
+ Separator const separator(",");
+ Tokenizer const tokens(getContents(), separator);
+ Tokenizer::const_iterator it = tokens.begin();
+ Tokenizer::const_iterator const end = tokens.end();
+
+ vector<string> databases;
+ for (; it != end; ++it) {
+ string const input = trim(*it);
+ string database = normalize_name(buffer, input, ".bib");
+ string const in_file = database + ".bib";
+
+ if (!buffer->niceFile &&
+ lyxrc.use_tempdir &&
+ IsFileReadable(in_file)) {
+
+ database = mangled_filename(database);
+ string const out_file = MakeAbsPath(database + ".bib",
+ buffer->tmppath);
+
+ bool const success = lyx::copy(in_file, out_file);
+ if (!success) {
+ lyxerr << "Failed to copy '" << in_file
+ << "' to '" << out_file << "'"
+ << endl;
+ }
+
+ databases.push_back(latex_path(database));
+ } else {
+ databases.push_back(latex_path(database));
+ }
}
- db_out = rtrim(db_out, ",");
- os << "\\bibliography{" << db_out << "}\n";
- return 2;
+ int nnewlines = 1;
+ if (!databases.empty()) {
+ ++nnewlines;
+
+ typedef vector<string>::const_iterator iterator;
+ iterator const begin = databases.begin();
+ iterator const end = databases.end();
+
+ os << "\\bibliography{";
+ for (iterator it = begin; it != end; ++it) {
+ if (it != begin)
+ os << ',';
+ os << *it;
+ }
+ os << "}\n";
+ }
+ return nnewlines;
}
Index: src/insets/insetgraphics.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insetgraphics.C,v
retrieving revision 1.146.2.12
diff -u -a -u -r1.146.2.12 insetgraphics.C
--- src/insets/insetgraphics.C 4 Jul 2005 11:26:41 -0000 1.146.2.12
+++ src/insets/insetgraphics.C 13 Jul 2005 16:16:24 -0000
@@ -619,37 +619,24 @@
<< "\tthe orig file is: " << orig_file_with_path << endl;
if (lyxrc.use_tempdir) {
- string const ext_tmp = GetExtension(orig_file_with_path);
- // without ext and /
- temp_file = subst(
- ChangeExtension(orig_file_with_path, string()), "/",
"_");
- // Replace ' ' in the file name with '_'
- temp_file = subst(temp_file, " ", "_");
- // without dots and again with ext
- temp_file = ChangeExtension(
- subst(temp_file, ".", "_"), ext_tmp);
-
-#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(_WIN32)
- // Mangle the drive letter in a Windows-style path.
- if (temp_file.size() >= 2 && temp_file[1] == ':')
- temp_file[1] = '_';
-#endif
-
- // now we have any_dir_file.ext
+ temp_file = mangled_filename(orig_file_with_path, buf->tmppath);
temp_file = MakeAbsPath(temp_file, buf->tmppath);
+
lyxerr[Debug::GRAPHICS]
<< "\tchanged to: " << temp_file << endl;
- // if the file doen't exists, copy it into the tempdir
+ // if the file doesn't exist, copy it into the tempdir
if (file_has_changed || !IsFileReadable(temp_file)) {
bool const success = lyx::copy(orig_file_with_path,
temp_file);
lyxerr[Debug::GRAPHICS]
- << "\tcopying from " << orig_file_with_path <<
" to "
+ << "\tcopying from "
+ << orig_file_with_path << " to "
<< temp_file
<< (success ? " succeeded\n" : " failed\n");
if (!success) {
- Alert::alert(_("Cannot copy file"),
orig_file_with_path,
- _("into tempdir"));
+ Alert::alert(_("Cannot copy file"),
+ orig_file_with_path,
+ _("into tempdir"));
return orig_file;
}
}
Index: src/support/filetools.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/filetools.C,v
retrieving revision 1.146.2.19
diff -u -a -u -r1.146.2.19 filetools.C
--- src/support/filetools.C 5 Jul 2005 07:45:44 -0000 1.146.2.19
+++ src/support/filetools.C 13 Jul 2005 16:16:24 -0000
@@ -41,8 +41,9 @@
#include <fcntl.h>
#include <cerrno>
-#include <utility>
#include <fstream>
+#include <map>
+#include <utility>
// Which part of this is still necessary? (JMarc).
@@ -1505,3 +1506,65 @@
readBB_lyxerrMessage(file_, zipped, "no bb found");
return string();
}
+
+
+string const mangled_filename(string const & filename, string const & dir)
+{
+ // We need to make sure that every FileName instance for a given
+ // filename returns the same mangled name.
+ typedef std::map<string, string> MangledMap;
+ static MangledMap mangledNames;
+ MangledMap::const_iterator const it = mangledNames.find(filename);
+ if (it != mangledNames.end())
+ return (*it).second;
+
+ // Now the real work
+ string mname = os::internal_path(filename);
+ // Remove the extension.
+ mname = ChangeExtension(filename, string());
+ // Replace '/' in the file name with '_'
+ mname = subst(mname, "/", "_");
+ // Replace '.' in the file name with '_'
+ mname = subst(mname, ".", "_");
+ // Replace ' ' in the file name with '_'
+ mname = subst(mname, " ", "_");
+ // Replace ':' in the file name with '_'
+ mname = subst(mname, ":", "_");
+ // Add the extension back on
+ mname = ChangeExtension(mname, GetExtension(filename));
+
+ // Prepend a counter to the filename. This is necessary to make
+ // the mangled name unique.
+ static int counter = 0;
+ std::ostringstream s;
+ s << counter++ << mname;
+ mname = STRCONV(s.str());
+
+ // Experiments show that MiKTeX's YAP (version 2.4.1803)
+ // will crash if the string referencing the file name in
+ // the .dvi file is longer than 220 characters.
+ // This string contains about 50 chars-worth of other data,
+ // leaving us, say, 160 characters for the file name itself.
+ // (Erring on the side of caution.)
+ string::size_type max_length = 160;
+ if (dir.size() - 1 < max_length) {
+ // If dir.size() > max_length, all bets are off anyway.
+ // "+ 1" for the directory separator.
+ max_length -= dir.size() + 1;
+
+ // If the mangled file name is too long, hack it to fit.
+ // We know we're guaranteed to have a unique file name because
+ // of the counter.
+ if (mname.size() > max_length) {
+ int const half = (int(max_length) / 2) - 2;
+ if (half > 0) {
+ mname = mname.substr(0, half) + "___" +
+ mname.substr(mname.size() - half);
+ }
+ }
+ }
+
+ mangledNames[filename] = mname;
+ return mname;
+}
+
Index: src/support/filetools.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/filetools.h,v
retrieving revision 1.38.2.7
diff -u -a -u -r1.38.2.7 filetools.h
--- src/support/filetools.h 4 Jul 2005 11:26:42 -0000 1.38.2.7
+++ src/support/filetools.h 13 Jul 2005 16:16:24 -0000
@@ -247,8 +247,21 @@
/// read the BoundingBox entry from a ps/eps/pdf-file
string const readBB_from_PSFile(string const & file);
-typedef std::pair<int, string> cmd_ret;
+/** @param filename the file path that is to be mangled.
+ * @param dir the directory that will contain this file with
+ * its mangled name. This information is used by the mangling
+ * algorithm when determining the maximum allowable length of
+ * the mangled name.
+ * @returns a mangled representation of the input @c filename.
+ * Eg C:/foo bar/baz.eps -> 0C__foo_bar_baz.eps
+ * The integer prefix is used to guarantee that the file name
+ * is unique.
+ * Only the file name is returned. It is not prepended with @c dir.
+ */
+string const mangled_filename(string const & filename,
+ string const & dir = string());
+typedef std::pair<int, string> cmd_ret;
cmd_ret const RunCommand(string const & cmd);
#endif