This patch has been to the list previously and been more or less
approved. I'm sending it again, however, as I've made some additional
changes and it should be tested by at least one other person, I think,
before I commit. If you do test, please test: (i) View>HTML; (ii)
File>Export>HTML; (iii) File>Export>HTML again, so that the original
export is over-written; and (iv) please make sure I didn't break
View>DVI (which I temporarily managed to do on my own machine).

Oh, to get this to work, you'll need to reconfigure so that the
converter definition for Latex->HTML is updated.

Richard

-- 
==================================================================
Richard G Heck, Jr
Professor of Philosophy
Brown University
http://frege.brown.edu/heck/
==================================================================
Get my public key from http://sks.keyserver.penguin.de
Hash: 0x1DE91F1E66FFBDEC
Learn how to sign your email using Thunderbird and GnuPG at:
http://dudu.dyn.2-h.org/nist/gpg-enigmail-howto

Index: lib/configure.py
===================================================================
--- lib/configure.py	(revision 18444)
+++ lib/configure.py	(working copy)
@@ -348,7 +348,7 @@
         rc_entry = [ r'\converter word       latex      "%%"	""' ])
     #
     checkProg('a LaTeX -> MS Word converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
-        rc_entry = [ r'\converter latex      wordhtml   "%%"	"originaldir,needaux"' ])
+        rc_entry = [ r'\converter latex      wordhtml   "%%"	"usetempdir,needaux"' ])
     #
     checkProg('an OpenOffice.org -> LaTeX converter', ['w2l -clean $$i'],
         rc_entry = [ r'\converter sxw        latex      "%%"	""' ])
@@ -359,10 +359,6 @@
     checkProg('a LaTeX -> Open Document converter', ['oolatex $$i', 'oolatex.sh $$i'],
         rc_entry = [ r'\converter latex      odt        "%%"	"latex"' ])
     #
-    #FIXME Looking for the commands needed to make oolatex output sxw instad of odt...
-    #checkProg('a LaTeX -> OpenOffice.org (sxw) converter', ['oolatex $$i', 'oolatex.sh $$i'],
-    #    rc_entry = [ r'\converter latex      odt        "%%"	"latex"' ])
-    # On windows it is called latex2rt.exe
     checkProg('a LaTeX -> RTF converter', ['latex2rtf -p -S -o $$o $$i', 'latex2rt -p -S -o $$o $$i'],
         rc_entry = [ r'\converter latex      rtf        "%%"	"needaux"' ])
     #
@@ -431,7 +427,7 @@
     #
     checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'tth  -t -e2 -L$$b < $$i > $$o', \
         'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
-        rc_entry = [ r'\converter latex      html       "%%"	"originaldir,needaux"' ])
+        rc_entry = [ r'\converter latex      html       "%%"	"usetempdir,needaux"' ])
     #
     path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond'])
     if (lilypond != ''):
Index: src/Converter.h
===================================================================
--- src/Converter.h	(revision 18444)
+++ src/Converter.h	(working copy)
@@ -55,10 +55,11 @@
 	bool latex;
 	/// The converter is xml
 	bool xml;
-	/// Do we need to run the converter in the original directory?
-	bool original_dir;
 	/// This converter needs the .aux files
 	bool need_aux;
+	/// This converter should put its files in a separate temporary
+	/// directory
+	bool use_temp_dir;
 	/// If the converter put the result in a directory, then result_dir
 	/// is the name of the directory
 	std::string result_dir;
@@ -123,6 +124,14 @@
 	             support::FileName const & orig_from,
 	             std::string const & from_format, std::string const & to_format,
 	             ErrorList & errorList, int conversionflags = none);
+	/// used_tmp_dir is a flag that signals whether our output files were put into
+	/// a temporary directory. Note also that to_file will be changed so that it points 
+	/// at the converted file in this case.
+	bool convert(Buffer const * buffer,
+	             support::FileName const & from_file, support::FileName & to_file,
+	             support::FileName const & orig_from, bool & used_temp_dir,
+	             std::string const & from_format, std::string const & to_format,
+	             ErrorList & errorList, int conversionflags = none);
 	///
 	void update(Formats const & formats);
 	///
Index: src/Converter.cpp
===================================================================
--- src/Converter.cpp	(revision 18444)
+++ src/Converter.cpp	(working copy)
@@ -31,7 +31,6 @@
 #include "support/Path.h"
 #include "support/Systemcall.h"
 
-
 namespace lyx {
 
 using support::addName;
@@ -118,7 +117,8 @@
 		     string const & c, string const & l)
 	: from(f), to(t), command(c), flags(l),
 	  From(0), To(0), latex(false), xml(false),
