Fix problems that occurred when multiple threads were trying to read/convert files at the same time (ie: indexing and previewing threads in the GUI calling internfile()). Either get rid of or lock-protect all shared data, eliminate misc initialization possible conflicts by using static initializers. Hopefuly closes issue #51
This commit is contained in:
parent
01f24fa5fd
commit
55f124725f
@ -320,7 +320,12 @@ list<string> RclConfig::getTopdirs()
|
||||
// (only the locale).
|
||||
const string& RclConfig::getDefCharset(bool filename)
|
||||
{
|
||||
// This can't change once computed inside a process.
|
||||
// This can't change once computed inside a process. It would be
|
||||
// nicer to move this to a static class initializer to avoid
|
||||
// possible threading issues but this doesn't work (tried) as
|
||||
// things would not be ready. In practise we make sure that this
|
||||
// is called from the main thread at once, by calling
|
||||
// getDefCharset from recollinit
|
||||
static string localecharset;
|
||||
if (localecharset.empty()) {
|
||||
const char *cp;
|
||||
|
||||
@ -92,6 +92,10 @@ RclConfig *recollinit(RclInitFlags flags,
|
||||
// to utf8 for indexing.
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
// Make sure the locale charset is initialized (so that multiple
|
||||
// threads don't try to do it at once).
|
||||
config->getDefCharset();
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@ -60,49 +60,47 @@ static int charclasses[charclasses_size];
|
||||
static set<unsigned int> unicign;
|
||||
static set<unsigned int> visiblewhite;
|
||||
|
||||
// Set up character classes array and the additional unicode sets
|
||||
static void setcharclasses()
|
||||
{
|
||||
static int init = 0;
|
||||
if (init)
|
||||
return;
|
||||
unsigned int i;
|
||||
class CharClassInit {
|
||||
public:
|
||||
CharClassInit()
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// Set default value for all: SPACE
|
||||
for (i = 0 ; i < 256 ; i ++)
|
||||
charclasses[i] = SPACE;
|
||||
// Set default value for all: SPACE
|
||||
for (i = 0 ; i < 256 ; i ++)
|
||||
charclasses[i] = SPACE;
|
||||
|
||||
char digits[] = "0123456789";
|
||||
for (i = 0; i < strlen(digits); i++)
|
||||
charclasses[int(digits[i])] = DIGIT;
|
||||
char digits[] = "0123456789";
|
||||
for (i = 0; i < strlen(digits); i++)
|
||||
charclasses[int(digits[i])] = DIGIT;
|
||||
|
||||
char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
for (i = 0; i < strlen(upper); i++)
|
||||
charclasses[int(upper[i])] = A_ULETTER;
|
||||
char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
for (i = 0; i < strlen(upper); i++)
|
||||
charclasses[int(upper[i])] = A_ULETTER;
|
||||
|
||||
char lower[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
for (i = 0; i < strlen(lower); i++)
|
||||
charclasses[int(lower[i])] = A_LLETTER;
|
||||
char lower[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
for (i = 0; i < strlen(lower); i++)
|
||||
charclasses[int(lower[i])] = A_LLETTER;
|
||||
|
||||
char wild[] = "*?[]";
|
||||
for (i = 0; i < strlen(wild); i++)
|
||||
charclasses[int(wild[i])] = WILD;
|
||||
char wild[] = "*?[]";
|
||||
for (i = 0; i < strlen(wild); i++)
|
||||
charclasses[int(wild[i])] = WILD;
|
||||
|
||||
char special[] = ".@+-,#'_\n\r";
|
||||
for (i = 0; i < strlen(special); i++)
|
||||
charclasses[int(special[i])] = special[i];
|
||||
char special[] = ".@+-,#'_\n\r";
|
||||
for (i = 0; i < strlen(special); i++)
|
||||
charclasses[int(special[i])] = special[i];
|
||||
|
||||
for (i = 0; i < sizeof(uniign) / sizeof(int); i++) {
|
||||
unicign.insert(uniign[i]);
|
||||
for (i = 0; i < sizeof(uniign) / sizeof(int); i++) {
|
||||
unicign.insert(uniign[i]);
|
||||
}
|
||||
unicign.insert((unsigned int)-1);
|
||||
|
||||
for (i = 0; i < sizeof(avsbwht) / sizeof(int); i++) {
|
||||
visiblewhite.insert(avsbwht[i]);
|
||||
}
|
||||
}
|
||||
unicign.insert((unsigned int)-1);
|
||||
|
||||
for (i = 0; i < sizeof(avsbwht) / sizeof(int); i++) {
|
||||
visiblewhite.insert(avsbwht[i]);
|
||||
}
|
||||
|
||||
init = 1;
|
||||
}
|
||||
};
|
||||
static const CharClassInit charClassInitInstance;
|
||||
|
||||
static inline int whatcc(unsigned int c)
|
||||
{
|
||||
@ -280,8 +278,6 @@ bool TextSplit::text_to_words(const string &in)
|
||||
m_flags & TXTS_KEEPWILD ? " keepwild" : "",
|
||||
in.substr(0,50).c_str()));
|
||||
|
||||
setcharclasses();
|
||||
|
||||
m_span.erase();
|
||||
m_inNumber = false;
|
||||
m_wordStart = m_wordLen = m_prevpos = m_prevlen = m_wordpos = m_spanpos = 0;
|
||||
@ -633,7 +629,6 @@ int TextSplit::countWords(const string& s, TextSplit::Flags flgs)
|
||||
|
||||
bool TextSplit::hasVisibleWhite(const string &in)
|
||||
{
|
||||
setcharclasses();
|
||||
Utf8Iter it(in);
|
||||
for (; !it.eof(); it++) {
|
||||
unsigned int c = (unsigned char)*it;
|
||||
@ -650,7 +645,6 @@ bool TextSplit::hasVisibleWhite(const string &in)
|
||||
|
||||
template <class T> bool u8stringToStrings(const string &s, T &tokens)
|
||||
{
|
||||
setcharclasses();
|
||||
Utf8Iter it(s);
|
||||
|
||||
string current;
|
||||
|
||||
@ -63,7 +63,13 @@ using namespace std;
|
||||
#define deleteZ(X) {delete X;X = 0;}
|
||||
#endif
|
||||
|
||||
FsIndexer::FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc)
|
||||
: m_config(cnf), m_db(db), m_updater(updfunc), m_missing(new FIMissingStore)
|
||||
{
|
||||
m_havelocalfields = m_config->hasNameAnywhere("localfields");
|
||||
}
|
||||
FsIndexer::~FsIndexer() {
|
||||
delete m_missing;
|
||||
}
|
||||
|
||||
bool FsIndexer::init()
|
||||
@ -121,7 +127,7 @@ bool FsIndexer::index()
|
||||
}
|
||||
|
||||
string missing;
|
||||
FileInterner::getMissingDescription(missing);
|
||||
FileInterner::getMissingDescription(m_missing, missing);
|
||||
if (!missing.empty()) {
|
||||
LOGINFO(("FsIndexer::index missing helper program(s):\n%s\n",
|
||||
missing.c_str()));
|
||||
@ -359,6 +365,7 @@ FsIndexer::processone(const std::string &fn, const struct stat *stp,
|
||||
// indexallfilenames is not set
|
||||
return FsTreeWalker::FtwOk;
|
||||
}
|
||||
interner.setMissingStore(m_missing);
|
||||
|
||||
// File name transcoded to utf8 for indexing.
|
||||
string charset = m_config->getDefCharset(true);
|
||||
|
||||
@ -26,6 +26,7 @@ using std::list;
|
||||
#include "rcldb.h"
|
||||
|
||||
class DbIxStatusUpdater;
|
||||
class FIMissingStore;
|
||||
|
||||
/** Index selected parts of the file system
|
||||
|
||||
@ -45,12 +46,7 @@ class FsIndexer : public FsTreeWalkerCB {
|
||||
* @param cnf Configuration data
|
||||
* @param updfunc Status updater callback
|
||||
*/
|
||||
FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc = 0)
|
||||
: m_config(cnf), m_db(db), m_updater(updfunc)
|
||||
{
|
||||
m_havelocalfields = m_config->hasNameAnywhere("localfields");
|
||||
}
|
||||
|
||||
FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc = 0);
|
||||
virtual ~FsIndexer();
|
||||
|
||||
/**
|
||||
@ -79,6 +75,7 @@ class FsIndexer : public FsTreeWalkerCB {
|
||||
string m_reason;
|
||||
DbIxStatusUpdater *m_updater;
|
||||
list<string> m_tdl;
|
||||
FIMissingStore *m_missing;
|
||||
|
||||
// The configuration can set attribute fields to be inherited by
|
||||
// all files in a file system area. Ie: set "rclaptg = thunderbird"
|
||||
|
||||
@ -45,6 +45,7 @@ using namespace std;
|
||||
#include "beaglequeuecache.h"
|
||||
#include "cancelcheck.h"
|
||||
#include "copyfile.h"
|
||||
#include "ptmutex.h"
|
||||
|
||||
#ifdef RCL_USE_XATTR
|
||||
#include "pxattr.h"
|
||||
@ -76,9 +77,6 @@ static string colon_restore(const string& in)
|
||||
return out;
|
||||
}
|
||||
|
||||
set<string> FileInterner::o_missingExternal;
|
||||
map<string, set<string> > FileInterner::o_typesForMissing;
|
||||
|
||||
#ifdef RCL_USE_XATTR
|
||||
void FileInterner::reapXAttrs(const string& path)
|
||||
{
|
||||
@ -192,7 +190,7 @@ void FileInterner::tmpcleanup()
|
||||
FileInterner::FileInterner(const string &f, const struct stat *stp,
|
||||
RclConfig *cnf,
|
||||
TempDir& td, int flags, const string *imime)
|
||||
: m_tdir(td), m_ok(false)
|
||||
: m_tdir(td), m_ok(false), m_missingdatap(0)
|
||||
{
|
||||
initcommon(cnf, flags);
|
||||
init(f, stp, cnf, flags, imime);
|
||||
@ -304,7 +302,7 @@ void FileInterner::init(const string &f, const struct stat *stp, RclConfig *cnf,
|
||||
// Setup from memory data (ie: out of the web cache). imime needs to be set.
|
||||
FileInterner::FileInterner(const string &data, RclConfig *cnf,
|
||||
TempDir& td, int flags, const string& imime)
|
||||
: m_tdir(td), m_ok(false)
|
||||
: m_tdir(td), m_ok(false), m_missingdatap(0)
|
||||
{
|
||||
initcommon(cnf, flags);
|
||||
init(data, cnf, flags, imime);
|
||||
@ -366,9 +364,13 @@ void FileInterner::initcommon(RclConfig *cnf, int flags)
|
||||
m_targetMType = stxtplain;
|
||||
}
|
||||
|
||||
// We used a single beagle cache object to access beagle data. We protect it
|
||||
// against multiple thread access.
|
||||
static PTMutexInit o_lock;
|
||||
|
||||
FileInterner::FileInterner(const Rcl::Doc& idoc, RclConfig *cnf,
|
||||
TempDir& td, int flags)
|
||||
: m_tdir(td), m_ok(false)
|
||||
: m_tdir(td), m_ok(false), m_missingdatap(0)
|
||||
{
|
||||
LOGDEB(("FileInterner::FileInterner(idoc)\n"));
|
||||
initcommon(cnf, flags);
|
||||
@ -405,10 +407,6 @@ FileInterner::FileInterner(const Rcl::Doc& idoc, RclConfig *cnf,
|
||||
}
|
||||
init(fn, &st, cnf, flags, &idoc.mimetype);
|
||||
} else if (!backend.compare("BGL")) {
|
||||
// Retrieve from our webcache (beagle data). The beagler
|
||||
// object is created at the first call of this routine and
|
||||
// deleted when the program exits.
|
||||
static BeagleQueueCache beagler(cnf);
|
||||
string data;
|
||||
Rcl::Doc dotdoc;
|
||||
map<string,string>::const_iterator it =
|
||||
@ -418,11 +416,19 @@ FileInterner::FileInterner(const Rcl::Doc& idoc, RclConfig *cnf,
|
||||
return;
|
||||
}
|
||||
string udi = it->second;
|
||||
if (!beagler.getFromCache(udi, dotdoc, data)) {
|
||||
LOGINFO(("FileInterner:: failed fetch from Beagle cache for [%s]\n",
|
||||
udi.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
PTMutexLocker locker(o_lock);
|
||||
// Retrieve from our webcache (beagle data). The beagler
|
||||
// object is created at the first call of this routine and
|
||||
// deleted when the program exits.
|
||||
static BeagleQueueCache beagler(cnf);
|
||||
if (!beagler.getFromCache(udi, dotdoc, data)) {
|
||||
LOGINFO(("FileInterner:: failed fetch from Beagle cache for [%s]\n",
|
||||
udi.c_str()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (dotdoc.mimetype.compare(idoc.mimetype)) {
|
||||
LOGINFO(("FileInterner:: udi [%s], mimetp mismatch: in: [%s], bgl "
|
||||
"[%s]\n", idoc.mimetype.c_str(), dotdoc.mimetype.c_str()));
|
||||
@ -485,7 +491,7 @@ bool FileInterner::dataToTempFile(const string& dt, const string& mt,
|
||||
// accumulate helper name if it is
|
||||
void FileInterner::checkExternalMissing(const string& msg, const string& mt)
|
||||
{
|
||||
if (msg.find("RECFILTERROR") == 0) {
|
||||
if (m_missingdatap && msg.find("RECFILTERROR") == 0) {
|
||||
list<string> lerr;
|
||||
stringToStrings(msg, lerr);
|
||||
if (lerr.size() > 2) {
|
||||
@ -495,28 +501,33 @@ void FileInterner::checkExternalMissing(const string& msg, const string& mt)
|
||||
lerr.erase(it++);
|
||||
string s;
|
||||
stringsToString(lerr, s);
|
||||
o_missingExternal.insert(s);
|
||||
o_typesForMissing[s].insert(mt);
|
||||
m_missingdatap->m_missingExternal.insert(s);
|
||||
m_missingdatap->m_typesForMissing[s].insert(mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileInterner::getMissingExternal(string& out)
|
||||
void FileInterner::getMissingExternal(FIMissingStore *st, string& out)
|
||||
{
|
||||
stringsToString(o_missingExternal, out);
|
||||
if (st)
|
||||
stringsToString(st->m_missingExternal, out);
|
||||
}
|
||||
|
||||
void FileInterner::getMissingDescription(string& out)
|
||||
void FileInterner::getMissingDescription(FIMissingStore *st, string& out)
|
||||
{
|
||||
if (st == 0)
|
||||
return;
|
||||
|
||||
out.erase();
|
||||
|
||||
for (set<string>::const_iterator it = o_missingExternal.begin();
|
||||
it != o_missingExternal.end(); it++) {
|
||||
for (set<string>::const_iterator it =
|
||||
st->m_missingExternal.begin();
|
||||
it != st->m_missingExternal.end(); it++) {
|
||||
out += *it;
|
||||
map<string, set<string> >::const_iterator it2;
|
||||
it2 = o_typesForMissing.find(*it);
|
||||
if (it2 != o_typesForMissing.end()) {
|
||||
it2 = st->m_typesForMissing.find(*it);
|
||||
if (it2 != st->m_typesForMissing.end()) {
|
||||
out += " (";
|
||||
set<string>::const_iterator it3;
|
||||
for (it3 = it2->second.begin();
|
||||
|
||||
@ -39,6 +39,19 @@ class Doc;
|
||||
|
||||
struct stat;
|
||||
|
||||
/** Storage for missing helper program info. We want to keep this out of the
|
||||
* FileInterner class, because the data will typically be accumulated by several
|
||||
* FileInterner objects. Can't use static member either (because there
|
||||
* may be several separate usages of the class which shouldn't mix
|
||||
* their data).
|
||||
*/
|
||||
class FIMissingStore {
|
||||
public:
|
||||
// Missing external programs
|
||||
set<string> m_missingExternal;
|
||||
map<string, set<string> > m_typesForMissing;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class to convert data from a datastore (file-system, firefox
|
||||
* history, etc.) into possibly one or severaldocuments in internal
|
||||
@ -110,6 +123,11 @@ class FileInterner {
|
||||
|
||||
~FileInterner();
|
||||
|
||||
void setMissingStore(FIMissingStore *st)
|
||||
{
|
||||
m_missingdatap = st;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn file or file part into Recoll document.
|
||||
*
|
||||
@ -169,11 +187,10 @@ class FileInterner {
|
||||
RclConfig *cnf, const Rcl::Doc& doc);
|
||||
|
||||
const string& getReason() const {return m_reason;}
|
||||
static void getMissingExternal(string& missing);
|
||||
static void getMissingDescription(string& desc);
|
||||
static void getMissingExternal(FIMissingStore *st, string& missing);
|
||||
static void getMissingDescription(FIMissingStore *st, string& desc);
|
||||
bool ok() {return m_ok;}
|
||||
|
||||
|
||||
private:
|
||||
static const unsigned int MAXHANDLERS = 20;
|
||||
RclConfig *m_cfg;
|
||||
@ -203,9 +220,7 @@ class FileInterner {
|
||||
vector<TempFile> m_tempfiles;
|
||||
// Error data if any
|
||||
string m_reason;
|
||||
// Missing external programs
|
||||
static set<string> o_missingExternal;
|
||||
static map<string, set<string> > o_typesForMissing;
|
||||
FIMissingStore *m_missingdatap;
|
||||
|
||||
// Pseudo-constructors
|
||||
void init(const string &fn, const struct stat *stp,
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#include "rclconfig.h"
|
||||
#include "md5.h"
|
||||
#include "conftree.h"
|
||||
#include "ptmutex.h"
|
||||
|
||||
using namespace std;
|
||||
class FpKeeper {
|
||||
@ -52,6 +53,7 @@ public:
|
||||
private: FILE **m_fpp;
|
||||
};
|
||||
|
||||
static PTMutexInit o_mutex;
|
||||
|
||||
/**
|
||||
* Handles a cache for message numbers to offset translations. Permits direct
|
||||
@ -78,6 +80,7 @@ public:
|
||||
~MboxCache() {}
|
||||
mbhoff_type get_offset(RclConfig *config, const string& udi, int msgnum)
|
||||
{
|
||||
PTMutexLocker locker(o_mutex);
|
||||
LOGDEB0(("MboxCache::get_offsets: udi [%s] msgnum %d\n", udi.c_str(),
|
||||
msgnum));
|
||||
if (!ok(config)) {
|
||||
@ -125,6 +128,7 @@ public:
|
||||
void put_offsets(RclConfig *config, const string& udi, mbhoff_type fsize,
|
||||
vector<mbhoff_type>& offs)
|
||||
{
|
||||
PTMutexLocker locker(o_mutex);
|
||||
LOGDEB0(("MboxCache::put_offsets: %u offsets\n", offs.size()));
|
||||
if (!ok(config) || !maybemakedir())
|
||||
return;
|
||||
@ -159,6 +163,7 @@ public:
|
||||
|
||||
// Check state, possibly initialize
|
||||
bool ok(RclConfig *config) {
|
||||
PTMutexLocker locker(o_mutex);
|
||||
if (m_minfsize == -1)
|
||||
return false;
|
||||
if (!m_ok) {
|
||||
@ -218,7 +223,9 @@ private:
|
||||
};
|
||||
|
||||
const size_t MboxCache::o_b1size = 1024;
|
||||
|
||||
static class MboxCache mcache;
|
||||
|
||||
static const string keyquirks("mhmboxquirks");
|
||||
|
||||
MimeHandlerMbox::~MimeHandlerMbox()
|
||||
@ -389,6 +396,7 @@ bool MimeHandlerMbox::next_document()
|
||||
// avoid rereading the whole thing in this case. But I'm not sure
|
||||
// we're ever used in this way (multiple retrieves on same
|
||||
// object). So:
|
||||
bool storeoffsets = true;
|
||||
if (mtarg > 0) {
|
||||
mbhoff_type off;
|
||||
line_type line;
|
||||
@ -404,6 +412,7 @@ bool MimeHandlerMbox::next_document()
|
||||
LOGDEB0(("MimeHandlerMbox: Cache: From_ Ok\n"));
|
||||
fseeko(fp, (off_t)off, SEEK_SET);
|
||||
m_msgnum = mtarg -1;
|
||||
storeoffsets = false;
|
||||
} else {
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
m_msgnum = 0;
|
||||
@ -444,7 +453,8 @@ bool MimeHandlerMbox::next_document()
|
||||
!regexec(&minifromregex, line, 0, 0, 0)) ) {
|
||||
LOGDEB1(("MimeHandlerMbox: msgnum %d, "
|
||||
"From_ at line %d: [%s]\n", m_msgnum, m_lineno, line));
|
||||
m_offsets.push_back(message_end);
|
||||
if (storeoffsets)
|
||||
m_offsets.push_back(message_end);
|
||||
m_msgnum++;
|
||||
if ((mtarg <= 0 && m_msgnum > 1) ||
|
||||
(mtarg > 0 && m_msgnum > mtarg)) {
|
||||
@ -477,7 +487,7 @@ bool MimeHandlerMbox::next_document()
|
||||
if (iseof) {
|
||||
LOGDEB2(("MimeHandlerMbox::next: eof hit\n"));
|
||||
m_havedoc = false;
|
||||
if (!m_udi.empty()) {
|
||||
if (!m_udi.empty() && storeoffsets) {
|
||||
mcache.put_offsets(m_config, m_udi, m_fsize, m_offsets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,6 @@ using namespace std;
|
||||
#include "debuglog.h"
|
||||
#include "rclconfig.h"
|
||||
#include "smallut.h"
|
||||
#include "pthread.h"
|
||||
|
||||
#include "mh_exec.h"
|
||||
#include "mh_execm.h"
|
||||
@ -37,6 +36,7 @@ using namespace std;
|
||||
#include "mh_mbox.h"
|
||||
#include "mh_text.h"
|
||||
#include "mh_unknown.h"
|
||||
#include "ptmutex.h"
|
||||
|
||||
// Performance help: we use a pool of already known and created
|
||||
// handlers. There can be several instances for a given mime type
|
||||
@ -48,26 +48,7 @@ using namespace std;
|
||||
// simple lock should be enough as handlers are removed from the cache
|
||||
// while in use and multiple copies are allowed
|
||||
static multimap<string, Dijon::Filter*> o_handlers;
|
||||
pthread_mutex_t o_handlers_mutex;
|
||||
class HandlersLocker {
|
||||
public:
|
||||
HandlersLocker()
|
||||
{
|
||||
pthread_mutex_lock(&o_handlers_mutex);
|
||||
}
|
||||
~HandlersLocker()
|
||||
{
|
||||
pthread_mutex_unlock(&o_handlers_mutex);
|
||||
}
|
||||
};
|
||||
class HandlersLockerInit {
|
||||
public:
|
||||
HandlersLockerInit()
|
||||
{
|
||||
pthread_mutex_init(&o_handlers_mutex, 0);
|
||||
}
|
||||
};
|
||||
static HandlersLockerInit o_hli;
|
||||
static PTMutexInit o_handlers_mutex;
|
||||
|
||||
/** For mime types set as "internal" in mimeconf:
|
||||
* create appropriate handler object. */
|
||||
@ -163,7 +144,7 @@ void returnMimeHandler(Dijon::Filter *handler)
|
||||
typedef multimap<string, Dijon::Filter*>::value_type value_type;
|
||||
if (handler) {
|
||||
handler->clear();
|
||||
HandlersLocker locker;
|
||||
PTMutexLocker locker(o_handlers_mutex);
|
||||
o_handlers.insert(value_type(handler->get_mime_type(), handler));
|
||||
}
|
||||
}
|
||||
@ -172,7 +153,7 @@ void clearMimeHandlerCache()
|
||||
{
|
||||
typedef multimap<string, Dijon::Filter*>::value_type value_type;
|
||||
map<string, Dijon::Filter *>::iterator it;
|
||||
HandlersLocker locker;
|
||||
PTMutexLocker locker(o_handlers_mutex);
|
||||
for (it = o_handlers.begin(); it != o_handlers.end(); it++) {
|
||||
delete it->second;
|
||||
}
|
||||
@ -187,7 +168,7 @@ Dijon::Filter *getMimeHandler(const string &mtype, RclConfig *cfg,
|
||||
LOGDEB2(("getMimeHandler: mtype [%s] filtertypes %d\n",
|
||||
mtype.c_str(), filtertypes));
|
||||
Dijon::Filter *h = 0;
|
||||
HandlersLocker locker;
|
||||
PTMutexLocker locker(o_handlers_mutex);
|
||||
|
||||
// Get handler definition for mime type. We do this even if an
|
||||
// appropriate handler object may be in the cache (indexed by mime
|
||||
|
||||
@ -35,8 +35,6 @@
|
||||
#include "debuglog.h"
|
||||
#include "transcode.h"
|
||||
|
||||
map<string, string> MyHtmlParser::my_named_ents;
|
||||
|
||||
inline static bool
|
||||
p_notdigit(char c)
|
||||
{
|
||||
@ -151,20 +149,11 @@ static const char *epairs[] = {
|
||||
"rsaquo", "\xe2\x80\xba", "euro", "\xe2\x82\xac",
|
||||
NULL, NULL
|
||||
};
|
||||
|
||||
MyHtmlParser::MyHtmlParser()
|
||||
: in_script_tag(false),
|
||||
in_style_tag(false),
|
||||
in_body_tag(false),
|
||||
in_pre_tag(false),
|
||||
pending_space(false),
|
||||
indexing_allowed(true)
|
||||
{
|
||||
// The default html document charset is iso-8859-1. We'll update
|
||||
// this value from the encoding tag if found.
|
||||
charset = "iso-8859-1";
|
||||
|
||||
if (my_named_ents.empty()) {
|
||||
map<string, string> my_named_ents;
|
||||
class NamedEntsInitializer {
|
||||
public:
|
||||
NamedEntsInitializer()
|
||||
{
|
||||
for (int i = 0;;) {
|
||||
const char *ent;
|
||||
const char *val;
|
||||
@ -177,6 +166,20 @@ MyHtmlParser::MyHtmlParser()
|
||||
my_named_ents[string(ent)] = val;
|
||||
}
|
||||
}
|
||||
};
|
||||
static NamedEntsInitializer namedEntsInitializerInstance;
|
||||
|
||||
MyHtmlParser::MyHtmlParser()
|
||||
: in_script_tag(false),
|
||||
in_style_tag(false),
|
||||
in_body_tag(false),
|
||||
in_pre_tag(false),
|
||||
pending_space(false),
|
||||
indexing_allowed(true)
|
||||
{
|
||||
// The default html document charset is iso-8859-1. We'll update
|
||||
// this value from the encoding tag if found.
|
||||
charset = "iso-8859-1";
|
||||
}
|
||||
|
||||
void MyHtmlParser::decode_entities(string &s)
|
||||
|
||||
@ -40,7 +40,6 @@ class MyHtmlParser : public HtmlParser {
|
||||
bool in_pre_tag;
|
||||
bool pending_space;
|
||||
map<string,string> meta;
|
||||
static map<string, string> my_named_ents;
|
||||
string dump, dmtime;
|
||||
// This is the charset our caller thinks the doc used (initially
|
||||
// comes from the environment/configuration, used as source for
|
||||
|
||||
@ -48,8 +48,6 @@ using std::unique;
|
||||
#include "guiutils.h"
|
||||
#include "rclhelp.h"
|
||||
|
||||
extern RclConfig *rclconfig;
|
||||
|
||||
static const int initclausetypes[] = {1, 3, 0, 2, 5};
|
||||
static const unsigned int iclausescnt = sizeof(initclausetypes) / sizeof(int);
|
||||
static map<QString,QString> cat_translations;
|
||||
@ -268,7 +266,7 @@ void AdvSearch::fillFileTypes()
|
||||
|
||||
QStringList ql;
|
||||
if (m_ignByCats == false) {
|
||||
list<string> types = rclconfig->getAllMimeTypes();
|
||||
list<string> types = theconfig->getAllMimeTypes();
|
||||
for (list<string>::iterator it = types.begin();
|
||||
it != types.end(); it++) {
|
||||
QString qs = QString::fromUtf8(it->c_str());
|
||||
@ -277,7 +275,7 @@ void AdvSearch::fillFileTypes()
|
||||
}
|
||||
} else {
|
||||
list<string> cats;
|
||||
rclconfig->getMimeCategories(cats);
|
||||
theconfig->getMimeCategories(cats);
|
||||
for (list<string>::const_iterator it = cats.begin();
|
||||
it != cats.end(); it++) {
|
||||
map<QString, QString>::const_iterator it1;
|
||||
@ -334,7 +332,7 @@ void AdvSearch::runSearch()
|
||||
cat = (const char *)qcat.toUtf8();
|
||||
}
|
||||
list<string> types;
|
||||
rclconfig->getMimeCatTypes(cat, types);
|
||||
theconfig->getMimeCatTypes(cat, types);
|
||||
for (list<string>::const_iterator it = types.begin();
|
||||
it != types.end(); it++) {
|
||||
sdata->addFiletype(*it);
|
||||
|
||||
@ -49,8 +49,8 @@ using std::list;
|
||||
|
||||
namespace confgui {
|
||||
|
||||
const static int spacing = 2;
|
||||
const static int margin = 2;
|
||||
static const int spacing = 2;
|
||||
static const int margin = 2;
|
||||
|
||||
void ConfParamW::setValue(const QString& value)
|
||||
{
|
||||
|
||||
@ -44,8 +44,8 @@ using std::list;
|
||||
#include "rclconfig.h"
|
||||
|
||||
namespace confgui {
|
||||
const static int spacing = 3;
|
||||
const static int margin = 3;
|
||||
static const int spacing = 3;
|
||||
static const int margin = 3;
|
||||
|
||||
ConfIndexW::ConfIndexW(QWidget *parent, RclConfig *config)
|
||||
: QDialog(parent), m_rclconf(config)
|
||||
@ -84,6 +84,7 @@ void ConfIndexW::acceptChanges()
|
||||
delete m_conf;
|
||||
m_conf = 0;
|
||||
m_rclconf->updateMainConfig();
|
||||
snapshotConfig();
|
||||
|
||||
if (startIndexingAfterConfig) {
|
||||
startIndexingAfterConfig = 0;
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "smallut.h"
|
||||
#include "rclinit.h"
|
||||
#include "pathut.h"
|
||||
#include "recoll.h"
|
||||
|
||||
static int stopindexing;
|
||||
static int startindexing;
|
||||
@ -60,7 +61,6 @@ class IdxThread : public QThread , public DbIxStatusUpdater {
|
||||
// Maintain a copy/snapshot of idx status
|
||||
DbIxStatus m_statusSnap;
|
||||
bool m_interrupted;
|
||||
const RclConfig *cnf;
|
||||
};
|
||||
|
||||
void IdxThread::run()
|
||||
@ -76,7 +76,11 @@ void IdxThread::run()
|
||||
indexingstatus = IDXTS_NULL;
|
||||
// We make a private snapshot of the config: setKeydir changes
|
||||
// it during indexing and it may be updated by the main thread.
|
||||
RclConfig *myconf = new RclConfig(*cnf);
|
||||
RclConfig *myconf;
|
||||
{
|
||||
PTMutexLocker locker(thestableconfiglock);
|
||||
myconf = new RclConfig(*thestableconfig);
|
||||
}
|
||||
int loglevel;
|
||||
myconf->setKeyDir("");
|
||||
myconf->getConfParam("loglevel", &loglevel);
|
||||
@ -117,9 +121,8 @@ static IdxThread idxthread;
|
||||
|
||||
// Functions called by the main thread
|
||||
|
||||
void start_idxthread(const RclConfig& cnf)
|
||||
void start_idxthread()
|
||||
{
|
||||
idxthread.cnf = &cnf;
|
||||
idxthread.start();
|
||||
}
|
||||
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
#include <string>
|
||||
#include "indexer.h"
|
||||
|
||||
class RclConfig;
|
||||
|
||||
// These two deal with starting / stopping the thread itself, not
|
||||
// indexing sessions.
|
||||
extern void start_idxthread(const RclConfig& cnf);
|
||||
// cnf will be cloned each time we start an indexing pass. The pointer must
|
||||
// stay valid for the whole program duration.
|
||||
extern void start_idxthread();
|
||||
extern void stop_idxthread();
|
||||
|
||||
// Use these to to request action from thread
|
||||
|
||||
@ -47,7 +47,16 @@
|
||||
#include "smallut.h"
|
||||
#include "recollq.h"
|
||||
|
||||
RclConfig *rclconfig;
|
||||
RclConfig *theconfig;
|
||||
RclConfig *thestableconfig;
|
||||
PTMutexInit thestableconfiglock;
|
||||
|
||||
void snapshotConfig()
|
||||
{
|
||||
PTMutexLocker locker(thestableconfiglock);
|
||||
thestableconfig = new RclConfig(*theconfig);
|
||||
}
|
||||
|
||||
Rcl::Db *rcldb;
|
||||
#ifdef RCL_USE_ASPELL
|
||||
Aspell *aspell;
|
||||
@ -80,7 +89,7 @@ bool maybeOpenDb(string &reason, bool force)
|
||||
}
|
||||
if (!rcldb->isopen() && !rcldb->open(Rcl::Db::DbRO)) {
|
||||
reason = "Could not open database in " +
|
||||
rclconfig->getDbDir() + " wait for indexing to complete?";
|
||||
theconfig->getDbDir() + " wait for indexing to complete?";
|
||||
return false;
|
||||
}
|
||||
rcldb->setAbstractParams(-1, prefs.syntAbsLen, prefs.syntAbsCtx);
|
||||
@ -104,7 +113,8 @@ static void recollCleanup()
|
||||
rwSettings(true);
|
||||
LOGDEB2(("recollCleanup: closing database\n"));
|
||||
deleteZ(rcldb);
|
||||
deleteZ(rclconfig);
|
||||
deleteZ(theconfig);
|
||||
deleteZ(thestableconfig);
|
||||
#ifdef RCL_USE_ASPELL
|
||||
deleteZ(aspell);
|
||||
#endif
|
||||
@ -165,7 +175,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-t")) {
|
||||
exit(recollq(&rclconfig, argc, argv));
|
||||
exit(recollq(&theconfig, argc, argv));
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,17 +228,18 @@ int main(int argc, char **argv)
|
||||
app.installTranslator( &qt );
|
||||
|
||||
string reason;
|
||||
rclconfig = recollinit(recollCleanup, sigcleanup, reason, &a_config);
|
||||
if (!rclconfig || !rclconfig->ok()) {
|
||||
theconfig = recollinit(recollCleanup, sigcleanup, reason, &a_config);
|
||||
if (!theconfig || !theconfig->ok()) {
|
||||
QString msg = "Configuration problem: ";
|
||||
msg += QString::fromUtf8(reason.c_str());
|
||||
QMessageBox::critical(0, "Recoll", msg);
|
||||
exit(1);
|
||||
}
|
||||
snapshotConfig();
|
||||
// fprintf(stderr, "recollinit done\n");
|
||||
|
||||
// Translations for Recoll
|
||||
string translatdir = path_cat(rclconfig->getDatadir(), "translations");
|
||||
string translatdir = path_cat(theconfig->getDatadir(), "translations");
|
||||
QTranslator translator(0);
|
||||
translator.load( QString("recoll_") + slang, translatdir.c_str() );
|
||||
app.installTranslator( &translator );
|
||||
@ -236,7 +247,7 @@ int main(int argc, char **argv)
|
||||
// fprintf(stderr, "Translations installed\n");
|
||||
|
||||
#ifdef RCL_USE_ASPELL
|
||||
aspell = new Aspell(rclconfig);
|
||||
aspell = new Aspell(theconfig);
|
||||
aspell->init(reason);
|
||||
if (!aspell || !aspell->ok()) {
|
||||
LOGDEB(("Aspell speller creation failed %s\n", reason.c_str()));
|
||||
@ -244,7 +255,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
string historyfile = path_cat(rclconfig->getConfDir(), "history");
|
||||
string historyfile = path_cat(theconfig->getConfDir(), "history");
|
||||
g_dynconf = new RclDynConf(historyfile);
|
||||
if (!g_dynconf || !g_dynconf->ok()) {
|
||||
QString msg = app.translate("Main", "Configuration problem (dynconf");
|
||||
@ -266,7 +277,7 @@ int main(int argc, char **argv)
|
||||
mainWindow->resize(s);
|
||||
}
|
||||
|
||||
string dbdir = rclconfig->getDbDir();
|
||||
string dbdir = theconfig->getDbDir();
|
||||
if (dbdir.empty()) {
|
||||
QMessageBox::critical(0, "Recoll",
|
||||
app.translate("Main",
|
||||
@ -274,7 +285,7 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rcldb = new Rcl::Db(rclconfig);
|
||||
rcldb = new Rcl::Db(theconfig);
|
||||
|
||||
mainWindow->show();
|
||||
QTimer::singleShot(0, mainWindow, SLOT(initDbOpen()));
|
||||
@ -286,7 +297,7 @@ int main(int argc, char **argv)
|
||||
|
||||
// Start the indexing thread. It will immediately go to sleep waiting for
|
||||
// something to do.
|
||||
start_idxthread(*rclconfig);
|
||||
start_idxthread();
|
||||
|
||||
mainWindow->sSearch->searchTypCMB->setCurrentIndex(prefs.ssearchTyp);
|
||||
mainWindow->sSearch->searchTypeChanged(prefs.ssearchTyp);
|
||||
|
||||
@ -518,7 +518,7 @@ void Preview::setCurTabProps(const Rcl::Doc &doc, int docnum)
|
||||
}
|
||||
LOGDEB(("Doc.url: [%s]\n", doc.url.c_str()));
|
||||
string url;
|
||||
printableUrl(rclconfig->getDefCharset(), doc.url, url);
|
||||
printableUrl(theconfig->getDefCharset(), doc.url, url);
|
||||
string tiptxt = url + string("\n");
|
||||
tiptxt += doc.mimetype + " " + string(datebuf) + "\n";
|
||||
if (meta_it != doc.meta.end() && !meta_it->second.empty())
|
||||
@ -538,6 +538,11 @@ bool Preview::makeDocCurrent(const Rcl::Doc& doc, int docnum, bool sametab)
|
||||
{
|
||||
LOGDEB(("Preview::makeDocCurrent: %s\n", doc.url.c_str()));
|
||||
|
||||
if (m_loading) {
|
||||
LOGERR(("Already loading\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if we already have this page */
|
||||
for (int i = 0; i < pvTab->count(); i++) {
|
||||
QWidget *tw = pvTab->widget(i);
|
||||
@ -621,9 +626,10 @@ class LoadThread : public QThread {
|
||||
|
||||
// QMessageBox::critical(0, "Recoll", Preview::tr("File does not exist"));
|
||||
|
||||
FileInterner interner(idoc, rclconfig, tmpdir,
|
||||
FileInterner interner(idoc, theconfig, tmpdir,
|
||||
FileInterner::FIF_forPreview);
|
||||
|
||||
FIMissingStore mst;
|
||||
interner.setMissingStore(&mst);
|
||||
// We don't set the interner's target mtype to html because we
|
||||
// do want the html filter to do its work: we won't use the
|
||||
// text, but we need the conversion to utf-8
|
||||
@ -647,7 +653,7 @@ class LoadThread : public QThread {
|
||||
}
|
||||
} else {
|
||||
out.mimetype = interner.getMimetype();
|
||||
interner.getMissingExternal(missing);
|
||||
interner.getMissingExternal(&mst, missing);
|
||||
*statusp = -1;
|
||||
}
|
||||
} catch (CancelExcept) {
|
||||
@ -706,10 +712,6 @@ public:
|
||||
bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
|
||||
{
|
||||
LOGDEB1(("PreviewTextEdit::loadDocInCurrentTab()\n"));
|
||||
if (m_loading) {
|
||||
LOGERR(("ALready loading\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadGuard guard(&m_loading);
|
||||
CancelCheck::instance().setCancel(false);
|
||||
@ -757,14 +759,20 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
|
||||
if (CancelCheck::instance().cancelState())
|
||||
return false;
|
||||
if (status != 0) {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Can't turn doc into internal "
|
||||
"representation for ") +
|
||||
fdoc.mimetype.c_str());
|
||||
QString explain;
|
||||
if (!lthr.missing.empty()) {
|
||||
explain = QString::fromAscii("<br>") +
|
||||
tr("Missing helper program: ") +
|
||||
QString::fromLocal8Bit(lthr.missing.c_str());
|
||||
}
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Can't turn doc into internal "
|
||||
"representation for ") +
|
||||
fdoc.mimetype.c_str() + explain);
|
||||
return false;
|
||||
}
|
||||
// Reset config just in case.
|
||||
rclconfig->setKeyDir("");
|
||||
theconfig->setKeyDir("");
|
||||
|
||||
// Create preview text: highlight search terms
|
||||
// We don't do the highlighting for very big texts: too long. We
|
||||
|
||||
@ -97,6 +97,7 @@ void RclMain::init()
|
||||
spellform = 0;
|
||||
m_idxStatusAck = false;
|
||||
periodictimer = new QTimer(this);
|
||||
m_periodicToggle = 0;
|
||||
|
||||
// At least some versions of qt4 don't display the status bar if
|
||||
// it's not created here.
|
||||
@ -124,7 +125,7 @@ void RclMain::init()
|
||||
// instead
|
||||
string slangs;
|
||||
list<string> langs;
|
||||
if (rclconfig->getConfParam("indexstemminglanguages", slangs)) {
|
||||
if (theconfig->getConfParam("indexstemminglanguages", slangs)) {
|
||||
stringToStrings(slangs, langs);
|
||||
} else {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
@ -166,7 +167,7 @@ void RclMain::init()
|
||||
connect(bgrp, SIGNAL(buttonClicked(int)), this, SLOT(catgFilter(int)));
|
||||
allRDB->setChecked(true);
|
||||
list<string> cats;
|
||||
rclconfig->getMimeCategories(cats);
|
||||
theconfig->getMimeCategories(cats);
|
||||
// Text for button 0 is not used. Next statement just avoids unused
|
||||
// variable compiler warning for catg_strings
|
||||
m_catgbutvec.push_back(catg_strings[0]);
|
||||
@ -350,7 +351,7 @@ void RclMain::initDbOpen()
|
||||
question
|
||||
(this, "Recoll",
|
||||
qApp->translate("Main", "Could not open database in ") +
|
||||
QString::fromLocal8Bit(rclconfig->getDbDir().c_str()) +
|
||||
QString::fromLocal8Bit(theconfig->getDbDir().c_str()) +
|
||||
qApp->translate("Main",
|
||||
".\n"
|
||||
"Click Cancel if you want to edit the configuration file before indexing starts, or Ok to let it proceed."),
|
||||
@ -492,7 +493,6 @@ void RclMain::fileExit()
|
||||
// indexing thread and a possible need to exit
|
||||
void RclMain::periodic100()
|
||||
{
|
||||
static int toggle = 0;
|
||||
// Check if indexing thread done
|
||||
if (idxthread_getStatus() != IDXTS_NULL) {
|
||||
// Indexing is stopped
|
||||
@ -527,7 +527,7 @@ void RclMain::periodic100()
|
||||
fileToggleIndexingAction->setEnabled(TRUE);
|
||||
periodictimer->setInterval(100);
|
||||
// The toggle thing is for the status to flash
|
||||
if (toggle < 9) {
|
||||
if (m_periodicToggle < 9) {
|
||||
QString msg = tr("Indexing in progress: ");
|
||||
DbIxStatus status = idxthread_idxStatus();
|
||||
QString phs;
|
||||
@ -548,17 +548,17 @@ void RclMain::periodic100()
|
||||
msg += QString::fromAscii(cnts) + " ";
|
||||
}
|
||||
string mf;int ecnt = 0;
|
||||
string fcharset = rclconfig->getDefCharset(true);
|
||||
string fcharset = theconfig->getDefCharset(true);
|
||||
if (!transcode(status.fn, mf, fcharset, "UTF-8", &ecnt) || ecnt) {
|
||||
mf = url_encode(status.fn, 0);
|
||||
}
|
||||
msg += QString::fromUtf8(mf.c_str());
|
||||
statusBar()->showMessage(msg, 4000);
|
||||
} else if (toggle == 9) {
|
||||
} else if (m_periodicToggle == 9) {
|
||||
statusBar()->showMessage("");
|
||||
}
|
||||
if (++toggle >= 10)
|
||||
toggle = 0;
|
||||
if (++m_periodicToggle >= 10)
|
||||
m_periodicToggle = 0;
|
||||
}
|
||||
if (recollNeedsExit)
|
||||
fileExit();
|
||||
@ -602,7 +602,7 @@ void RclMain::startSearch(RefCntr<Rcl::SearchData> sdata)
|
||||
|
||||
string stemLang = (const char *)prefs.queryStemLang.toAscii();
|
||||
if (stemLang == "ALL") {
|
||||
rclconfig->getConfParam("indexstemminglanguages", stemLang);
|
||||
theconfig->getConfParam("indexstemminglanguages", stemLang);
|
||||
}
|
||||
sdata->setStemlang(stemLang);
|
||||
|
||||
@ -692,7 +692,7 @@ void RclMain::showIndexConfig()
|
||||
{
|
||||
LOGDEB(("showIndexConfig()\n"));
|
||||
if (indexConfig == 0) {
|
||||
indexConfig = new ConfIndexW(0, rclconfig);
|
||||
indexConfig = new ConfIndexW(0, theconfig);
|
||||
connect(new QShortcut(quitKeySeq, indexConfig), SIGNAL (activated()),
|
||||
this, SLOT (fileExit()));
|
||||
} else {
|
||||
@ -744,7 +744,7 @@ void RclMain::showAboutDialog()
|
||||
|
||||
void RclMain::showMissingHelpers()
|
||||
{
|
||||
string miss = rclconfig->getMissingHelperDesc();
|
||||
string miss = theconfig->getMissingHelperDesc();
|
||||
QString msg = tr("External applications/commands needed and not found "
|
||||
"for indexing your file types:\n\n");
|
||||
if (!miss.empty()) {
|
||||
@ -984,7 +984,7 @@ void RclMain::saveDocToFile(Rcl::Doc doc)
|
||||
);
|
||||
string tofile((const char *)s.toLocal8Bit());
|
||||
TempFile temp; // not used
|
||||
if (!FileInterner::idocToFile(temp, tofile, rclconfig, doc)) {
|
||||
if (!FileInterner::idocToFile(temp, tofile, theconfig, doc)) {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Cannot extract document or create "
|
||||
"temporary file"));
|
||||
@ -1034,13 +1034,13 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
|
||||
// Look for appropriate viewer
|
||||
string cmdplusattr;
|
||||
if (prefs.useDesktopOpen) {
|
||||
cmdplusattr = rclconfig->getMimeViewerDef("application/x-all", "");
|
||||
cmdplusattr = theconfig->getMimeViewerDef("application/x-all", "");
|
||||
} else {
|
||||
string apptag;
|
||||
map<string,string>::const_iterator it;
|
||||
if ((it = doc.meta.find(Rcl::Doc::keyapptg)) != doc.meta.end())
|
||||
apptag = it->second;
|
||||
cmdplusattr = rclconfig->getMimeViewerDef(doc.mimetype, apptag);
|
||||
cmdplusattr = theconfig->getMimeViewerDef(doc.mimetype, apptag);
|
||||
}
|
||||
|
||||
if (cmdplusattr.empty()) {
|
||||
@ -1053,7 +1053,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
|
||||
// Extract possible viewer attributes
|
||||
ConfSimple attrs;
|
||||
string cmd;
|
||||
rclconfig->valueSplitAttributes(cmdplusattr, cmd, attrs);
|
||||
theconfig->valueSplitAttributes(cmdplusattr, cmd, attrs);
|
||||
bool ignoreipath = false;
|
||||
if (attrs.get("ignoreipath", cmdplusattr))
|
||||
ignoreipath = stringToBool(cmdplusattr);
|
||||
@ -1073,7 +1073,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
|
||||
// directory
|
||||
string cmdpath;
|
||||
if (!ExecCmd::which(lcmd.front(), cmdpath)) {
|
||||
cmdpath = rclconfig->findFilter(lcmd.front());
|
||||
cmdpath = theconfig->findFilter(lcmd.front());
|
||||
// findFilter returns its input param if the filter is not in
|
||||
// the normal places. As we already looked in the path, we
|
||||
// have no use for a simple command name here (as opposed to
|
||||
@ -1128,10 +1128,10 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
|
||||
|
||||
// If the command wants a file but this is not a file url, or
|
||||
// there is an ipath that it won't understand, we need a temp file:
|
||||
rclconfig->setKeyDir(path_getfather(fn));
|
||||
theconfig->setKeyDir(path_getfather(fn));
|
||||
if ((wantsfile && fn.empty()) || (!wantsipath && !doc.ipath.empty())) {
|
||||
TempFile temp;
|
||||
if (!FileInterner::idocToFile(temp, string(), rclconfig, doc)) {
|
||||
if (!FileInterner::idocToFile(temp, string(), theconfig, doc)) {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Cannot extract document or create "
|
||||
"temporary file"));
|
||||
@ -1145,7 +1145,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
|
||||
|
||||
// If using an actual file, check that it exists, and if it is
|
||||
// compressed, we may need an uncompressed version
|
||||
if (!fn.empty() && rclconfig->mimeViewerNeedsUncomp(doc.mimetype)) {
|
||||
if (!fn.empty() && theconfig->mimeViewerNeedsUncomp(doc.mimetype)) {
|
||||
if (access(fn.c_str(), R_OK) != 0) {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Can't access file: ") +
|
||||
@ -1153,8 +1153,8 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
|
||||
return;
|
||||
}
|
||||
TempFile temp;
|
||||
if (FileInterner::isCompressed(fn, rclconfig)) {
|
||||
if (!FileInterner::maybeUncompressToTemp(temp, fn, rclconfig,
|
||||
if (FileInterner::isCompressed(fn, theconfig)) {
|
||||
if (!FileInterner::maybeUncompressToTemp(temp, fn, theconfig,
|
||||
doc)) {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Can't uncompress file: ") +
|
||||
@ -1208,7 +1208,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
|
||||
ncmd += " &";
|
||||
QStatusBar *stb = statusBar();
|
||||
if (stb) {
|
||||
string fcharset = rclconfig->getDefCharset(true);
|
||||
string fcharset = theconfig->getDefCharset(true);
|
||||
string prcmd;
|
||||
transcode(ncmd, prcmd, fcharset, "UTF-8");
|
||||
QString msg = tr("Executing: [") +
|
||||
@ -1234,7 +1234,7 @@ void RclMain::startManual(const string& index)
|
||||
{
|
||||
Rcl::Doc doc;
|
||||
doc.url = "file://";
|
||||
doc.url = path_cat(doc.url, rclconfig->getDatadir());
|
||||
doc.url = path_cat(doc.url, theconfig->getDatadir());
|
||||
doc.url = path_cat(doc.url, "doc");
|
||||
doc.url = path_cat(doc.url, "usermanual.html");
|
||||
LOGDEB(("RclMain::startManual: help index is %s\n",
|
||||
@ -1382,7 +1382,7 @@ void RclMain::catgFilter(int id)
|
||||
if (id != 0) {
|
||||
string catg = m_catgbutvec[id];
|
||||
list<string> tps;
|
||||
rclconfig->getMimeCatTypes(catg, tps);
|
||||
theconfig->getMimeCatTypes(catg, tps);
|
||||
for (list<string>::const_iterator it = tps.begin();
|
||||
it != tps.end(); it++)
|
||||
m_filtspec.orCrit(DocSeqFiltSpec::DSFS_MIMETYPE, *it);
|
||||
|
||||
@ -133,7 +133,8 @@ private:
|
||||
bool m_sortspecnochange;
|
||||
DocSeqSortSpec m_sortspec;
|
||||
RefCntr<DocSequence> m_source;
|
||||
|
||||
int m_periodicToggle;
|
||||
|
||||
virtual void init();
|
||||
virtual void previewPrevOrNextInTab(Preview *, int sid, int docnum,
|
||||
bool next);
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "rclconfig.h"
|
||||
#include "rcldb.h"
|
||||
#include "idxthread.h"
|
||||
#include "ptmutex.h"
|
||||
|
||||
// Misc declarations in need of sharing between the UI files
|
||||
|
||||
@ -30,7 +31,11 @@ extern bool maybeOpenDb(std::string &reason, bool force = true);
|
||||
/** Retrieve configured stemming languages */
|
||||
bool getStemLangs(list<string>& langs);
|
||||
|
||||
extern RclConfig *rclconfig;
|
||||
extern RclConfig *theconfig;
|
||||
extern RclConfig *thestableconfig;
|
||||
extern PTMutexInit thestableconfiglock;
|
||||
extern void snapshotConfig();
|
||||
|
||||
extern Rcl::Db *rcldb;
|
||||
extern int recollNeedsExit;
|
||||
extern int startIndexingAfterConfig; // 1st startup
|
||||
|
||||
@ -158,7 +158,7 @@ string QtGuiResListPager::pageTop()
|
||||
string QtGuiResListPager::iconPath(const string& mtype)
|
||||
{
|
||||
string iconpath;
|
||||
rclconfig->getMimeIconName(mtype, &iconpath);
|
||||
theconfig->getMimeIconName(mtype, &iconpath);
|
||||
return iconpath;
|
||||
}
|
||||
|
||||
@ -167,7 +167,7 @@ void QtGuiResListPager::suggest(const vector<string>uterms, vector<string>&sugg)
|
||||
sugg.clear();
|
||||
#ifdef RCL_USE_ASPELL
|
||||
bool noaspell = false;
|
||||
rclconfig->getConfParam("noaspell", &noaspell);
|
||||
theconfig->getConfParam("noaspell", &noaspell);
|
||||
if (noaspell)
|
||||
return;
|
||||
if (!aspell) {
|
||||
@ -524,7 +524,7 @@ void ResList::displayPage()
|
||||
{
|
||||
m_pageParaToReldocnums.clear();
|
||||
clear();
|
||||
m_pager->displayPage(rclconfig);
|
||||
m_pager->displayPage(theconfig);
|
||||
LOGDEB0(("ResList::resultPageNext: hasNext %d hasPrev %d\n",
|
||||
m_pager->hasPrev(), m_pager->hasNext()));
|
||||
emit prevPageAvailable(m_pager->hasPrev());
|
||||
|
||||
@ -102,7 +102,7 @@ const string& ResTablePager::parFormat()
|
||||
string ResTablePager::iconPath(const string& mtype)
|
||||
{
|
||||
string iconpath;
|
||||
rclconfig->getMimeIconName(mtype, &iconpath);
|
||||
theconfig->getMimeIconName(mtype, &iconpath);
|
||||
return iconpath;
|
||||
}
|
||||
|
||||
@ -229,8 +229,8 @@ RecollModel::RecollModel(const QStringList fields, QObject *parent)
|
||||
// Add dynamic "stored" fields to the full column list. This
|
||||
// could be protected to be done only once, but it's no real
|
||||
// problem
|
||||
if (rclconfig) {
|
||||
const set<string>& stored = rclconfig->getStoredFields();
|
||||
if (theconfig) {
|
||||
const set<string>& stored = theconfig->getStoredFields();
|
||||
for (set<string>::const_iterator it = stored.begin();
|
||||
it != stored.end(); it++) {
|
||||
if (o_displayableFields.find(*it) == o_displayableFields.end()) {
|
||||
@ -535,7 +535,7 @@ void ResTable::onTableView_currentChanged(const QModelIndex& index)
|
||||
m_detail->clear();
|
||||
m_detaildocnum = index.row();
|
||||
m_detaildoc = doc;
|
||||
m_pager->displayDoc(rclconfig, index.row(), doc, m_model->m_hdata);
|
||||
m_pager->displayDoc(theconfig, index.row(), doc, m_model->m_hdata);
|
||||
} else {
|
||||
m_detaildocnum = -1;
|
||||
}
|
||||
|
||||
@ -82,8 +82,8 @@ void SearchClauseW::languageChange()
|
||||
// sTpCMB->insertItem(tr("Complex clause"));//6
|
||||
|
||||
fldCMB->addItem(tr("In field"));
|
||||
if (rclconfig) {
|
||||
set<string> fields = rclconfig->getIndexedFields();
|
||||
if (theconfig) {
|
||||
set<string> fields = theconfig->getIndexedFields();
|
||||
for (set<string>::const_iterator it = fields.begin();
|
||||
it != fields.end(); it++) {
|
||||
// Some fields don't make sense here
|
||||
|
||||
@ -50,7 +50,7 @@ void SpellW::init()
|
||||
/*2*/expTypeCMB->addItem(tr("Stem expansion"));
|
||||
#ifdef RCL_USE_ASPELL
|
||||
bool noaspell = false;
|
||||
rclconfig->getConfParam("noaspell", &noaspell);
|
||||
theconfig->getConfParam("noaspell", &noaspell);
|
||||
if (!noaspell)
|
||||
/*3*/expTypeCMB->addItem(tr("Spelling/Phonetic"));
|
||||
#endif
|
||||
|
||||
@ -132,9 +132,9 @@ void SSearch::startSimpleSearch()
|
||||
if (tp == SST_LANG) {
|
||||
string reason;
|
||||
if (prefs.autoSuffsEnable)
|
||||
sdata = wasaStringToRcl(rclconfig, u8, reason, (const char *)prefs.autoSuffs.toUtf8());
|
||||
sdata = wasaStringToRcl(theconfig, u8, reason, (const char *)prefs.autoSuffs.toUtf8());
|
||||
else
|
||||
sdata = wasaStringToRcl(rclconfig, u8, reason);
|
||||
sdata = wasaStringToRcl(theconfig, u8, reason);
|
||||
if (sdata == 0) {
|
||||
QMessageBox::warning(0, "Recoll", tr("Bad query string") + ": " +
|
||||
QString::fromAscii(reason.c_str()));
|
||||
@ -280,7 +280,7 @@ void SSearch::completion()
|
||||
Rcl::TermMatchResult tmres;
|
||||
string stemLang = (const char *)prefs.queryStemLang.toAscii();
|
||||
if (stemLang == "ALL") {
|
||||
rclconfig->getConfParam("indexstemminglanguages", stemLang);
|
||||
theconfig->getConfParam("indexstemminglanguages", stemLang);
|
||||
}
|
||||
if (!rcldb->termMatch(Rcl::Db::ET_WILD, stemLang, s, tmres, max) ||
|
||||
tmres.entries.size() == 0) {
|
||||
|
||||
@ -372,7 +372,7 @@ void UIPrefsDialog::addExtraDbPB_clicked()
|
||||
}
|
||||
struct stat st1, st2;
|
||||
stat(dbdir.c_str(), &st1);
|
||||
string rcldbdir = rclconfig->getDbDir();
|
||||
string rcldbdir = theconfig->getDbDir();
|
||||
stat(rcldbdir.c_str(), &st2);
|
||||
path_catslash(rcldbdir);
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ void ViewAction::fillLists()
|
||||
actionsLV->clear();
|
||||
actionsLV->verticalHeader()->setDefaultSectionSize(20);
|
||||
vector<pair<string, string> > defs;
|
||||
rclconfig->getMimeViewerDefs(defs);
|
||||
theconfig->getMimeViewerDefs(defs);
|
||||
actionsLV->setRowCount(defs.size());
|
||||
int row = 0;
|
||||
for (vector<pair<string, string> >::const_iterator it = defs.begin();
|
||||
@ -128,7 +128,7 @@ void ViewAction::editActions()
|
||||
string sact = (const char *)newaction.toLocal8Bit();
|
||||
for (list<string>::const_iterator it = mtypes.begin();
|
||||
it != mtypes.end(); it++) {
|
||||
rclconfig->setMimeViewerDef(*it, sact);
|
||||
theconfig->setMimeViewerDef(*it, sact);
|
||||
}
|
||||
fillLists();
|
||||
}
|
||||
|
||||
@ -372,7 +372,7 @@ string ResListPager::detailsLink()
|
||||
|
||||
const string &ResListPager::parFormat()
|
||||
{
|
||||
const static string format("<img src=\"%I\" align=\"left\">"
|
||||
static const string format("<img src=\"%I\" align=\"left\">"
|
||||
"%R %S %L <b>%T</b><br>"
|
||||
"%M %D <i>%U</i><br>"
|
||||
"%A %K");
|
||||
|
||||
@ -80,7 +80,7 @@ string version_string(){
|
||||
|
||||
// Synthetic abstract marker (to discriminate from abstract actually
|
||||
// found in document)
|
||||
const static string rclSyntAbs("?!#@");
|
||||
static const string rclSyntAbs("?!#@");
|
||||
|
||||
// Compute the unique term used to link documents to their origin.
|
||||
// "Q" + external udi
|
||||
|
||||
@ -38,7 +38,7 @@ namespace Rcl {
|
||||
namespace StemDb {
|
||||
|
||||
|
||||
const static string stemdirstem = "stem_";
|
||||
static const string stemdirstem = "stem_";
|
||||
|
||||
/// Compute name of stem db for given base database and language
|
||||
static string stemdbname(const string& dbdir, const string& lang)
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
@ -44,6 +43,7 @@
|
||||
#include "smallut.h"
|
||||
#include "netcon.h"
|
||||
#include "closefrom.h"
|
||||
#include "ptmutex.h"
|
||||
|
||||
#ifndef NO_NAMESPACES
|
||||
using namespace std;
|
||||
@ -316,38 +316,20 @@ private:
|
||||
// The netcon selectloop that doexec() uses for reading/writing would
|
||||
// be complicated to render thread-safe. Use locking to ensure only
|
||||
// one thread in there
|
||||
class ExecLocking {
|
||||
public:
|
||||
pthread_mutex_t m_mutex;
|
||||
ExecLocking()
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, 0);
|
||||
}
|
||||
};
|
||||
ExecLocking o_lock;
|
||||
class ExecLocker {
|
||||
public:
|
||||
ExecLocker()
|
||||
{
|
||||
pthread_mutex_lock(&o_lock.m_mutex);
|
||||
}
|
||||
~ExecLocker()
|
||||
{
|
||||
pthread_mutex_unlock(&o_lock.m_mutex);
|
||||
}
|
||||
};
|
||||
static PTMutexInit o_lock;
|
||||
|
||||
int ExecCmd::doexec(const string &cmd, const list<string>& args,
|
||||
const string *input, string *output)
|
||||
{
|
||||
// Only one thread allowed in here...
|
||||
PTMutexLocker locker(o_lock);
|
||||
|
||||
if (startExec(cmd, args, input != 0, output != 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Cleanup in case we return early
|
||||
ExecCmdRsrc e(this);
|
||||
// Only one thread allowed in here...
|
||||
ExecLocker locker;
|
||||
|
||||
int ret = 0;
|
||||
if (input || output) {
|
||||
|
||||
52
src/utils/ptmutex.h
Normal file
52
src/utils/ptmutex.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* Copyright (C) 2011 J.F.Dockes
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef _PTMUTEX_H_INCLUDED_
|
||||
#define _PTMUTEX_H_INCLUDED_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/// A trivial wrapper/helper for pthread mutex locks
|
||||
|
||||
|
||||
/// Init lock. Used as a single PTMutexInit static object.
|
||||
class PTMutexInit {
|
||||
public:
|
||||
pthread_mutex_t m_mutex;
|
||||
PTMutexInit()
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/// Take the lock when constructed, release when deleted
|
||||
class PTMutexLocker {
|
||||
public:
|
||||
PTMutexLocker(PTMutexInit& l) : m_lock(l)
|
||||
{
|
||||
m_status = pthread_mutex_lock(&m_lock.m_mutex);
|
||||
}
|
||||
~PTMutexLocker()
|
||||
{
|
||||
pthread_mutex_unlock(&m_lock.m_mutex);
|
||||
}
|
||||
int ok() {return m_status == 0;}
|
||||
private:
|
||||
PTMutexInit& m_lock;
|
||||
int m_status;
|
||||
};
|
||||
|
||||
#endif /* _PTMUTEX_H_INCLUDED_ */
|
||||
Loading…
x
Reference in New Issue
Block a user