Angus Leeming wrote:
> If you're happy with this, I'll make the change, commit it to the 1.3.x
> tree and forward-port it to 1.4.x. AFAIK, that's all squashable bugs
> squashed for 1.3.x. If you know different, please keep it to yourself ;-)
Patch attached. I also implemented Paul Rubin's suggestion of popping up a
warning the first time that the user exports a file to LaTeX that
references a BibTeX database whose path contains spaces.
--
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 -p -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 14 Jul 2005 09:09:59 -0000
@@ -10,26 +10,31 @@
#include <config.h>
#include "insetbib.h"
+
#include "buffer.h"
-#include "debug.h"
#include "BufferView.h"
+#include "debug.h"
#include "gettext.h"
-#include "lyxtext.h"
-#include "lyxrc.h"
#include "lyxlex.h"
-#include "frontends/font_metrics.h"
-#include "frontends/LyXView.h"
+#include "lyxrc.h"
+#include "lyxtext.h"
+#include "frontends/Alert.h"
#include "frontends/Dialogs.h"
+#include "frontends/font_metrics.h"
+#include "frontends/LyXView.h"
#include "support/filetools.h"
-#include "support/path.h"
-#include "support/os.h"
-#include "support/lstrings.h"
#include "support/LAssert.h"
+#include "support/lstrings.h"
+#include "support/os.h"
+#include "support/path.h"
+
+#include <boost/tokenizer.hpp>
-#include <fstream>
#include <cstdlib>
+#include <fstream>
+#include "Lsstream.h"
using std::ostream;
using std::ifstream;
@@ -150,12 +155,12 @@ string normalize_name(Buffer const * buf
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 +214,70 @@ int InsetBibtex::latex(Buffer const * bu
}
// 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 const begin = tokens.begin();
+ Tokenizer::const_iterator const end = tokens.end();
+
+ ostringstream dbs;
+ for (Tokenizer::const_iterator it = begin; 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;
+ }
+ }
+
+ if (it != begin)
+ dbs << ',';
+ dbs << latex_path(database);
+ }
+ string const dbs_str = dbs.str();
+
+ // Post this warning only once.
+ static bool warned_about_spaces = false;
+ if (!warned_about_spaces &&
+ buffer->niceFile && dbs_str.find(' ') != string::npos) {
+ warned_about_spaces = true;
+
+ Alert::alert(_("LyX Warning!"),
+ _("There are spaces in the paths to your BibTeX databases."),
+ _("BibTeX will be unable to find them."));
+
+ }
+
+ int nnewlines = 1;
+ if (!dbs_str.empty()) {
+ ++nnewlines;
+ os << "\\bibliography{" << dbs_str << "}\n";
}
- db_out = rtrim(db_out, ",");
- os << "\\bibliography{" << db_out << "}\n";
- return 2;
+ 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 -p -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 14 Jul 2005 09:10:01 -0000
@@ -619,37 +619,24 @@ string const InsetGraphics::prepareFile(
<< "\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 -p -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 14 Jul 2005 09:10:03 -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 @@ string const readBB_from_PSFile(string c
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 -p -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 14 Jul 2005 09:10:03 -0000
@@ -247,8 +247,21 @@ void removeAutosaveFile(string const & f
/// 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