aspell checkpoint
This commit is contained in:
parent
57b468f58a
commit
8283ca3bfc
@ -1 +1 @@
|
||||
1.5.4
|
||||
1.6.0
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#ifndef TEST_RCLASPELL
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: rclaspell.cpp,v 1.1 2006-10-09 14:05:35 dockes Exp $ (C) 2006 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: rclaspell.cpp,v 1.2 2006-10-09 16:37:08 dockes Exp $ (C) 2006 J.F.Dockes";
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
@ -173,7 +173,7 @@ bool Aspell::buildDict(Rcl::Db &db, string &reason)
|
||||
|
||||
|
||||
bool Aspell::suggest(Rcl::Db &db,
|
||||
string &term, list<string>suggestions, string &reason)
|
||||
string &term, list<string> &suggestions, string &reason)
|
||||
{
|
||||
AspellCanHaveError *ret;
|
||||
AspellSpeller *speller;
|
||||
@ -184,6 +184,8 @@ bool Aspell::suggest(Rcl::Db &db,
|
||||
aapi.aspell_config_replace(config, "lang", m_lang.c_str());
|
||||
aapi.aspell_config_replace(config, "encoding", "utf-8");
|
||||
aapi.aspell_config_replace(config, "master", dicPath().c_str());
|
||||
aapi.aspell_config_replace(config, "sug-mode", "fast");
|
||||
// aapi.aspell_config_replace(config, "sug-edit-dist", "2");
|
||||
ret = aapi.new_aspell_speller(config);
|
||||
aapi.delete_aspell_config(config);
|
||||
|
||||
@ -203,7 +205,15 @@ bool Aspell::suggest(Rcl::Db &db,
|
||||
AspellStringEnumeration *els = aapi.aspell_word_list_elements(wl);
|
||||
const char *word;
|
||||
while ((word = aapi.aspell_string_enumeration_next(els)) != 0) {
|
||||
suggestions.push_back(word);
|
||||
// stemDiffers checks that the word exists (we don't want
|
||||
// aspell computed stuff, only exact terms from the dictionary),
|
||||
// and that it stems differently to the base word (else it's not
|
||||
// useful to expand the search). Or is it ?
|
||||
// ******** This should depend if
|
||||
// stemming is turned on or not for querying *******
|
||||
string sw(word);
|
||||
if (db.termExists(sw) && db.stemDiffers("english", sw, term))
|
||||
suggestions.push_back(word);
|
||||
}
|
||||
aapi.delete_aspell_string_enumeration(els);
|
||||
aapi.delete_aspell_speller(speller);
|
||||
@ -233,7 +243,9 @@ RclConfig *rclconfig;
|
||||
Rcl::Db rcldb;
|
||||
|
||||
static char usage [] =
|
||||
" \n\n"
|
||||
" -b : build dictionary\n"
|
||||
" -s <term>: suggestions for term\n"
|
||||
"\n\n"
|
||||
;
|
||||
static void
|
||||
Usage(void)
|
||||
@ -249,75 +261,75 @@ static int op_flags;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int count = 10;
|
||||
string word;
|
||||
|
||||
thisprog = argv[0];
|
||||
argc--; argv++;
|
||||
thisprog = argv[0];
|
||||
argc--; argv++;
|
||||
|
||||
while (argc > 0 && **argv == '-') {
|
||||
(*argv)++;
|
||||
if (!(**argv))
|
||||
/* Cas du "adb - core" */
|
||||
Usage();
|
||||
while (**argv)
|
||||
switch (*(*argv)++) {
|
||||
case 's': op_flags |= OPT_s; break;
|
||||
case 'b': op_flags |= OPT_b; if (argc < 2) Usage();
|
||||
if ((sscanf(*(++argv), "%d", &count)) != 1)
|
||||
Usage();
|
||||
argc--;
|
||||
goto b1;
|
||||
default: Usage(); break;
|
||||
}
|
||||
b1: argc--; argv++;
|
||||
}
|
||||
|
||||
if (argc != 0)
|
||||
Usage();
|
||||
|
||||
string reason;
|
||||
rclconfig = recollinit(0, 0, reason);
|
||||
if (!rclconfig || !rclconfig->ok()) {
|
||||
fprintf(stderr, "Configuration problem: %s\n", reason.c_str());
|
||||
exit(1);
|
||||
while (argc > 0 && **argv == '-') {
|
||||
(*argv)++;
|
||||
if (!(**argv))
|
||||
/* Cas du "adb - core" */
|
||||
Usage();
|
||||
while (**argv)
|
||||
switch (*(*argv)++) {
|
||||
case 'b': op_flags |= OPT_b; break;
|
||||
case 's': op_flags |= OPT_s; if (argc < 2) Usage();
|
||||
word = *(++argv);
|
||||
argc--;
|
||||
goto b1;
|
||||
default: Usage(); break;
|
||||
}
|
||||
b1: argc--; argv++;
|
||||
}
|
||||
|
||||
string dbdir = rclconfig->getDbDir();
|
||||
if (dbdir.empty()) {
|
||||
fprintf(stderr, "No db directory in configuration");
|
||||
exit(1);
|
||||
}
|
||||
if (argc != 0 || op_flags == 0)
|
||||
Usage();
|
||||
|
||||
if (!rcldb.open(dbdir, Rcl::Db::DbRO, 0)) {
|
||||
fprintf(stderr, "Could not open database in %s\n", dbdir.c_str());
|
||||
exit(1);
|
||||
}
|
||||
string reason;
|
||||
rclconfig = recollinit(0, 0, reason);
|
||||
if (!rclconfig || !rclconfig->ok()) {
|
||||
fprintf(stderr, "Configuration problem: %s\n", reason.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
string lang = "en";
|
||||
string dbdir = rclconfig->getDbDir();
|
||||
if (dbdir.empty()) {
|
||||
fprintf(stderr, "No db directory in configuration");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Aspell aspell(rclconfig, lang);
|
||||
if (!rcldb.open(dbdir, Rcl::Db::DbRO, 0)) {
|
||||
fprintf(stderr, "Could not open database in %s\n", dbdir.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!aspell.init("/usr/local", reason)) {
|
||||
cerr << "Init failed: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
#if 0
|
||||
if (!aspell.buildDict(rcldb, reason)) {
|
||||
cerr << "buildDict failed: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
list<string> sug;
|
||||
string word = "practice";
|
||||
if (!aspell.suggest(rcldb, word, sug, reason)) {
|
||||
cerr << "suggest failed: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
for (list<string>::iterator it = sug.begin(); it != sug.end(); it++) {
|
||||
cout << *it << endl;
|
||||
}
|
||||
string lang = "en";
|
||||
|
||||
exit(0);
|
||||
Aspell aspell(rclconfig, lang);
|
||||
|
||||
if (!aspell.init("/usr/local", reason)) {
|
||||
cerr << "Init failed: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
if (op_flags & OPT_b) {
|
||||
if (!aspell.buildDict(rcldb, reason)) {
|
||||
cerr << "buildDict failed: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
list<string> suggs;
|
||||
if (!aspell.suggest(rcldb, word, suggs, reason)) {
|
||||
cerr << "suggest failed: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
cout << "Suggestions for " << word << ":" << endl;
|
||||
for (list<string>::iterator it = suggs.begin();
|
||||
it != suggs.end(); it++) {
|
||||
cout << *it << endl;
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif // TEST_RCLASPELL test driver
|
||||
|
||||
@ -1,8 +1,17 @@
|
||||
#ifndef _RCLASPELL_H_INCLUDED_
|
||||
#define _RCLASPELL_H_INCLUDED_
|
||||
/* @(#$Id: rclaspell.h,v 1.1 2006-10-09 14:05:35 dockes Exp $ (C) 2006 J.F.Dockes */
|
||||
/* @(#$Id: rclaspell.h,v 1.2 2006-10-09 16:37:08 dockes Exp $ (C) 2006 J.F.Dockes */
|
||||
|
||||
/// Class to interface an aspell speller.
|
||||
/**
|
||||
* Aspell speller interface class.
|
||||
*
|
||||
* Aspell is used to let the user find about spelling variations that may
|
||||
* exist in the document set for a given word.
|
||||
* A specific aspell dictionary is created out of all the terms in the
|
||||
* xapian index, and we then use it to expand a term to spelling neighbours.
|
||||
* We use the aspell C api for term expansion, but have
|
||||
* to execute the program to create dictionaries.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
@ -22,19 +31,23 @@ class Aspell {
|
||||
Aspell(RclConfig *cnf, const string &lang)
|
||||
: m_conf(cnf), m_lang(lang), m_data(0) {};
|
||||
~Aspell();
|
||||
|
||||
/** Check health */
|
||||
bool ok();
|
||||
/** Get hold of the aspell command and shared library */
|
||||
|
||||
/** Find the aspell command and shared library, init function pointers */
|
||||
bool init(const string &basedir, string &reason);
|
||||
|
||||
/** Build dictionary out of index term list. This is done at the end
|
||||
* of an indexing pass. */
|
||||
bool buildDict(Rcl::Db &db, string &reason);
|
||||
/** Return a list of possible expansions for user term */
|
||||
bool suggest(Rcl::Db &db, string &term, list<string>suggestions,
|
||||
|
||||
/** Return a list of possible expansions for a given word */
|
||||
bool suggest(Rcl::Db &db, string &term, list<string> &suggestions,
|
||||
string &reason);
|
||||
string dicPath();
|
||||
|
||||
private:
|
||||
string dicPath();
|
||||
RclConfig *m_conf;
|
||||
string m_lang;
|
||||
AspellData *m_data;
|
||||
|
||||
@ -4,7 +4,7 @@ include $(depth)/mk/sysconf
|
||||
PROGS = recollindex csguess mimetype
|
||||
SRCS = recollindex.cpp
|
||||
|
||||
all: depend $(PROGS)
|
||||
all: depend $(PROGS) $(BIGLIB)
|
||||
|
||||
RECOLLINDEX_OBJS= recollindex.o $(BIGLIB) $(MIMELIB)
|
||||
recollindex : $(RECOLLINDEX_OBJS)
|
||||
@ -29,8 +29,10 @@ trmimetype.o : mimetype.cpp
|
||||
$(CXX) $(ALL_CXXFLAGS) -DTEST_MIMETYPE -c -o trmimetype.o \
|
||||
mimetype.cpp
|
||||
|
||||
$(BIGLIB):
|
||||
$(BIGLIB): force
|
||||
cd $(depth)/lib;$(MAKE)
|
||||
force:
|
||||
|
||||
$(MIMELIB):
|
||||
cd $(depth)/bincimapmime;$(MAKE)
|
||||
|
||||
|
||||
@ -8,8 +8,8 @@ LIBS = librcl.a
|
||||
|
||||
all: $(LIBS)
|
||||
|
||||
OBJS = conftree.o csguess.o debuglog.o execmd.o idfile.o md5.o wipedir.o fstreewalk.o mh_html.o mh_mail.o mh_exec.o mh_text.o htmlparse.o indexer.o internfile.o mimehandler.o mimeparse.o mimetype.o myhtmlparse.o pathhash.o pathut.o rclconfig.o rcldb.o rclinit.o stemdb.o base64.o readfile.o smallut.o textsplit.o transcode.o unacpp.o history.o docseq.o sortseq.o copyfile.o
|
||||
DEPS = conftree.dep.stamp csguess.dep.stamp debuglog.dep.stamp execmd.dep.stamp idfile.dep.stamp md5.dep.stamp wipedir.dep.stamp fstreewalk.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_exec.dep.stamp mh_text.dep.stamp htmlparse.dep.stamp indexer.dep.stamp internfile.dep.stamp mimehandler.dep.stamp mimeparse.dep.stamp mimetype.dep.stamp myhtmlparse.dep.stamp pathhash.dep.stamp pathut.dep.stamp rclconfig.dep.stamp rcldb.dep.stamp rclinit.dep.stamp stemdb.dep.stamp base64.dep.stamp readfile.dep.stamp smallut.dep.stamp textsplit.dep.stamp transcode.dep.stamp unacpp.dep.stamp history.dep.stamp docseq.dep.stamp sortseq.dep.stamp copyfile.dep.stamp
|
||||
OBJS = conftree.o csguess.o debuglog.o execmd.o idfile.o md5.o wipedir.o fstreewalk.o mh_html.o mh_mail.o mh_exec.o mh_text.o htmlparse.o indexer.o internfile.o mimehandler.o mimeparse.o mimetype.o myhtmlparse.o pathhash.o pathut.o rclconfig.o rcldb.o rclinit.o stemdb.o base64.o readfile.o smallut.o textsplit.o transcode.o unacpp.o history.o docseq.o sortseq.o copyfile.o rclaspell.o
|
||||
DEPS = conftree.dep.stamp csguess.dep.stamp debuglog.dep.stamp execmd.dep.stamp idfile.dep.stamp md5.dep.stamp wipedir.dep.stamp fstreewalk.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_exec.dep.stamp mh_text.dep.stamp htmlparse.dep.stamp indexer.dep.stamp internfile.dep.stamp mimehandler.dep.stamp mimeparse.dep.stamp mimetype.dep.stamp myhtmlparse.dep.stamp pathhash.dep.stamp pathut.dep.stamp rclconfig.dep.stamp rcldb.dep.stamp rclinit.dep.stamp stemdb.dep.stamp base64.dep.stamp readfile.dep.stamp smallut.dep.stamp textsplit.dep.stamp transcode.dep.stamp unacpp.dep.stamp history.dep.stamp docseq.dep.stamp sortseq.dep.stamp copyfile.dep.stamp rclaspell.dep.stamp
|
||||
|
||||
librcl.a : $(DEPS) $(OBJS) unac.o
|
||||
ar ru librcl.a $(OBJS) unac.o
|
||||
@ -87,6 +87,8 @@ sortseq.o : ../query/sortseq.cpp
|
||||
$(CXX) $(ALL_CXXFLAGS) -c ../query/sortseq.cpp
|
||||
copyfile.o : ../utils/copyfile.cpp
|
||||
$(CXX) $(ALL_CXXFLAGS) -c ../utils/copyfile.cpp
|
||||
rclaspell.o : ../aspell/rclaspell.cpp
|
||||
$(CXX) $(ALL_CXXFLAGS) -c ../aspell/rclaspell.cpp
|
||||
depend: $(DEPS)
|
||||
clean:
|
||||
rm -f $(OBJS) $(LIBS) $(DEPS) unac.o
|
||||
@ -198,6 +200,9 @@ sortseq.dep.stamp : ../query/sortseq.cpp
|
||||
copyfile.dep.stamp : ../utils/copyfile.cpp
|
||||
$(CXX) -M $(ALL_CXXFLAGS) ../utils/copyfile.cpp > copyfile.dep
|
||||
touch copyfile.dep.stamp
|
||||
rclaspell.dep.stamp : ../aspell/rclaspell.cpp
|
||||
$(CXX) -M $(ALL_CXXFLAGS) ../aspell/rclaspell.cpp > rclaspell.dep
|
||||
touch rclaspell.dep.stamp
|
||||
include conftree.dep
|
||||
include csguess.dep
|
||||
include debuglog.dep
|
||||
@ -233,3 +238,4 @@ include history.dep
|
||||
include docseq.dep
|
||||
include sortseq.dep
|
||||
include copyfile.dep
|
||||
include rclaspell.dep
|
||||
|
||||
@ -21,7 +21,7 @@ SRCS="${depth}/utils/conftree.cpp ${depth}/index/csguess.cpp \
|
||||
${depth}/utils/transcode.cpp ${depth}/common/unacpp.cpp \
|
||||
${depth}/query/history.cpp \
|
||||
${depth}/query/docseq.cpp ${depth}/query/sortseq.cpp \
|
||||
${depth}/utils/copyfile.cpp"
|
||||
${depth}/utils/copyfile.cpp ${depth}/aspell/rclaspell.cpp"
|
||||
|
||||
|
||||
for c in $SRCS;do
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# @(#$Id: makesrcdist.sh,v 1.10 2006-09-23 13:13:49 dockes Exp $ (C) 2005 J.F.Dockes
|
||||
# @(#$Id: makesrcdist.sh,v 1.11 2006-10-09 16:37:08 dockes Exp $ (C) 2005 J.F.Dockes
|
||||
# A shell-script to make a recoll source distribution
|
||||
|
||||
#set -x
|
||||
@ -71,7 +71,7 @@ diff $topdir/doc/user/u1.html $topdir/doc/user/usermanual.html
|
||||
mv -f $topdir/doc/user/u1.html $topdir/doc/user/usermanual.html
|
||||
|
||||
# We tag .. as there is the 'packaging/' directory in there
|
||||
CVSTAG="RECOLL-$versionforcvs"
|
||||
CVSTAG="RECOLL_$versionforcvs"
|
||||
[ $dotag = "yes" ] && (cd ..;cvs tag -F $CVSTAG .)
|
||||
|
||||
out=recoll-$version.tar.gz
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: rcldb.cpp,v 1.79 2006-09-29 08:26:02 dockes Exp $ (C) 2004 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: rcldb.cpp,v 1.80 2006-10-09 16:37:08 dockes Exp $ (C) 2004 J.F.Dockes";
|
||||
#endif
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -890,7 +890,7 @@ static void stringToXapianQueries(const string &iq,
|
||||
dumb_string(term, term1);
|
||||
// Possibly perform stem compression/expansion
|
||||
if (!nostemexp && (opts & Db::QO_STEM)) {
|
||||
exp = m_ndb->stemExpand(stemlang,term1);
|
||||
exp = m_ndb->stemExpand(stemlang, term1);
|
||||
} else {
|
||||
exp.push_back(term1);
|
||||
}
|
||||
@ -1117,6 +1117,60 @@ list<string> Db::completions(const string &root, const string &lang, int max)
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Term list walking. */
|
||||
class TermIter {
|
||||
public:
|
||||
Xapian::TermIterator it;
|
||||
Xapian::Database db;
|
||||
};
|
||||
TermIter *Db::termWalkOpen()
|
||||
{
|
||||
if (!m_ndb || !m_ndb->m_isopen)
|
||||
return 0;
|
||||
TermIter *tit = new TermIter;
|
||||
if (tit) {
|
||||
tit->db = m_ndb->m_iswritable ? m_ndb->wdb: m_ndb->db;
|
||||
tit->it = tit->db.allterms_begin();
|
||||
}
|
||||
return tit;
|
||||
}
|
||||
bool Db::termWalkNext(TermIter *tit, string &term)
|
||||
{
|
||||
|
||||
if (tit && tit->it != tit->db.allterms_end()) {
|
||||
term = *(tit->it)++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void Db::termWalkClose(TermIter *tit)
|
||||
{
|
||||
delete tit;
|
||||
}
|
||||
|
||||
|
||||
bool Db::termExists(const string& word)
|
||||
{
|
||||
if (!m_ndb || !m_ndb->m_isopen)
|
||||
return 0;
|
||||
Xapian::Database db = m_ndb->m_iswritable ? m_ndb->wdb: m_ndb->db;
|
||||
if (!db.term_exists(word))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Db::stemDiffers(const string& lang, const string& word,
|
||||
const string& base)
|
||||
{
|
||||
Xapian::Stem stemmer(lang);
|
||||
if (!stemmer.stem_word(word).compare(stemmer.stem_word(base))) {
|
||||
LOGDEB2(("Rcl::Db::stemDiffers: same for %s and %s\n",
|
||||
word.c_str(), base.c_str()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Db::getQueryTerms(list<string>& terms)
|
||||
{
|
||||
if (!m_ndb)
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
*/
|
||||
#ifndef _DB_H_INCLUDED_
|
||||
#define _DB_H_INCLUDED_
|
||||
/* @(#$Id: rcldb.h,v 1.36 2006-09-13 13:53:35 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
/* @(#$Id: rcldb.h,v 1.37 2006-10-09 16:37:08 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
@ -105,6 +105,7 @@ class Doc {
|
||||
|
||||
class AdvSearchData;
|
||||
class Native;
|
||||
class TermIter;
|
||||
|
||||
/**
|
||||
* Wrapper class for the native database.
|
||||
@ -170,9 +171,22 @@ class Db {
|
||||
/** Get a list of existing stemming databases */
|
||||
std::list<std::string> getStemLangs();
|
||||
|
||||
/** Retrieve main database directory */
|
||||
string getDbDir();
|
||||
|
||||
/** Set parameters for synthetic abstract generation */
|
||||
void setAbstractParams(int idxTrunc, int synthLen, int syntCtxLen);
|
||||
|
||||
/** Whole term list walking. */
|
||||
TermIter *termWalkOpen();
|
||||
bool termWalkNext(TermIter *, string &term);
|
||||
void termWalkClose(TermIter *);
|
||||
/** Test term existence */
|
||||
bool termExists(const string& term);
|
||||
/** Test if terms stem to different roots. */
|
||||
bool stemDiffers(const string& lang, const string& term,
|
||||
const string& base);
|
||||
|
||||
private:
|
||||
|
||||
string m_filterTopDir; // Current query filter on subtree top directory
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: stemdb.cpp,v 1.4 2006-09-20 06:21:43 dockes Exp $ (C) 2005 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: stemdb.cpp,v 1.5 2006-10-09 16:37:08 dockes Exp $ (C) 2005 J.F.Dockes";
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -254,7 +254,8 @@ list<string> stemExpand(const string& dbdir, const string& lang,
|
||||
LOGDEB(("stemExpand: %s -> %s\n", stem.c_str(),
|
||||
stringlistdisp(explist).c_str()));
|
||||
} catch (...) {
|
||||
LOGERR(("stemExpand: error accessing stem db\n"));
|
||||
LOGERR(("stemExpand: error accessing stem db. dbdir [%s] lang [%s]\n",
|
||||
dbdir.c_str(), lang.c_str()));
|
||||
explist.push_back(term);
|
||||
return explist;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: execmd.cpp,v 1.17 2006-04-03 09:42:47 dockes Exp $ (C) 2004 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: execmd.cpp,v 1.18 2006-10-09 16:37:08 dockes Exp $ (C) 2004 J.F.Dockes";
|
||||
#endif
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -53,7 +53,9 @@ void ExecCmd::putenv(const string &ea)
|
||||
* raised in the callback */
|
||||
class ExecCmdRsrc {
|
||||
public:
|
||||
// Pipe for data going to the command
|
||||
int pipein[2];
|
||||
// Pipe for data coming out
|
||||
int pipeout[2];
|
||||
pid_t pid;
|
||||
ExecCmdRsrc() {
|
||||
@ -124,26 +126,25 @@ int ExecCmd::doexec(const string &cmd, const list<string>& args,
|
||||
}
|
||||
|
||||
if (e.pid) {
|
||||
// Father process
|
||||
if (input) {
|
||||
close(e.pipein[0]);
|
||||
e.pipein[0] = -1;
|
||||
fcntl(e.pipein[1], F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
if (output) {
|
||||
close(e.pipeout[1]);
|
||||
e.pipeout[1] = -1;
|
||||
fcntl(e.pipeout[0], F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
fd_set readfds, writefds;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
if (input || output) {
|
||||
if (input)
|
||||
fcntl(e.pipein[1], F_SETFL, O_NONBLOCK);
|
||||
if (output)
|
||||
fcntl(e.pipeout[0], F_SETFL, O_NONBLOCK);
|
||||
unsigned int nwritten = 0;
|
||||
int nfds = MAX(e.pipein[1], e.pipeout[0]) + 1;
|
||||
fd_set readfds, writefds;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = m_timeoutMs / 1000;
|
||||
tv.tv_usec = 1000 * (m_timeoutMs % 1000);
|
||||
for(; nfds > 0;) {
|
||||
if (m_cancelRequest)
|
||||
break;
|
||||
@ -240,7 +241,22 @@ int ExecCmd::doexec(const string &cmd, const list<string>& args,
|
||||
e.pipeout[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Do we need to redirect stderr ?
|
||||
if (!m_stderrFile.empty()) {
|
||||
int fd = open(m_stderrFile.c_str(), O_WRONLY|O_CREAT
|
||||
#ifdef O_APPEND
|
||||
|O_APPEND
|
||||
#endif
|
||||
, 0600);
|
||||
if (fd < 0) {
|
||||
close(2);
|
||||
} else {
|
||||
if (fd != 2) {
|
||||
dup2(fd, 2);
|
||||
}
|
||||
lseek(2, 0, 2);
|
||||
}
|
||||
}
|
||||
e.reset();
|
||||
|
||||
// Allocate arg vector (2 more for arg0 + final 0)
|
||||
@ -300,10 +316,10 @@ const char *data = "Une ligne de donnees\n";
|
||||
class MEAdv : public ExecCmdAdvise {
|
||||
public:
|
||||
ExecCmd *cmd;
|
||||
void newData(int) {
|
||||
cerr << "New Data!" << endl;
|
||||
CancelCheck::instance().setCancel();
|
||||
CancelCheck::instance().checkCancel();
|
||||
void newData(int cnt) {
|
||||
cerr << "newData(" << cnt << ")" << endl;
|
||||
// CancelCheck::instance().setCancel();
|
||||
// CancelCheck::instance().checkCancel();
|
||||
// cmd->setCancel();
|
||||
}
|
||||
};
|
||||
@ -325,10 +341,13 @@ int main(int argc, const char **argv)
|
||||
MEAdv adv;
|
||||
adv.cmd = &mexec;
|
||||
mexec.setAdvise(&adv);
|
||||
mexec.setTimeout(500);
|
||||
mexec.setStderr("/tmp/trexecStderr");
|
||||
|
||||
string input, output;
|
||||
input = data;
|
||||
string *ip = 0;
|
||||
//ip = &input;
|
||||
ip = &input;
|
||||
mexec.putenv("TESTVARIABLE1=TESTVALUE1");
|
||||
mexec.putenv("TESTVARIABLE2=TESTVALUE2");
|
||||
mexec.putenv("TESTVARIABLE3=TESTVALUE3");
|
||||
|
||||
@ -16,10 +16,14 @@
|
||||
*/
|
||||
#ifndef _EXECMD_H_INCLUDED_
|
||||
#define _EXECMD_H_INCLUDED_
|
||||
/* @(#$Id: execmd.h,v 1.8 2006-01-30 11:15:28 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
/* @(#$Id: execmd.h,v 1.9 2006-10-09 16:37:08 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#ifndef NO_NAMESPACES
|
||||
using std::list;
|
||||
using std::string;
|
||||
#endif
|
||||
|
||||
/** Callback function object to advise of new data arrival (or just heartbeat) * if cnt is 0 */
|
||||
class ExecCmdAdvise {
|
||||
@ -37,46 +41,66 @@ class ExecCmd {
|
||||
/**
|
||||
* Execute command.
|
||||
*
|
||||
* Both input and output can be specified, and
|
||||
* asynchronous io is used to prevent blocking. This wont work if
|
||||
* input and output need to be synchronized (ie: Q/A), but ok for
|
||||
* filtering.
|
||||
* Both input and output can be specified, and asynchronous
|
||||
* io (select-based) is used to prevent blocking. This will not
|
||||
* work if input and output need to be synchronized (ie: Q/A), but
|
||||
* works ok for filtering.
|
||||
* The function is exception-safe. In case an exception occurs in the
|
||||
* advise callback, fds and pids will be cleaned-up properly.
|
||||
*
|
||||
* @param cmd the program to execute. This must be an absolute file name
|
||||
* or exist in the PATH.
|
||||
* @param args the argument list (NOT including argv[0]).
|
||||
* @param input Input to send to the command.
|
||||
* @param output Output from the command.
|
||||
* @param input Input to send TO the command.
|
||||
* @param output Output FROM the command.
|
||||
* @return the exec ouput status (0 if ok).
|
||||
*/
|
||||
int doexec(const std::string &cmd, const std::list<std::string>& args,
|
||||
const std::string *input = 0,
|
||||
std::string *output = 0);
|
||||
int doexec(const string &cmd, const list<string>& args,
|
||||
const string *input = 0,
|
||||
string *output = 0);
|
||||
/**
|
||||
* Add/replace environment variable before executing command. This should
|
||||
* be called before doexec of course (possibly multiple times for several
|
||||
* variables).
|
||||
* Add/replace environment variable before executing command. This must
|
||||
* be called before doexec to have an effect (possibly multiple
|
||||
* times for several variables).
|
||||
* @param envassign an environment assignment string (name=value)
|
||||
*/
|
||||
void putenv(const std::string &envassign);
|
||||
void putenv(const string &envassign);
|
||||
|
||||
/** Set function object to call whenever new data is available */
|
||||
/**
|
||||
* Set function object to call whenever new data is available or on
|
||||
* select timeout.
|
||||
*/
|
||||
void setAdvise(ExecCmdAdvise *adv) {m_advise = adv;}
|
||||
|
||||
/** Cancel exec. This can be called from another thread or from the
|
||||
* advise callback, which could also raise an exception to accomplish
|
||||
* the same thing
|
||||
/**
|
||||
* Set select timeout in milliseconds. The default is 1 S.
|
||||
*/
|
||||
void setTimeout(int mS) {if (mS > 30) m_timeoutMs = mS;}
|
||||
|
||||
/**
|
||||
* Set destination for stderr data. The default is to let it alone (will
|
||||
* usually go to the terminal or to wherever the desktop messages go).
|
||||
* There is currently no option to put stderr data into a program variable
|
||||
* If the parameter can't be opened for writing, the command's
|
||||
* stderr will be closed.
|
||||
*/
|
||||
void setStderr(const string &stderrFile) {m_stderrFile = stderrFile;}
|
||||
|
||||
/**
|
||||
* Cancel/kill command. This can be called from another thread or
|
||||
* from the advise callback, which could also raise an exception to
|
||||
* accomplish the same thing
|
||||
*/
|
||||
void setCancel() {m_cancelRequest = true;}
|
||||
|
||||
ExecCmd() : m_advise(0), m_cancelRequest(false) {}
|
||||
ExecCmd() : m_advise(0), m_cancelRequest(false), m_timeoutMs(1000) {}
|
||||
|
||||
private:
|
||||
std::list<std::string> m_env;
|
||||
list<string> m_env;
|
||||
ExecCmdAdvise *m_advise;
|
||||
bool m_cancelRequest;
|
||||
bool m_cancelRequest;
|
||||
int m_timeoutMs;
|
||||
string m_stderrFile;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user