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