]> git.lyx.org Git - features.git/blob - src/Thesaurus.cpp
add check for version 1 index files - skip them if present
[features.git] / src / Thesaurus.cpp
1 /**
2  * \file Thesaurus.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "Thesaurus.h"
15
16 #include "LyXRC.h"
17
18 #include "support/FileNameList.h"
19 #include "support/Package.h"
20 #include "support/debug.h"
21 #include "support/filetools.h"
22 #include "support/gettext.h"
23 #include "support/lstrings.h"
24 #include "support/os.h"
25
26 #include "support/mythes/mythes.hxx"
27
28 #include "frontends/alert.h"
29
30 #include <algorithm>
31 #include <cstring>
32 #include <fstream>
33
34 using namespace std;
35 using namespace lyx::support;
36 using namespace lyx::support::os;
37
38 namespace lyx {
39
40 namespace {
41
42 typedef std::map<docstring, MyThes *> Thesauri;
43
44 } // namespace anon
45
46 struct Thesaurus::Private
47 {
48         ~Private()
49         {
50                 for (Thesauri::iterator it = thes_.begin();
51                      it != thes_.end(); ++it) {
52                         delete it->second;
53                 }
54         }
55         ///
56         bool thesaurusAvailable(docstring const & lang) const
57         {
58                 for (Thesauri::const_iterator it = thes_.begin();
59                         it != thes_.end(); ++it) {
60                                 if (it->first == lang)
61                                         if (it->second)
62                                                 return true;
63                 }
64                 return false;
65         }
66
67         ///
68         typedef std::pair<std::string, std::string> ThesFiles;
69         ///
70         ThesFiles getThesaurus(string const & path, docstring const & lang);
71         ThesFiles getThesaurus(docstring const & lang);
72         /// add a thesaurus to the list
73         bool addThesaurus(docstring const & lang);
74
75         /// the thesauri
76         Thesauri thes_;
77
78         /// the location below system/user directory
79         /// there the data+idx files lookup will happen
80         const string dataDirectory(void) { return "thes"; }
81
82 };
83
84
85 pair<string,string> Thesaurus::Private::getThesaurus(string const & path, docstring const & lang)
86 {
87         FileName base(path);
88         if (!base.isDirectory()) {
89                 return make_pair(string(), string());
90         }
91         FileNameList const idx_files = base.dirList("idx");
92         FileNameList const data_files = base.dirList("dat");
93         string idx;
94         string data;
95         string basename;
96
97         LYXERR(Debug::FILES, "thesaurus path: " << path);
98         for (FileNameList::const_iterator it = idx_files.begin(); it != idx_files.end(); ++it) {
99                 basename = it->onlyFileNameWithoutExt();
100                 if (contains(basename, to_ascii(lang))) {
101                         ifstream ifs(it->absFileName().c_str());
102                         if (ifs) {
103                                 string s;
104                                 getline(ifs,s);
105                                 if (s.find_first_of(',') != string::npos) {
106                                         LYXERR(Debug::FILES, "ignore version1 thesaurus idx file: " << it->absFileName());
107                                         continue;
108                                 }
109                         }
110                         idx = it->absFileName();
111                         LYXERR(Debug::FILES, "selected thesaurus idx file: " << idx);
112                         break;
113                 }
114         }
115         if (idx.empty()) {
116                 return make_pair(string(), string());
117         }
118         for (support::FileNameList::const_iterator it = data_files.begin(); it != data_files.end(); ++it) {
119                 if (contains(it->onlyFileName(), basename)) {
120                         data = it->absFileName();
121                         LYXERR(Debug::FILES, "selected thesaurus data file: " << data);
122                         break;
123                 }
124         }
125         return make_pair(idx, data);
126 }
127
128
129 pair<string,string> Thesaurus::Private::getThesaurus(docstring const & lang)
130 {
131         string const thes_path = external_path(lyxrc.thesaurusdir_path);
132         pair<string,string> result ;
133
134         if (thesaurusAvailable(lang))
135                 return make_pair(string(), string());
136
137         if (!thes_path.empty()) {
138                 result = getThesaurus(thes_path, lang);
139         }
140         if (result.first.empty() || result.second.empty()) {
141                 string const sys_path = external_path(addName(lyx::support::package().system_support().absFileName(),dataDirectory())) ;
142                 result = getThesaurus(sys_path, lang);
143         }
144         if (result.first.empty() || result.second.empty()) {
145                 string const user_path = external_path(addName(lyx::support::package().user_support().absFileName(),dataDirectory())) ;
146                 result = getThesaurus(user_path, lang);
147         }
148         return result;
149 }
150
151
152 bool Thesaurus::Private::addThesaurus(docstring const & lang)
153 {
154         if (thesaurusAvailable(lang))
155                 return true;
156
157         ThesFiles files = getThesaurus(lang);
158         string const idx = files.first;
159         string const data = files.second;
160
161         if (idx.empty() || data.empty())
162                 return false;
163
164         char const * af = idx.c_str();
165         char const * df = data.c_str();
166         thes_[lang] = new MyThes(af, df);
167         return true;
168 }
169
170
171 bool Thesaurus::thesaurusAvailable(docstring const & lang) const
172 {
173         return d->thesaurusAvailable(lang);
174 }
175
176
177 bool Thesaurus::thesaurusInstalled(docstring const & lang) const
178 {
179         if (thesaurusAvailable(lang))
180                 return true;
181         pair<string, string> files = d->getThesaurus(lang);
182         return (!files.first.empty() && !files.second.empty());
183 }
184
185
186 Thesaurus::Meanings Thesaurus::lookup(docstring const & t, docstring const & lang)
187 {
188         Meanings meanings;
189         MyThes * mythes = 0;
190
191         if (!d->addThesaurus(lang))
192                 return meanings;
193
194         for (Thesauri::const_iterator it = d->thes_.begin();
195              it != d->thes_.end(); ++it) {
196                 if (it->first == lang) {
197                         mythes = it->second;
198                         break;
199                 }
200         }
201
202         if (!mythes)
203                 return meanings;
204
205         string const encoding = mythes->get_th_encoding();
206         
207         mentry * pmean;
208         string const text = to_iconv_encoding(support::lowercase(t), encoding);
209         int len = strlen(text.c_str());
210         int count = mythes->Lookup(text.c_str(), len, &pmean);
211         if (!count)
212                 return meanings;
213
214         // don't change value of pmean or count
215         // they are needed for the CleanUpAfterLookup routine
216         mentry * pm = pmean;
217         docstring meaning;
218         docstring ret;
219         for (int i = 0; i < count; i++) {
220                 meaning = from_iconv_encoding(string(pm->defn), encoding);
221                 // remove silly item
222                 if (support::prefixIs(meaning, '-'))
223                         meaning = support::ltrim(meaning, "- ");
224                 for (int j = 0; j < pm->count; j++) {
225                         ret = from_iconv_encoding(string(pm->psyns[j]), encoding);
226                 }
227         meanings[meaning].push_back(ret);
228         pm++;
229         }
230         // now clean up all allocated memory
231         mythes->CleanUpAfterLookup(&pmean, count);
232
233         for (Meanings::iterator it = meanings.begin();
234              it != meanings.end(); ++it)
235                 sort(it->second.begin(), it->second.end());
236
237         return meanings;
238 }
239
240
241 Thesaurus::Thesaurus() : d(new Thesaurus::Private)
242 {
243 }
244
245
246 Thesaurus::~Thesaurus()
247 {
248         delete d;
249 }
250
251 // Global instance
252 Thesaurus thesaurus;
253
254
255 } // namespace lyx