Add a cache for converted image files. This needs to be enabled in the

preferences file with \use_converter_cache true. It is disabled by default,
and no GUI support for changing the preferences is yet implemented.

	* src/insets/insetgraphics.C
	(InsetGraphics::prepareFile): Use image file cache

	* src/insets/ExternalSupport.C
	(updateExternal): Use image file cache

	* src/exporter.C
	(Exporter::Export): Do not use image file cache

	* src/graphics/GraphicsCacheItem.C

	(CacheItem::Impl::imageConverted): Add the converted file to the
	image file cache
	(CacheItem::Impl::convertToDisplayFo): Use image file cache

	* src/converter.C
	(Converters::convert): Use image file cache if the caller allowed that

	* src/converter.h
	(Converters::convert): Adjust arguments

	* src/Makefile.am: Add new files

	* src/support/lyxlib.h
	(chmod): new function
	(copy): add mode argument

	* src/support/copy.C
	(chmod): new function
	(copy): implement mode argument

	* src/support/mkdir.C
	(lyx::support::mkdir): Add warning if permissions are ignored

	* src/lyxrc.[Ch]: Add new settings \converter_cache_maxage and
	\use_converter_cache

	* src/ConverterCache.[Ch]: New image file cache

	* src/importer.C
	(Importer::Import): Do nut use the image file cache

	* src/lyx_main.C
	(LyX::init): Initialize the image file cache

	* src/mover.[Ch]
	(Mover::do_copy): Add mode argument
	(SpecialisedMover::do_copy): ditto

	* configure.ac: Check for chmod

	* development/cmake/ConfigureChecks.cmake: ditto

	* development/cmake/config.h.cmake: ditto

	* development/scons/SConstruct: ditto

	* development/scons/scons_manifest.py: Add new files


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@15897 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Georg Baum 2006-11-13 10:27:57 +00:00
parent 6ff8d78118
commit 5ed606f9c5
23 changed files with 643 additions and 63 deletions

View File

@ -260,7 +260,7 @@ dnl work correctly because of some conflict with stdlib.h with g++ 2.96
dnl We aim to remove this eventually, since we should test as much as
dnl possible with the compiler which will use the functions (JMarc)
AC_LANG_PUSH(C)
AC_CHECK_FUNCS(close _close getpid _getpid lstat mkfifo mkstemp mktemp open _open pclose _pclose popen _popen readlink)
AC_CHECK_FUNCS(chmod close _close getpid _getpid lstat mkfifo mkstemp mktemp open _open pclose _pclose popen _popen readlink)
AC_LANG_POP(C)
LYX_CHECK_SPELL_ENGINES

View File

@ -41,6 +41,7 @@ check_include_files(argz.h HAVE_ARGZ_H)
check_function_exists(open HAVE_OPEN)
check_function_exists(chmod HAVE_CHMOD)
check_function_exists(close HAVE_CLOSE)
check_function_exists(popen HAVE_POPEN)
check_function_exists(pclose HAVE_PCLOSE)

View File

@ -33,6 +33,7 @@
#cmakedefine HAVE_IOS 1
#cmakedefine HAVE_LOCALE 1
#cmakedefine HAVE_OPEN 1
#cmakedefine HAVE_CHMOD 1
#cmakedefine HAVE_CLOSE 1
#cmakedefine HAVE_POPEN 1
#cmakedefine HAVE_PCLOSE 1

View File

