|
a/src/aspell/rclaspell.cpp |
|
b/src/aspell/rclaspell.cpp |
1 |
#ifndef TEST_RCLASPELL
|
1 |
#ifndef TEST_RCLASPELL
|
2 |
#ifndef lint
|
2 |
#ifndef lint
|
3 |
static char rcsid[] = "@(#$Id: rclaspell.cpp,v 1.2 2006-10-09 16:37:08 dockes Exp $ (C) 2006 J.F.Dockes";
|
3 |
static char rcsid[] = "@(#$Id: rclaspell.cpp,v 1.3 2006-10-11 14:16:25 dockes Exp $ (C) 2006 J.F.Dockes";
|
4 |
#endif
|
4 |
#endif
|
|
|
5 |
#ifdef HAVE_CONFIG_H
|
|
|
6 |
#include "autoconfig.h"
|
|
|
7 |
#endif
|
|
|
8 |
|
|
|
9 |
#ifdef RCL_USE_ASPELL
|
|
|
10 |
|
5 |
#include <unistd.h>
|
11 |
#include <unistd.h>
|
6 |
#include <dlfcn.h>
|
12 |
#include <dlfcn.h>
|
7 |
#include <iostream>
|
13 |
#include <iostream>
|
8 |
|
14 |
|
9 |
#include "aspell.h"
|
15 |
#include ASPELL_INCLUDE
|
10 |
|
16 |
|
11 |
#include "pathut.h"
|
17 |
#include "pathut.h"
|
12 |
#include "execmd.h"
|
18 |
#include "execmd.h"
|
13 |
#include "rclaspell.h"
|
19 |
#include "rclaspell.h"
|
14 |
|
20 |
|
|
|
21 |
// Stuff that we don't wish to see in the .h (possible sysdeps, etc.)
|
15 |
class AspellData {
|
22 |
class AspellData {
|
16 |
public:
|
23 |
public:
|
17 |
AspellData() : m_handle(0) {}
|
24 |
AspellData() : m_handle(0) {}
|
18 |
~AspellData() {
|
25 |
~AspellData() {
|
19 |
if (m_handle)
|
26 |
if (m_handle)
|
|
... |
|
... |
60 |
#define NMTOPTR(NM, TP) \
|
67 |
#define NMTOPTR(NM, TP) \
|
61 |
if ((aapi.NM = TP dlsym(m_data->m_handle, #NM)) == 0) { \
|
68 |
if ((aapi.NM = TP dlsym(m_data->m_handle, #NM)) == 0) { \
|
62 |
badnames += #NM + string(" "); \
|
69 |
badnames += #NM + string(" "); \
|
63 |
}
|
70 |
}
|
64 |
|
71 |
|
65 |
bool Aspell::init(const string &basedir, string &reason)
|
72 |
const char *aspell_progs[] = {
|
|
|
73 |
#ifdef ASPELL_PROG
|
|
|
74 |
ASPELL_PROG ,
|
|
|
75 |
#endif
|
|
|
76 |
"/usr/local/bin/aspell",
|
|
|
77 |
"/usr/bin/aspell"
|
|
|
78 |
};
|
|
|
79 |
|
|
|
80 |
bool Aspell::init(string &reason)
|
66 |
{
|
81 |
{
|
|
|
82 |
delete m_data;
|
67 |
if (m_data == 0)
|
83 |
m_data = 0;
|
|
|
84 |
// Language: we get this from the configuration, else from the NLS
|
|
|
85 |
// environment. The aspell language names used for selecting language
|
|
|
86 |
// definition files (used to create dictionaries) are like en, fr
|
|
|
87 |
if (!m_config->getConfParam("aspellLanguage", m_lang)) {
|
|
|
88 |
string lang = "en";
|
|
|
89 |
const char *cp;
|
|
|
90 |
if (cp = getenv("LC_ALL"))
|
|
|
91 |
lang = cp;
|
|
|
92 |
else if (cp = getenv("LANG"))
|
|
|
93 |
lang = cp;
|
|
|
94 |
if (!lang.compare("C"))
|
|
|
95 |
lang = "en";
|
|
|
96 |
m_lang = lang.substr(0, lang.find_first_of("_"));
|
|
|
97 |
} else {
|
|
|
98 |
if (!m_lang.compare("disable")) {
|
|
|
99 |
reason = "Aspell disabled in recoll configuration file";
|
|
|
100 |
return false;
|
|
|
101 |
}
|
|
|
102 |
}
|
|
|
103 |
|
68 |
m_data = new AspellData;
|
104 |
m_data = new AspellData;
|
69 |
if (m_data->m_handle) {
|
105 |
for (unsigned int i = 0; i < sizeof(aspell_progs) / sizeof(char*); i++) {
|
70 |
dlclose(m_data->m_handle);
|
106 |
if (access(aspell_progs[i], X_OK) == 0) {
|
71 |
m_data->m_handle = 0;
|
107 |
m_data->m_exec = aspell_progs[i];
|
|
|
108 |
break;
|
|
|
109 |
}
|
72 |
}
|
110 |
}
|
73 |
|
111 |
if (m_data->m_exec.empty()) {
|
74 |
m_data->m_exec = path_cat(basedir, "bin");
|
112 |
reason = "aspell program not found or not executable";
|
75 |
m_data->m_exec = path_cat(m_data->m_exec, "aspell");
|
|
|
76 |
if (access(m_data->m_exec.c_str(), X_OK) != 0) {
|
|
|
77 |
reason = m_data->m_exec + " not found or not executable";
|
|
|
78 |
return false;
|
113 |
return false;
|
79 |
}
|
114 |
}
|
|
|
115 |
|
|
|
116 |
// For now, the aspell library has to live under the same prefix as the
|
|
|
117 |
// aspell program.
|
|
|
118 |
string aspellPrefix = path_getfather(path_getfather(m_data->m_exec));
|
80 |
string lib = path_cat(basedir, "lib");
|
119 |
string lib = path_cat(aspellPrefix, "lib");
|
81 |
lib = path_cat(lib, "libaspell.so");
|
120 |
lib = path_cat(lib, "libaspell.so");
|
82 |
if ((m_data->m_handle = dlopen(lib.c_str(), RTLD_LAZY)) == 0) {
|
121 |
if ((m_data->m_handle = dlopen(lib.c_str(), RTLD_LAZY)) == 0) {
|
83 |
reason = "Could not open shared library [";
|
122 |
reason = "Could not open shared library [";
|
84 |
reason += lib + "] : " + dlerror();
|
123 |
reason += lib + "] : " + dlerror();
|
85 |
return false;
|
124 |
return false;
|
|
... |
|
... |
118 |
|
157 |
|
119 |
if (!badnames.empty()) {
|
158 |
if (!badnames.empty()) {
|
120 |
reason = string("Aspell::init: symbols not found:") + badnames;
|
159 |
reason = string("Aspell::init: symbols not found:") + badnames;
|
121 |
return false;
|
160 |
return false;
|
122 |
}
|
161 |
}
|
|
|
162 |
|
123 |
return true;
|
163 |
return true;
|
124 |
}
|
164 |
}
|
125 |
|
165 |
|
126 |
bool Aspell::ok()
|
166 |
bool Aspell::ok()
|
127 |
{
|
167 |
{
|
128 |
return m_data != 0 && m_data->m_handle != 0;
|
168 |
return m_data != 0 && m_data->m_handle != 0;
|
129 |
}
|
169 |
}
|
130 |
|
170 |
|
131 |
string Aspell::dicPath()
|
171 |
string Aspell::dicPath()
|
132 |
{
|
172 |
{
|
133 |
return path_cat(m_conf->getConfDir(),
|
173 |
return path_cat(m_config->getConfDir(),
|
134 |
string("aspdict.") + m_lang + string(".rws"));
|
174 |
string("aspdict.") + m_lang + string(".rws"));
|
135 |
}
|
175 |
}
|
136 |
|
176 |
|
137 |
bool Aspell::buildDict(Rcl::Db &db, string &reason)
|
177 |
bool Aspell::buildDict(Rcl::Db &db, string &reason)
|
138 |
{
|
178 |
{
|
139 |
string term;
|
179 |
if (!ok())
|
140 |
|
|
|
141 |
// Il faut nettoyer la liste, peut-etre faire un tri unique (verifier),
|
|
|
142 |
// puis construire le dico
|
|
|
143 |
Rcl::TermIter *tit = db.termWalkOpen();
|
|
|
144 |
if (tit == 0) {
|
|
|
145 |
reason = "termWalkOpen failed\n";
|
|
|
146 |
return false;
|
180 |
return false;
|
147 |
}
|
181 |
|
148 |
ExecCmd aspell;
|
182 |
// We create the dictionary by executing the aspell command:
|
149 |
list<string> args;
|
|
|
150 |
// aspell --lang=[lang] create master [dictApath]
|
183 |
// aspell --lang=[lang] create master [dictApath]
|
|
|
184 |
ExecCmd aspell;
|
|
|
185 |
list<string> args;
|
151 |
args.push_back(string("--lang=")+ m_lang);
|
186 |
args.push_back(string("--lang=")+ m_lang);
|
152 |
args.push_back("create");
|
187 |
args.push_back("create");
|
153 |
args.push_back("master");
|
188 |
args.push_back("master");
|
154 |
args.push_back(dicPath());
|
189 |
args.push_back(dicPath());
|
155 |
// aspell.setStderr("/dev/null");
|
190 |
aspell.setStderr("/dev/null");
|
|
|
191 |
|
|
|
192 |
Rcl::TermIter *tit = db.termWalkOpen();
|
|
|
193 |
if (tit == 0) {
|
|
|
194 |
reason = "termWalkOpen failed\n";
|
|
|
195 |
return false;
|
|
|
196 |
}
|
156 |
string allterms;
|
197 |
string allterms, term;
|
157 |
while (db.termWalkNext(tit, term)) {
|
198 |
while (db.termWalkNext(tit, term)) {
|
158 |
// Filter out terms beginning with upper case (special stuff) and
|
199 |
// Filter out terms beginning with upper case (special stuff) and
|
159 |
// containing numbers
|
200 |
// containing numbers
|
160 |
if (term.empty())
|
201 |
if (term.empty())
|
161 |
continue;
|
202 |
continue;
|
162 |
if ('A' <= term.at(0) && term.at(0) <= 'Z')
|
203 |
if ('A' <= term.at(0) && term.at(0) <= 'Z')
|
163 |
continue;
|
204 |
continue;
|
164 |
if (term.find_first_of("0123456789+-._@") != string::npos)
|
205 |
if (term.find_first_of("0123456789+-._@") != string::npos)
|
165 |
continue;
|
206 |
continue;
|
166 |
allterms += term + "\n";
|
207 |
allterms += term + "\n";
|
167 |
// std::cout << "[" << term << "]" << std::endl;
|
208 |
// std::cout << "[" << term << "]" << std::endl;
|
168 |
}
|
209 |
}
|
169 |
db.termWalkClose(tit);
|
210 |
db.termWalkClose(tit);
|
170 |
aspell.doexec(m_data->m_exec, args, &allterms);
|
211 |
if (aspell.doexec(m_data->m_exec, args, &allterms)) {
|
|
|
212 |
reason = string("aspell dictionary creation command failed. Check the language data files for lang = ") + m_lang;
|
|
|
213 |
return false;
|
|
|
214 |
}
|
171 |
return true;
|
215 |
return true;
|
172 |
}
|
216 |
}
|
173 |
|
217 |
|
174 |
|
218 |
|
175 |
bool Aspell::suggest(Rcl::Db &db,
|
219 |
bool Aspell::suggest(Rcl::Db &db,
|
176 |
string &term, list<string> &suggestions, string &reason)
|
220 |
string &term, list<string> &suggestions, string &reason)
|
177 |
{
|
221 |
{
|
|
|
222 |
if (!ok())
|
|
|
223 |
return false;
|
|
|
224 |
|
178 |
AspellCanHaveError *ret;
|
225 |
AspellCanHaveError *ret;
|
179 |
AspellSpeller *speller;
|
226 |
AspellSpeller *speller;
|
180 |
AspellConfig *config;
|
227 |
AspellConfig *config;
|
181 |
|
228 |
|
182 |
config = aapi.new_aspell_config();
|
229 |
config = aapi.new_aspell_config();
|
|
... |
|
... |
219 |
aapi.delete_aspell_speller(speller);
|
266 |
aapi.delete_aspell_speller(speller);
|
220 |
// Config belongs to speller here? aapi.delete_aspell_config(config);
|
267 |
// Config belongs to speller here? aapi.delete_aspell_config(config);
|
221 |
return true;
|
268 |
return true;
|
222 |
}
|
269 |
}
|
223 |
|
270 |
|
|
|
271 |
#endif // RCL_USE_ASPELL
|
224 |
|
272 |
|
225 |
#else // TEST_RCLASPELL test driver ->
|
273 |
#else // TEST_RCLASPELL test driver ->
|
|
|
274 |
|
|
|
275 |
#ifdef HAVE_CONFIG_H
|
|
|
276 |
#include "autoconfig.h"
|
|
|
277 |
#endif
|
|
|
278 |
|
|
|
279 |
#ifdef RCL_USE_ASPELL
|
226 |
|
280 |
|
227 |
#include <stdio.h>
|
281 |
#include <stdio.h>
|
228 |
#include <stdlib.h>
|
282 |
#include <stdlib.h>
|
229 |
#include <unistd.h>
|
283 |
#include <unistd.h>
|
230 |
#include <errno.h>
|
284 |
#include <errno.h>
|
|
... |
|
... |
302 |
if (!rcldb.open(dbdir, Rcl::Db::DbRO, 0)) {
|
356 |
if (!rcldb.open(dbdir, Rcl::Db::DbRO, 0)) {
|
303 |
fprintf(stderr, "Could not open database in %s\n", dbdir.c_str());
|
357 |
fprintf(stderr, "Could not open database in %s\n", dbdir.c_str());
|
304 |
exit(1);
|
358 |
exit(1);
|
305 |
}
|
359 |
}
|
306 |
|
360 |
|
307 |
string lang = "en";
|
|
|
308 |
|
|
|
309 |
Aspell aspell(rclconfig, lang);
|
361 |
Aspell aspell(rclconfig);
|
310 |
|
362 |
|
311 |
if (!aspell.init("/usr/local", reason)) {
|
363 |
if (!aspell.init(reason)) {
|
312 |
cerr << "Init failed: " << reason << endl;
|
364 |
cerr << "Init failed: " << reason << endl;
|
313 |
exit(1);
|
365 |
exit(1);
|
314 |
}
|
366 |
}
|
315 |
if (op_flags & OPT_b) {
|
367 |
if (op_flags & OPT_b) {
|
316 |
if (!aspell.buildDict(rcldb, reason)) {
|
368 |
if (!aspell.buildDict(rcldb, reason)) {
|
|
... |
|
... |
329 |
cout << *it << endl;
|
381 |
cout << *it << endl;
|
330 |
}
|
382 |
}
|
331 |
}
|
383 |
}
|
332 |
exit(0);
|
384 |
exit(0);
|
333 |
}
|
385 |
}
|
|
|
386 |
#else
|
|
|
387 |
int main(int argc, char **argv)
|
|
|
388 |
{return 1;}
|
|
|
389 |
#endif // RCL_USE_ASPELL
|
334 |
|
390 |
|
335 |
#endif // TEST_RCLASPELL test driver
|
391 |
#endif // TEST_RCLASPELL test driver
|