Switch to unified view

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