@ -986,6 +986,7 @@ result = utils.createConfigFile(conf,
],
functions = [
('open', 'HAVE_OPEN', None),
('chmod', 'HAVE_CHMOD', None),
('close', 'HAVE_CLOSE', None),
('popen', 'HAVE_POPEN', None),
('pclose', 'HAVE_PCLOSE', None),

View File

@ -1034,6 +1034,7 @@ src_header_files = Split('''
Bullet.h
Chktex.h
Color.h
ConverterCache.h
CutAndPaste.h
DepTable.h
FloatList.h
@ -1155,6 +1156,7 @@ src_pre_files = Split('''
Bullet.C
Chktex.C
Color.C
ConverterCache.C
CutAndPaste.C
DepTable.C
FloatList.C

349
src/ConverterCache.C Normal file
View File

@ -0,0 +1,349 @@
/**
* \file ConverterCache.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Baruch Even
* \author Angus Leeming
* \author Georg Baum
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "ConverterCache.h"
#include "debug.h"
#include "lyxrc.h"
#include "mover.h"
#include "support/filetools.h"
#include "support/lyxlib.h"
#include "support/lyxtime.h"
#include "support/package.h"
#include <boost/crc.hpp>
#include <boost/filesystem/operations.hpp>
#include <fstream>
#include <iomanip>
#include <map>
#include <sstream>
using lyx::support::absolutePath;
using lyx::support::addName;
using std::string;
namespace fs = boost::filesystem;
namespace lyx {
namespace {
unsigned long do_crc(string const & s)
{
boost::crc_32_type crc;
crc = std::for_each(s.begin(), s.end(), crc);
return crc.checksum();
}
static string cache_dir;
class CacheItem {
public:
CacheItem() {}
CacheItem(string const & orig_from, string const & to_format,
time_t t, unsigned long c)
: timestamp(t), checksum(c)
{
BOOST_ASSERT(absolutePath(orig_from));
std::ostringstream os;
os << std::setw(10) << std::setfill('0') << do_crc(orig_from)
<< '-' << to_format;
cache_name = addName(cache_dir, os.str());
lyxerr[Debug::FILES] << "Add file cache item " << orig_from
<< ' ' << to_format << ' ' << cache_name
<< ' ' << timestamp << ' ' << checksum
<< '.' << std::endl;
}
~CacheItem() {}
string cache_name;
time_t timestamp;
unsigned long checksum;
};
}
/** The cache contains one item per orig file and target format, so use a
* nested map to find the cache item quickly by filename and format.
*/
typedef std::map<string, CacheItem> FormatCacheType;
typedef std::map<string, FormatCacheType> CacheType;
class ConverterCache::Impl {
public:
///
void readIndex();
///
void writeIndex();
///
CacheItem * find(string const & from, string const & format);
CacheType cache;
};
void ConverterCache::Impl::readIndex()
{
time_t const now = current_time();
string const index = addName(cache_dir, "index");
std::ifstream is(index.c_str());
while (is.good()) {
string orig_from;
string to_format;
time_t timestamp;
unsigned long checksum;
if (!(is >> orig_from >> to_format >> timestamp >> checksum))
return;
CacheItem item(orig_from, to_format, timestamp, checksum);
// Don't cache files that do not exist anymore
if (!fs::exists(orig_from)) {
lyxerr[Debug::FILES] << "Not caching file `"
<< orig_from << "' (does not exist anymore)."
<< std::endl;
support::unlink(item.cache_name);
continue;
}
// Delete the cached file if it is too old
if (difftime(now, fs::last_write_time(item.cache_name)) >
lyxrc.converter_cache_maxage) {
lyxerr[Debug::FILES] << "Not caching file `"
<< orig_from << "' (too old)." << std::endl;
support::unlink(item.cache_name);
continue;
}
cache[orig_from][to_format] = item;
}
is.close();
}
void ConverterCache::Impl::writeIndex()
{
string const index = addName(cache_dir, "index");
std::ofstream os(index.c_str());
os.close();
if (!lyx::support::chmod(index.c_str(), 0600))
return;
os.open(index.c_str());
CacheType::iterator it1 = cache.begin();
CacheType::iterator const end1 = cache.end();
for (; it1 != end1; ++it1) {
FormatCacheType::iterator it2 = it1->second.begin();
FormatCacheType::iterator const end2 = it1->second.end();
for (; it2 != end2; ++it2)
os << it1->first << ' ' << it2->first << ' '
<< it2->second.timestamp << ' '
<< it2->second.checksum << '\n';
}
os.close();
}
CacheItem * ConverterCache::Impl::find(string const & from,
string const & format)
{
if (!lyxrc.use_converter_cache)
return 0;
CacheType::iterator const it1 = cache.find(from);
if (it1 == cache.end())
return 0;
FormatCacheType::iterator const it2 = it1->second.find(format);
if (it2 == it1->second.end())
return 0;
return &(it2->second);
}
ConverterCache & ConverterCache::get()
{
// Now return the cache
static ConverterCache singleton;
return singleton;
}
void ConverterCache::init()
{
if (!lyxrc.use_converter_cache)
return;
// We do this here and not in the constructor because package() gets
// initialized after all static variables.
cache_dir = addName(support::package().user_support(), "cache");
if (!fs::exists(cache_dir))
if (support::mkdir(cache_dir, 0700) != 0) {
lyxerr << "Could not create cache directory `"
<< cache_dir << "'." << std::endl;
exit(EXIT_FAILURE);
}
get().pimpl_->readIndex();
}
ConverterCache::ConverterCache()
: pimpl_(new Impl)
{}
ConverterCache::~ConverterCache()
{
if (!lyxrc.use_converter_cache)
return;
pimpl_->writeIndex();
}
void ConverterCache::add(string const & orig_from, string const & to_format,
string const & converted_file) const
{
if (!lyxrc.use_converter_cache)
return;
lyxerr[Debug::FILES] << BOOST_CURRENT_FUNCTION << ' ' << orig_from
<< ' ' << to_format << ' ' << converted_file
<< std::endl;
BOOST_ASSERT(absolutePath(orig_from));
BOOST_ASSERT(absolutePath(converted_file));
// Is the file in the cache already?
CacheItem * item = pimpl_->find(orig_from, to_format);
time_t const timestamp = fs::last_write_time(orig_from);
Mover const & mover = movers(to_format);
if (item) {
lyxerr[Debug::FILES] << "ConverterCache::add(" << orig_from << "):\n"
"The file is already in the cache."
<< std::endl;
// First test for timestamp
if (timestamp == item->timestamp) {
lyxerr[Debug::FILES] << "Same timestamp."
<< std::endl;
return;
} else {
// Maybe the contents is still the same?
item->timestamp = timestamp;
unsigned long const checksum = support::sum(orig_from);
if (checksum == item->checksum) {
lyxerr[Debug::FILES] << "Same checksum."
<< std::endl;
return;
}
item->checksum = checksum;
}
if (!mover.copy(converted_file, item->cache_name, 0600))
lyxerr[Debug::FILES] << "ConverterCache::add("
<< orig_from << "):\n"
"Could not copy file."
<< std::endl;
} else {
CacheItem new_item = CacheItem(orig_from, to_format, timestamp,
support::sum(orig_from));
if (mover.copy(converted_file, new_item.cache_name, 0600))
pimpl_->cache[orig_from][to_format] = new_item;
else
lyxerr[Debug::FILES] << "ConverterCache::add("
<< orig_from << "):\n"
"Could not copy file."
<< std::endl;
}
}
void ConverterCache::remove(string const & orig_from,
string const & to_format) const
{
if (!lyxrc.use_converter_cache)
return;
lyxerr[Debug::FILES] << BOOST_CURRENT_FUNCTION << ' ' << orig_from
<< ' ' << to_format << std::endl;
BOOST_ASSERT(absolutePath(orig_from));
CacheType::iterator const it1 = pimpl_->cache.find(orig_from);
if (it1 == pimpl_->cache.end())
return;
FormatCacheType::iterator const it2 = it1->second.find(to_format);
if (it2 == it1->second.end())
return;
it1->second.erase(it2);
if (it1->second.empty())
pimpl_->cache.erase(it1);
}
bool ConverterCache::inCache(string const & orig_from,
string const & to_format) const
{
if (!lyxrc.use_converter_cache)
return false;
lyxerr[Debug::FILES] << BOOST_CURRENT_FUNCTION << ' ' << orig_from
<< ' ' << to_format << std::endl;
BOOST_ASSERT(absolutePath(orig_from));
CacheItem * const item = pimpl_->find(orig_from, to_format);
if (!item) {
lyxerr[Debug::FILES] << "not in cache." << std::endl;
return false;
}
time_t const timestamp = fs::last_write_time(orig_from);
if (item->timestamp == timestamp) {
lyxerr[Debug::FILES] << "identical timestamp." << std::endl;
return true;
}
if (item->checksum == support::sum(orig_from)) {
item->timestamp = timestamp;
lyxerr[Debug::FILES] << "identical checksum." << std::endl;
return true;
}
lyxerr[Debug::FILES] << "in cache, but too old." << std::endl;
return false;
}
string const ConverterCache::cacheName(string const & orig_from,
string const & to_format) const
{
lyxerr[Debug::FILES] << BOOST_CURRENT_FUNCTION << ' ' << orig_from
<< ' ' << to_format << std::endl;
BOOST_ASSERT(absolutePath(orig_from));
CacheItem * const item = pimpl_->find(orig_from, to_format);
BOOST_ASSERT(item);
return item->cache_name;
}
bool ConverterCache::copy(string const & orig_from, string const & to_format,
string const & dest) const
{
if (!lyxrc.use_converter_cache)
return false;
lyxerr[Debug::FILES] << BOOST_CURRENT_FUNCTION << ' ' << orig_from
<< ' ' << to_format << ' ' << dest << std::endl;
BOOST_ASSERT(absolutePath(orig_from));
BOOST_ASSERT(absolutePath(dest));
CacheItem * const item = pimpl_->find(orig_from, to_format);
BOOST_ASSERT(item);
Mover const & mover = movers(to_format);
return mover.copy(item->cache_name, dest);
}
} // namespace lyx

101
src/ConverterCache.h Normal file
View File

@ -0,0 +1,101 @@
// -*- C++ -*-
/**
* \file ConverterCache.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Baruch Even
* \author Angus Leeming
* \author Georg Baum
*
* Full author contact details are available in file CREDITS.
*
* lyx::ConverterCache is the manager of the file cache.
* It is responsible for creating the lyx::ConverterCacheItem's
* and maintaining them.
*
* lyx::ConverterCache is a singleton class. It is possible to have
* only one instance of it at any moment.
*/
#ifndef CONVERTERCACHE_H
#define CONVERTERCACHE_H
#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
#include <string>
namespace lyx {
/**
* Cache for converted files. The cache works as follows:
*
* The key for a cache item consists of the absolute name of the original
* file and the format name of the target format. The original file in the
* user directory is named \c orig_from in the code, the format name is named
* \c to_format. Example:
* \c orig_from = "/home/me/myfigure.fig"
* \c to_format = "eps"
* A cache item is considered up to date (inCache() returns \c true) if
* - The cache contains an item with key (\c orig_to, \c to_format)
* - The stored timestamp of the item is identical with the actual timestamp
* of \c orig_from, or, if that is not the case, the stored checksum is
* identical with the actual checksum of \c orig_from.
* Otherwise the item is not considered up to date, and add() will refresh it.
*
* There is no cache maintenance yet (max size, max age etc.)
*/
class ConverterCache : boost::noncopyable {
public:
/// This is a singleton class. Get the instance.
static ConverterCache & get();
/// Init the cache. This must be done after package initialization.
static void init();
/**
* Add \c converted_file (\c orig_from converted to \c to_format) to
* the cache if it is not already in or not up to date.
*/
void add(std::string const & orig_from, std::string const & to_format,
std::string const & converted_file) const;
/// Remove a file from the cache.
void remove(std::string const & orig_from,
std::string const & to_format) const;
/**
* Returns \c true if \c orig_from converted to \c to_format is in
* the cache and up to date.
*/
bool inCache(std::string const & orig_from,
std::string const & to_format) const;
/// Get the name of the cached file
std::string const cacheName(std::string const & orig_from,
std::string const & to_format) const;
/// Copy the file from the cache to \p dest
bool copy(std::string const & orig_from, std::string const & to_format,
std::string const & dest) const;
private:
/** Make the c-tor, d-tor private so we can control how many objects
* are instantiated.
*/
ConverterCache();
///
~ConverterCache();
/// Use the Pimpl idiom to hide the internals.
class Impl;
/// The pointer never changes although *pimpl_'s contents may.
boost::scoped_ptr<Impl> const pimpl_;
};
} // namespace lyx
#endif

View File

@ -72,6 +72,8 @@ lyx_SOURCES = \
Chktex.h \
Color.C \
Color.h \
ConverterCache.C \
ConverterCache.h \
CutAndPaste.C \
CutAndPaste.h \
DepTable.C \

View File

@ -12,6 +12,7 @@
#include "converter.h"
#include "ConverterCache.h"
#include "buffer.h"
#include "buffer_funcs.h"
#include "bufferparams.h"
@ -33,6 +34,7 @@
namespace lyx {
using support::absolutePath;
using support::addName;
using support::bformat;
using support::changeExtension;
@ -285,24 +287,31 @@ OutputParams::FLAVOR Converters::getFlavor(Graph::EdgePath const & path)
bool Converters::convert(Buffer const * buffer,
string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format,
string & to_file, ErrorList & errorList, bool try_default)
string const & from_file, string const & to_file,
string const & orig_from,
string const & from_format, string const & to_format,
ErrorList & errorList, int conversionflags)
{
string const to_ext = formats.extension(to_format);
to_file = changeExtension(to_file_base, to_ext);
BOOST_ASSERT(absolutePath(from_file));
BOOST_ASSERT(absolutePath(to_file));
BOOST_ASSERT(absolutePath(orig_from));
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);
Graph::EdgePath edgepath = getPath(from_format, to_format);
if (edgepath.empty()) {
if (try_default) {
if (conversionflags & try_default) {
// if no special converter defined, then we take the
// default one from ImageMagic.
string const from_ext = from_format.empty() ?
getExtension(from_file) :
formats.extension(from_format);
string const to_ext = formats.extension(to_format);
string const command =
support::os::python() + ' ' +
quoteName(libFileSearch("scripts", "convertDefault.py")) +
@ -317,6 +326,9 @@ bool Converters::convert(Buffer const * buffer,
Systemcall one;
one.startscript(Systemcall::Wait, command);
if (isFileReadable(to_file)) {
if (conversionflags & try_cache)
ConverterCache::get().add(orig_from,
to_format, to_file);
return true;
}
}
@ -466,9 +478,8 @@ bool Converters::convert(Buffer const * buffer,
return true;
if (!conv.result_dir.empty()) {
to_file = addName(subst(conv.result_dir, token_base, to_base),
subst(conv.result_file,
token_base, onlyFilename(to_base)));
// 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,
token_base, from_base);
@ -477,14 +488,17 @@ bool Converters::convert(Buffer const * buffer,
Mover const & mover = movers(conv.from);
if (!mover.rename(from, to)) {
Alert::error(_("Cannot convert file"),
bformat(_("Could not move a temporary file from %1$s to %2$s."),
bformat(_("Could not move a temporary directory from %1$s to %2$s."),
from_ascii(from), from_ascii(to)));
return false;
}
}
return true;
} else
} else {
if (conversionflags & try_cache)
ConverterCache::get().add(orig_from, to_format, outfile);
return move(conv.to, outfile, to_file, conv.latex);
}
}
@ -527,17 +541,6 @@ bool Converters::move(string const & fmt,
}
bool Converters::convert(Buffer const * buffer,
string const & from_file, string const & to_file_base,
string const & from_format, string const & to_format,
ErrorList & errorList, bool try_default)
{
string to_file;
return convert(buffer, from_file, to_file_base, from_format, to_format,
to_file, errorList, try_default);
}
bool Converters::formatIsUsed(string const & format)
{
ConverterList::const_iterator cit = converterlist_.begin();

View File

@ -107,17 +107,21 @@ public:
Graph::EdgePath const getPath(std::string const & from, std::string const & to);
///
OutputParams::FLAVOR getFlavor(Graph::EdgePath const & path);
/// Flags for converting files
enum ConversionFlags {
/// No special flags
none = 0,
/// Use the default converter if no converter is defined
try_default = 1 << 0,
/// Get the converted file from cache if possible
try_cache = 1 << 1
};
///
bool convert(Buffer const * buffer,
std::string const & from_file, std::string const & to_file_base,
std::string const & from_format, std::string const & to_format,
std::string & to_file, ErrorList & errorList,
bool try_default = false);
///
bool convert(Buffer const * buffer,
std::string const & from_file, std::string const & to_file_base,
std::string const & from_format, std::string const & to_format,
ErrorList & errorList, bool try_default = false);
std::string const & from_file, std::string const & to_file,
std::string const & orig_from,
std::string const & from_format, std::string const & to_format,
ErrorList & errorList, int conversionflags = none);
///
void update(Formats const & formats);
///

View File

@ -217,18 +217,20 @@ bool Exporter::Export(Buffer * buffer, string const & format,
}
string const error_type = (format == "program")? "Build" : bufferFormat(*buffer);
bool const success = converters.convert(buffer, filename, filename,
backend_format, format, result_file,
string const ext = formats.extension(format);
string const tmp_result_file = changeExtension(filename, ext);
bool const success = converters.convert(buffer, filename,
tmp_result_file, buffer->fileName(), backend_format, format,
buffer->errorList(error_type));
// Emit the signal to show the error list.
buffer->errors(error_type);
if (!success)
return false;
if (!put_in_tempdir) {
string const tmp_result_file = result_file;
result_file = changeExtension(buffer->fileName(),
formats.extension(format));
if (put_in_tempdir)
result_file = tmp_result_file;
else {
result_file = changeExtension(buffer->fileName(), ext);
// We need to copy referenced files (e. g. included graphics
// if format == "dvi") to the result dir.
vector<ExportedFile> const files =

View File

@ -16,6 +16,7 @@
#include "GraphicsConverter.h"
#include "GraphicsImage.h"
#include "ConverterCache.h"
#include "debug.h"
#include "format.h"
@ -28,7 +29,6 @@
namespace lyx {
using support::changeExtension;
using support::FileMonitor;
using support::isFileReadable;
using support::makeDisplayPath;
@ -108,6 +108,8 @@ public:
bool zipped_;
/// If so, store the uncompressed file in this temporary file.
string unzipped_filename_;
/// The target format
string to_;
/// What file are we trying to load?
string file_to_load_;
/** Should we delete the file after loading? True if the file is
@ -228,6 +230,7 @@ void CacheItem::Impl::reset()
unlink(file_to_load_);
remove_loaded_file_ = false;
file_to_load_.erase();
to_.erase();
if (image_.get())
image_.reset();
@ -278,6 +281,9 @@ void CacheItem::Impl::imageConverted(bool success)
return;
}
// Add the converted file to the file cache
ConverterCache::get().add(filename_, to_, file_to_load_);
loadImage();
}
@ -403,9 +409,9 @@ void CacheItem::Impl::convertToDisplayFormat()
}
lyxerr[Debug::GRAPHICS]
<< "\n\tThe file contains " << from << " format data." << endl;
string const to = findTargetFormat(from);
to_ = findTargetFormat(from);
if (from == to) {
if (from == to_) {
// No conversion needed!
lyxerr[Debug::GRAPHICS] << "\tNo conversion needed (from == to)!" << endl;
file_to_load_ = filename;
@ -413,7 +419,15 @@ void CacheItem::Impl::convertToDisplayFormat()
return;
}
lyxerr[Debug::GRAPHICS] << "\tConverting it to " << to << " format." << endl;
if (ConverterCache::get().inCache(filename, to_)) {
lyxerr[Debug::GRAPHICS] << "\tNo conversion needed (file in file cache)!"
<< endl;
file_to_load_ = ConverterCache::get().cacheName(filename, to_);
loadImage();
return;
}
lyxerr[Debug::GRAPHICS] << "\tConverting it to " << to_ << " format." << endl;
// Add some stuff to create a uniquely named temporary file.
// This file is deleted in loadImage after it is loaded into memory.
@ -427,7 +441,7 @@ void CacheItem::Impl::convertToDisplayFormat()
// Connect a signal to this->imageConverted and pass this signal to
// the graphics converter so that we can load the modified file
// on completion of the conversion process.
converter_.reset(new Converter(filename, to_file_base, from, to));
converter_.reset(new Converter(filename, to_file_base, from, to_));
converter_->connect(boost::bind(&Impl::imageConverted, this, _1));
converter_->startConversion();
}

View File

@ -53,8 +53,11 @@ bool Importer::Import(LyXView * lv, string const & filename,
for (vector<string>::const_iterator it = loaders.begin();
it != loaders.end(); ++it) {
if (converters.isReachable(format, *it)) {
if (!converters.convert(0, filename, filename,
format, *it, errorList))
string const tofile =
changeExtension(filename,
formats.extension(*it));
if (!converters.convert(0, filename, tofile,
filename, format, *it, errorList))
return false;
loader_format = *it;
break;

View File

@ -305,14 +305,13 @@ void updateExternal(InsetExternalParams const & params,
// Yes if to_file does not exist or if from_file is newer than to_file
if (support::compare_timestamps(temp_file, abs_to_file) < 0)
return; // SUCCESS
string const to_file_base =
support::changeExtension(to_file, string());
// FIXME (Abdel 12/08/06): Is there a need to show these errors?
ErrorList el;
/* bool const success = */
converters.convert(&buffer, temp_file, to_file_base,
from_format, to_format, el, true);
converters.convert(&buffer, temp_file, abs_to_file,
abs_from_file, from_format, to_format, el,
Converters::try_default | Converters::try_cache);
// return success
}

View File

@ -722,7 +722,9 @@ string const InsetGraphics::prepareFile(Buffer const & buf,
// FIXME (Abdel 12/08/06): Is there a need to show these errors?
ErrorList el;
if (converters.convert(&buf, temp_file, temp_file, from, to, el, true)) {
if (converters.convert(&buf, temp_file, to_file, orig_file,
from, to, el,
Converters::try_default | Converters::try_cache)) {
runparams.exportdata->addExternalFile(tex_format,
to_file, output_to_file);
runparams.exportdata->addExternalFile("dvi",

View File

@ -17,6 +17,7 @@
#include "lyx_main.h"
#include "ConverterCache.h"
#include "buffer.h"
#include "buffer_funcs.h"
#include "bufferlist.h"
@ -796,6 +797,11 @@ bool LyX::init()
lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
// This must happen after package initialization and after lyxrc is
// read, therefore it can't be done by a static object.
ConverterCache::init();
return true;
}

View File

@ -79,6 +79,7 @@ keyword_item lyxrcTags[] = {
{ "\\check_lastfiles", LyXRC::RC_CHECKLASTFILES },
{ "\\chktex_command", LyXRC::RC_CHKTEX_COMMAND },
{ "\\converter", LyXRC::RC_CONVERTER },
{ "\\converter_cache_maxage", LyXRC::RC_CONVERTER_CACHE_MAXAGE },
{ "\\copier", LyXRC::RC_COPIER },
{ "\\cursor_follows_scrollbar", LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR },
{ "\\custom_export_command", LyXRC::RC_CUSTOM_EXPORT_COMMAND },
@ -167,6 +168,7 @@ keyword_item lyxrcTags[] = {
{ "\\tex_expects_windows_paths", LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS },
{ "\\ui_file", LyXRC::RC_UIFILE },
{ "\\use_alt_language", LyXRC::RC_USE_ALT_LANG },
{ "\\use_converter_cache", LyXRC::RC_USE_CONVERTER_CACHE },
{ "\\use_escape_chars", LyXRC::RC_USE_ESC_CHARS },
{ "\\use_input_encoding", LyXRC::RC_USE_INP_ENC },
{ "\\use_lastfilepos", LyXRC::RC_USELASTFILEPOS },
@ -289,6 +291,8 @@ void LyXRC::setDefaults() {
preview = PREVIEW_OFF;
preview_hashed_labels = false;
preview_scale_factor = "0.9";
use_converter_cache = false;
converter_cache_maxage = 6 * 30 * 24 * 3600; // 6 months
user_name = support::user_name();
@ -1187,6 +1191,17 @@ int LyXRC::read(LyXLex & lexrc)
path_prefix = lexrc.getString();
break;
case RC_USE_CONVERTER_CACHE:
if (lexrc.next())
use_converter_cache = lexrc.getBool();
break;
case RC_CONVERTER_CACHE_MAXAGE:
if (lexrc.next())
converter_cache_maxage =
convert<unsigned int>(lexrc.getString());
break;
case RC_LAST: break; // this is just a dummy
}
}
@ -1463,6 +1478,20 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc) const
<< preview_scale_factor << '\n';
}
case RC_USE_CONVERTER_CACHE:
if (ignore_system_lyxrc ||
use_converter_cache != system_lyxrc.use_converter_cache) {
os << "\\use_converter_cache "
<< convert<string>(use_converter_cache) << '\n';
}
case RC_CONVERTER_CACHE_MAXAGE:
if (ignore_system_lyxrc ||
converter_cache_maxage != system_lyxrc.converter_cache_maxage) {
os << "\\converter_cache_maxage"
<< converter_cache_maxage << '\n';
}
os << "\n#\n"
<< "# SCREEN & FONTS SECTION ############################\n"
<< "#\n\n";

View File

@ -50,6 +50,7 @@ public:
RC_CHECKLASTFILES,
RC_CHKTEX_COMMAND,
RC_CONVERTER,
RC_CONVERTER_CACHE_MAXAGE,
RC_COPIER,
RC_CURSOR_FOLLOWS_SCROLLBAR,
RC_CUSTOM_EXPORT_COMMAND,
@ -136,6 +137,7 @@ public:
RC_USER_NAME,
RC_USETEMPDIR,
RC_USE_ALT_LANG,
RC_USE_CONVERTER_CACHE,
RC_USE_ESC_CHARS,
RC_USE_INP_ENC,
RC_USE_PERS_DICT,
@ -396,6 +398,10 @@ public:
* The string is input, stored and output in native format.
*/
std::string path_prefix;
/// Use the cache for file converters?
bool use_converter_cache;
/// The maximum age of cache files in seconds
unsigned int converter_cache_maxage;
};

View File

@ -17,11 +17,13 @@
#include "support/lyxlib.h"
#include "support/systemcall.h"
#include <fstream>
#include <sstream>
namespace lyx {
using std::ios;
using std::string;
Movers movers;
@ -29,9 +31,9 @@ Movers system_movers;
bool Mover::do_copy(string const & from, string const & to,
string const &) const
string const &, unsigned long int mode) const
{
return support::copy(from, to);
return support::copy(from, to, mode);
}
@ -43,10 +45,19 @@ bool Mover::do_rename(string const & from, string const & to,
bool SpecialisedMover::do_copy(string const & from, string const & to,
string const & latex) const
string const & latex, unsigned long int mode) const
{
if (command_.empty())
return Mover::do_copy(from, to, latex);
return Mover::do_copy(from, to, latex, mode);
if (mode != (unsigned long int)-1) {
std::ofstream ofs(to.c_str(), ios::binary | ios::out | ios::trunc);
if (!ofs)
return false;
ofs.close();
if (!support::chmod(to.c_str(), mode_t(mode)))
return false;
}
string command = support::libScriptSearch(command_);
command = support::subst(command, "$$i", from);
@ -64,7 +75,7 @@ bool SpecialisedMover::do_rename(string const & from, string const & to,
if (command_.empty())
return Mover::do_rename(from, to, latex);
if (!do_copy(from, to, latex))
if (!do_copy(from, to, latex, (unsigned long int)-1))
return false;
return support::unlink(from) == 0;
}

View File

@ -34,9 +34,10 @@ public:
* \returns true if successful.
*/
bool
copy(std::string const & from, std::string const & to) const
copy(std::string const & from, std::string const & to,
unsigned long int mode = (unsigned long int)-1) const
{
return do_copy(from, to, to);
return do_copy(from, to, to, mode);
}
/** Copy file @c from to @c to.
@ -49,9 +50,10 @@ public:
*/
bool
copy(std::string const & from, std::string const & to,
std::string const & latex) const
std::string const & latex,
unsigned long int mode = (unsigned long int)-1) const
{
return do_copy(from, to, latex);
return do_copy(from, to, latex, mode);
}
/** Rename file @c from as @c to.
@ -84,7 +86,7 @@ public:
protected:
virtual bool
do_copy(std::string const & from, std::string const & to,
std::string const &) const;
std::string const &, unsigned long int mode) const;
virtual bool
do_rename(std::string const & from, std::string const & to,
@ -131,7 +133,7 @@ public:
private:
virtual bool
do_copy(std::string const & from, std::string const & to,
std::string const & latex) const;
std::string const & latex, unsigned long int mode) const;
virtual bool
do_rename(std::string const & from, std::string const & to,

View File

@ -14,6 +14,13 @@
#include "support/lyxlib.h"
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
namespace lyx {
@ -24,12 +31,35 @@ using std::ios;
using std::string;
bool lyx::support::copy(string const & from, string const & to)
bool lyx::support::chmod(string const & file, unsigned long int mode)
{
#ifdef HAVE_CHMOD
if (::chmod(file.c_str(), mode_t(mode)) != 0)
return false;
#else
# ifdef WITH_WARNINGS
# warning "File permissions are ignored on this system."
# endif
#endif
return true;
}
bool lyx::support::copy(string const & from, string const & to, unsigned long int mode)
{
ifstream ifs(from.c_str(), ios::binary | ios::in);
if (!ifs)
return false;
if (mode != (unsigned long int)-1) {
ofstream ofs(to.c_str(), ios::binary | ios::out | ios::trunc);
if (!ofs)
return false;
ofs.close();
if (!chmod(to, mode_t(mode)))
return false;
}
ofstream ofs(to.c_str(), ios::binary | ios::out | ios::trunc);
if (!ofs)
return false;

View File

@ -25,13 +25,16 @@ namespace support {
std::string const getcwd();
/// change to a directory, 0 is returned on success.
int chdir(std::string const & name);
/// Change file permissions
bool chmod(std::string const & file, unsigned long int mode);
/**
* rename a file, returns false if it fails.
* It can handle renames across partitions.
*/
bool rename(std::string const & from, std::string const & to);
/// copy a file, returns false it it fails
bool copy(std::string const & from, std::string const & to);
bool copy(std::string const & from, std::string const & to,
unsigned long int mode = (unsigned long int)-1);
/// generates a checksum of a file
unsigned long sum(std::string const & file);
/// FIXME: some point to this hmm ?

View File

@ -39,6 +39,9 @@ int lyx::support::mkdir(std::string const & pathname, unsigned long int mode)
# if MKDIR_TAKES_ONE_ARG
// MinGW32
return ::mkdir(pathname.c_str());
# ifdef WITH_WARNINGS
# warning "Permissions of created directories are ignored on this system."
# endif
# else
// POSIX
return ::mkdir(pathname.c_str(), mode_t(mode));
@ -46,8 +49,14 @@ int lyx::support::mkdir(std::string const & pathname, unsigned long int mode)
#elif defined(_WIN32)
// plain Windows 32
return CreateDirectory(pathname.c_str(), 0) != 0 ? 0 : -1;
# ifdef WITH_WARNINGS
# warning "Permissions of created directories are ignored on this system."
# endif
#elif HAVE__MKDIR
return ::_mkdir(pathname.c_str());
# ifdef WITH_WARNINGS
# warning "Permissions of created directories are ignored on this system."
# endif
#else
# error "Don't know how to create a directory on this system."
#endif