-	  original_dir(false), need_aux(false)
+	  need_aux(false),
+		use_temp_dir(false)
 {}
 
 
@@ -133,8 +133,8 @@
 			latex = true;
 		else if (flag_name == "xml")
 			xml = true;
-		else if (flag_name == "originaldir")
-			original_dir = true;
+		else if (flag_name == "usetempdir")
+			use_temp_dir = true;
 		else if (flag_name == "needaux")
 			need_aux = true;
 		else if (flag_name == "resultdir")
@@ -145,6 +145,10 @@
 		else if (flag_name == "parselog")
 			parselog = flag_value;
 	}
+	if (!result_dir.empty() && use_temp_dir) {
+		lyxerr << "Cannot set resultdir and usetempdir together." << endl;
+		use_temp_dir = false;
+	}
 	if (!result_dir.empty() && result_file.empty())
 		result_file = "index." + formats.extension(to);
 	//if (!contains(command, token_from))
@@ -293,15 +297,34 @@
                          string const & from_format, string const & to_format,
                          ErrorList & errorList, int conversionflags)
 {
+	FileName tmp_to_file = to_file;
+	bool trash;
+	return convert(buffer, from_file, tmp_to_file, orig_from, trash,
+	               from_format, to_format, errorList, conversionflags);
+}
+
+
+//FIXME Georg suggested that the converter should ALWAYS determine the
+//name of the converted file. So this should return a FileName, and it
+//can return an empty one on failure. The used_temp_dir flag may still
+//need to be set, though.
+bool Converters::convert(Buffer const * buffer,
+                         FileName const & from_file, FileName & to_file,
+                         FileName const & orig_from, bool & used_temp_dir,
+                         string const & from_format, string const & to_format,
+                         ErrorList & errorList, int conversionflags)
+{
 	if (from_format == to_format)
 		return move(from_format, from_file, to_file, false);
 
-	if ((conversionflags & try_cache) &&
-	    ConverterCache::get().inCache(orig_from, to_format))
-		return ConverterCache::get().copy(orig_from, to_format, to_file);
+	used_temp_dir = false;
 
 	Graph::EdgePath edgepath = getPath(from_format, to_format);
 	if (edgepath.empty()) {
+		if ((conversionflags & try_cache) &&
+		    ConverterCache::get().inCache(orig_from, to_format)
+		 	)
+			return ConverterCache::get().copy(orig_from, to_format, to_file);
 		if (conversionflags & try_default) {
 			// if no special converter defined, then we take the
 			// default one from ImageMagic.
@@ -336,8 +359,25 @@
 							from_ascii(from_format), from_ascii(to_format)));
 		return false;
 	}
+	
+	// At this point, we have a non-empty EdgePath (i.e., sequence
+	// of converters) to run.
 
-	// buffer is only invalid for importing, and then runparams is not
+	// set lastConv to the last converter in the chain
+	Converter const & lastConv = converterlist_[edgepath.back()];
+	
+	//FIXME As things presently are, the cache routines aren't set up to
+	//cache more than one file. So we have to skip this when we're using
+	//the flags that indicate we're probably dealing with more than one
+	//file. For then only the main result file and none of the supporting 
+	//files (eg, the CSS file in the case of htlatex) would be cached.
+	if ((conversionflags & try_cache) &&
+	    ConverterCache::get().inCache(orig_from, to_format) &&
+	    !lastConv.use_temp_dir
+		 )
+		return ConverterCache::get().copy(orig_from, to_format, to_file);
+	
+	// buffer is invalid if we're importing, and then runparams is not
 	// used anyway.
 	OutputParams runparams(buffer ? &buffer->params().encoding() : 0);
 	runparams.flavor = getFlavor(edgepath);
@@ -346,7 +386,7 @@
 	// current directory, so we need to change the current directory.
 	// This has the added benefit that all other files that may be
 	// generated by the converter are deleted when LyX closes and do not
-	// clutter the real working directory.
+	// clutter the real working directory. 
 	string const path(onlyPath(from_file.absFilename()));
 	// Prevent the compiler from optimizing away p
 	FileName pp(path);
@@ -355,7 +395,7 @@
 	// empty the error list before any new conversion takes place.
 	errorList.clear();
 
-	bool run_latex = false;
+	bool ran_latex = false;
 	string from_base = changeExtension(from_file.absFilename(), "");
 	string to_base = changeExtension(to_file.absFilename(), "");
 	FileName infile;
@@ -367,30 +407,51 @@
 		if (!dummy)
 			LYXERR(Debug::FILES) << "Converting from  "
 			       << conv.from << " to " << conv.to << endl;
+		//input file for this converter is output file from last one
 		infile = outfile;
-		outfile = FileName(conv.result_dir.empty()
-			? changeExtension(from_file.absFilename(), conv.To->extension())
-			: addName(subst(conv.result_dir,
+		
+		//set output filename
+		string temp_dir;
+		if (conv.result_dir.empty()) {
+			if (conv.use_temp_dir) {
+				string const basename = 
+					changeExtension(onlyFilename(outfile.toFilesystemEncoding()), "");
+				temp_dir = addName(buffer->temppath(), 
+			    basename + "." + to_format + ".conversion");
+				outfile = FileName(addName(temp_dir, 
+				                   basename + "." + to_format));
+			} else
+				outfile = 
+					FileName(changeExtension(from_file.absFilename(), 
+					         conv.To->extension()));
+		}
+		else
+			outfile = FileName(addName(subst(conv.result_dir,
 					token_base, from_base),
 				  subst(conv.result_file,
 					token_base, onlyFilename(from_base))));
 
 		// if input and output files are equal, we use a
 		// temporary file as intermediary (JMarc)
+		bool const needTempFile = (outfile == infile);
 		FileName real_outfile;
-		if (outfile == infile) {
+		if (needTempFile) {
 			real_outfile = infile;
 			outfile = FileName(addName(buffer->temppath(), "tmpfile.out"));
-		}
-
+		} 
+		
+		//run latex if requested...
 		if (conv.latex) {
-			run_latex = true;
+			ran_latex = true;
 			string const command = subst(conv.command, token_from, "");
 			LYXERR(Debug::FILES) << "Running " << command << endl;
 			if (!runLaTeX(*buffer, command, runparams, errorList))
 				return false;
-		} else {
-			if (conv.need_aux && !run_latex
+		} 
+		else {
+			//or if needed to generate the aux file and latex hasn't been
+			//run yet
+			if (conv.need_aux && !ran_latex
 			    && !latex_command_.empty()) {
 				LYXERR(Debug::FILES)
 					<< "Running " << latex_command_
@@ -399,48 +460,59 @@
 			}
 
 			// FIXME UNICODE
-			string const infile2 = (conv.original_dir)
-				? infile.absFilename() : to_utf8(makeRelPath(from_utf8(infile.absFilename()),
-				                                             from_utf8(path)));
-			string const outfile2 = (conv.original_dir)
-				? outfile.absFilename() : to_utf8(makeRelPath(from_utf8(outfile.absFilename()),
-				                                              from_utf8(path)));
-
+			string const infile2 = (conv.use_temp_dir)
+				? infile.absFilename() : 
+					to_utf8(makeRelPath(from_utf8(infile.absFilename()),
+															from_utf8(path)));
+			string const outfile2 = (conv.use_temp_dir)
+				? outfile.absFilename() : 
+					to_utf8(makeRelPath(from_utf8(outfile.absFilename()),
+															from_utf8(path)));
+	
 			string command = conv.command;
 			command = subst(command, token_from, quoteName(infile2));
 			command = subst(command, token_base, quoteName(from_base));
 			command = subst(command, token_to, quoteName(outfile2));
-			command = libScriptSearch(command);
-
+			command = libScriptSearch	(command);
+	
 			if (!conv.parselog.empty())
 				command += " 2> " + quoteName(infile2 + ".out");
-
+	
 			if (conv.from == "dvi" && conv.to == "ps")
 				command = add_options(command,
-						      buffer->params().dvips_options());
+									buffer->params().dvips_options());
 			else if (conv.from == "dvi" && prefixIs(conv.to, "pdf"))
 				command = add_options(command,
-						      dvipdfm_options(buffer->params()));
-
+									dvipdfm_options(buffer->params()));
+	
 			LYXERR(Debug::FILES) << "Calling " << command << endl;
 			if (buffer)
 				buffer->message(_("Executing command: ")
 				+ from_utf8(command));
-
+	
 			Systemcall::Starttype const type = (dummy)
 				? Systemcall::DontWait : Systemcall::Wait;
 			Systemcall one;
+	
 			int res;
-			if (conv.original_dir) {
-				FileName path(buffer->filePath());
+			if (conv.use_temp_dir) {
+				FileName path(temp_dir);
+				//create the temporary directory if necessary
+				if (!isDirWriteable(path) && !createDirectory(path, 0777)) {
+					Alert::error(_("Directory error"),
+					_("Unable to create temporary directory."));
+					return false;
+				}
+				//switch into it and run the command
 				support::Path p(path);
 				res = one.startscript(type,
 					to_filesystem8bit(from_utf8(command)));
 			} else
 				res = one.startscript(type,
 					to_filesystem8bit(from_utf8(command)));
-
-			if (!real_outfile.empty()) {
+	
+			if (needTempFile) {
+				// move temporary file to requested location
 				Mover const & mover = getMover(conv.to);
 				if (!mover.rename(outfile, real_outfile))
 					res = -1;
@@ -449,11 +521,14 @@
 						<< "renaming file " << outfile
 						<< " to " << real_outfile
 						<< endl;
-				// Finally, don't forget to tell any future
-				// converters to use the renamed file...
+				// make sure the next converter knows what file to use
 				outfile = real_outfile;
+			} else {
+				//check if the output file exists
+				if(!isFileReadable(outfile))
+					res = -1;
 			}
-
+	
 			if (!conv.parselog.empty()) {
 				string const logfile =  infile2 + ".log";
 				string const script = libScriptSearch(conv.parselog);
@@ -465,14 +540,14 @@
 				if (!scanLog(*buffer, command, makeAbsPath(logfile, path), errorList))
 					return false;
 			}
-
+	
 			if (res) {
 				if (conv.to == "program") {
 					Alert::error(_("Build errors"),
 						_("There were errors during the build process."));
 				} else {
-// FIXME: this should go out of here. For example, here we cannot say if
-// it is a document (.lyx) or something else. Same goes for elsewhere.
+	// FIXME: this should go out of here. For example, here we cannot say if
+	// it is a document (.lyx) or something else. Same goes for elsewhere.
 					Alert::error(_("Cannot convert file"),
 						bformat(_("An error occurred whilst running %1$s"),
 						from_utf8(command.substr(0, 50))));
@@ -480,21 +555,22 @@
 				return false;
 			}
 		}
+		//this converter is now complete
 	}
+	// all the converters have now been run
 
-	Converter const & conv = converterlist_[edgepath.back()];
-	if (conv.To->dummy())
+	if (lastConv.To->dummy())
 		return true;
 
-	if (!conv.result_dir.empty()) {
+	if (!lastConv.result_dir.empty()) {
 		// The converter has put the file(s) in a directory.
 		// In this case we ignore the given to_file.
 		if (from_base != to_base) {
-			string const from = subst(conv.result_dir,
+			string const from = subst(lastConv.result_dir,
 					    token_base, from_base);
-			string const to = subst(conv.result_dir,
+			string const to = subst(lastConv.result_dir,
 					  token_base, to_base);
-			Mover const & mover = getMover(conv.from);
+			Mover const & mover = getMover(lastConv.from);
 			if (!mover.rename(FileName(from), FileName(to))) {
 				Alert::error(_("Cannot convert file"),
 					bformat(_("Could not move a temporary directory from %1$s to %2$s."),
@@ -503,11 +579,19 @@
 			}
 		}
 		return true;
-	} else {
-		if (conversionflags & try_cache)
-			ConverterCache::get().add(orig_from, to_format, outfile);
-		return move(conv.to, outfile, to_file, conv.latex);
 	}
+	// else...
+	// if the last converter created its own temporary directory, then
+	// the files can stay there.
+	if (lastConv.use_temp_dir) {
+		to_file = outfile;
+		used_temp_dir = true;
+		return true;
+	} // note that we skip the cache in this case
+	// else...
+	if (conversionflags & try_cache)
+		ConverterCache::get().add(orig_from, to_format, outfile);
+	return move(lastConv.to, outfile, to_file, lastConv.latex);
 }
 
 
Index: src/Exporter.cpp
===================================================================
--- src/Exporter.cpp	(revision 18444)
+++ src/Exporter.cpp	(working copy)
@@ -91,6 +91,21 @@
 }
 
 
+/// ask for permission to over-write files in an export directory
+int checkDirOverwrite(FileName const & filename)
+{
+	if (fs::exists(filename.toFilesystemEncoding())) {
+		docstring text = bformat(_("The export directory %1$s already exists.\n\n"
+						     "Do you want to over-write files in it?"),
+				      makeDisplayPath(filename.absFilename()));
+		return Alert::prompt(_("Over-write?"),
+				     text, 0, 1,
+				     _("&Over-write"), _("&Cancel export"));
+	}
+	return 0;
+}
+
+
 enum CopyStatus {
 	SUCCESS,
 	FORCE,
@@ -203,7 +218,8 @@
 	} else if (!lyxrc.tex_allows_spaces
 		   && contains(buffer->filePath(), ' ')) {
 		Alert::error(_("File name error"),
-			   _("The directory path to the document cannot contain spaces."));
+			   _("The directory path to the document cannot contain spaces, "
+		       "since your LaTeX installation does not allow them."));
 		return false;
 	} else {
 		runparams.nice = false;
@@ -213,19 +229,57 @@
 
 	string const error_type = (format == "program")? "Build" : bufferFormat(*buffer);
 	string const ext = formats.extension(format);
-	FileName const tmp_result_file(changeExtension(filename, ext));
+	bool used_temp_dir = false;
+	FileName tmp_result_file(changeExtension(filename, ext));
 	bool const success = theConverters().convert(buffer, FileName(filename),
-		tmp_result_file, FileName(buffer->fileName()), backend_format, format,
-		buffer->errorList(error_type));
+		tmp_result_file, FileName(buffer->fileName()), used_temp_dir, backend_format, 
+		format, buffer->errorList(error_type));
 	// Emit the signal to show the error list.
 	if (format != backend_format)
 		buffer->errors(error_type);
 	if (!success)
 		return false;
 
-	if (put_in_tempdir)
+	if (put_in_tempdir) {
 		result_file = tmp_result_file.absFilename();
-	else {
+	} else if (used_temp_dir) {
+		FileName const temp_dir = 
+			FileName(onlyPath(tmp_result_file.toFilesystemEncoding()));
+		string const new_dir = 
+			addName(onlyPath(buffer->fileName()), 
+			        changeExtension(buffer->getLatexName(true), "") + 
+			        "." + format + ".conversion");
+		FileName newDir = FileName(new_dir);
+		//FIXME Should be put in a copyDirectory() routine.
+		//FIXME
+		if (isDirWriteable(newDir) && checkDirOverwrite(newDir)) {
+			buffer->message(_("Document export cancelled."));
+			return false;
+		}
+		if (!isDirWriteable(newDir) && !createDirectory(newDir, 0777)) {
+			Alert::error(_("Directory error"),
+		   _("Unable to create destination directory."
+				"Output files are in LyX temporary directory."));
+			return false;
+		}
+		vector<FileName> const files = dirList(temp_dir);
+		for (vector<FileName>::const_iterator it = files.begin();
+				it != files.end(); ++it) 
+			{
+				string const fromFile = it->absFilename();
+				string const toFile = addName(new_dir, onlyFilename(fromFile));
+				try {
+					if (fs::exists(toFile))
+						fs::remove(toFile);
+					fs::copy_file(fromFile, toFile);
+				} catch (fs::filesystem_error & e) {
+					Alert::error(_("File copy error"),
+					_("Unable to copy files. "
+						"Output files are in LyX temporary directory."));
+					return false;
+				}
+			}
+	} else {
 		result_file = changeExtension(buffer->fileName(), ext);
 		// We need to copy referenced files (e. g. included graphics
 		// if format == "dvi") to the result dir.
Index: src/insets/InsetGraphics.cpp
===================================================================
--- src/insets/InsetGraphics.cpp	(revision 18444)
+++ src/insets/InsetGraphics.cpp	(working copy)
@@ -724,6 +724,8 @@
 
 	// FIXME (Abdel 12/08/06): Is there a need to show these errors?
 	ErrorList el;
+	
+	//FIXME Converter::convert call
 	if (theConverters().convert(&buf, temp_file, to_file, params().filename,
 	                       from, to, el,
 	                       Converters::try_default | Converters::try_cache)) {
Index: src/insets/ExternalSupport.cpp
===================================================================
--- src/insets/ExternalSupport.cpp	(revision 18444)
+++ src/insets/ExternalSupport.cpp	(working copy)
@@ -270,6 +270,9 @@
 	}
 
 	// the generated file (always in the temp dir)
+	//FIXME This needs to be changed, since the foregoing is no longer true
+	//if the usetempdir flag is set. But if we're going to have the converter
+	//always set the to_file name, then this doesn't even need doing....
 	string const to_file = doSubstitution(params, buffer,
 					      outputFormat.updateResult,
 					      false, true);
@@ -315,6 +318,7 @@
 
 	// FIXME (Abdel 12/08/06): Is there a need to show these errors?
 	ErrorList el;
+	//FIXME Converter::convert call
 	bool const success =
 		theConverters().convert(&buffer, temp_file, abs_to_file,
 		                   params.filename, from_format, to_format, el,

Reply via email to