]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/TDictionary.cc
* added default dictionary/stylesheet paths
[helm.git] / helm / DEVEL / mathml_editor / src / TDictionary.cc
1 /* This file is part of EdiTeX, an editor of mathematical
2  * expressions based on TeX syntax.
3  * 
4  * Copyright (C) 2002-2003 Luca Padovani <lpadovan@cs.unibo.it>,
5  *                    2003 Paolo Marinelli <pmarinel@cs.unibo.it>.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * For more information, please visit the project's home page
22  * http://helm.cs.unibo.it/editex/
23  * or send an email to <lpadovan@cs.unibo.it>
24  */
25
26 #include <sstream>
27
28 #include "dom.hh"
29 #include "config.dirs"
30 #include "TDictionary.hh"
31 #include "TTokenizer.hh"
32 #include "CLoggerConsole.hh"
33
34 static TDictionary::Entry undefinedEntry;
35
36 static std::string
37 getURIBase(const std::string& uri)
38 {
39   std::string::size_type slash = uri.rfind('/');
40   if (slash != std::string::npos) return uri.substr(0, slash + 1);
41   else return "";
42 }
43
44 static std::string
45 getURIName(const std::string& uri)
46 {
47   std::string::size_type slash = uri.rfind('/');
48   if (slash != std::string::npos) return uri.substr(slash + 1, uri.size());
49   else return uri;
50 }
51
52 std::string
53 TDictionary::getDefaultDictionaryPath()
54 {
55   return PKGDATADIR"/dictionary-tex.xml";
56 }
57
58 void
59 TDictionary::load(const std::string& uri)
60 {
61   load(getURIName(uri), getURIBase(uri));
62 }
63
64 void
65 TDictionary::load(const std::string& name, const std::string& base)
66 {
67   logger.debug("Dictionary: loading `" + base + name + "'");
68
69   DOM::DOMImplementation di;
70   DOM::Document doc = di.createDocumentFromURI((base + name).c_str());
71   assert(doc);
72   load(doc, base);
73 }
74
75 void
76 TDictionary::load(const DOM::Document& doc, const std::string& base)
77 {
78   assert(doc);
79
80   DOM::Element root = doc.get_documentElement();
81   assert(root);
82
83   CLoggerConsole logger;
84   TTokenizer tokenizer(logger);
85
86   for (DOM::Node p = root.get_firstChild(); p; p = p.get_nextSibling())
87     if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "include")
88       {
89         DOM::Element el = p;
90         assert(el);
91         if (el.hasAttribute("href"))
92           {
93             // WARNING: this may result into an infinite loop!
94             std::string href = el.getAttribute("href");
95             std::string newBase = getURIBase(href);
96             std::string newName = getURIName(href);
97             if (newBase != "") load(newName, newBase);
98             else load(newName, base);
99           }
100         else
101           logger.warning("Dictionary: include statement with no href attribute (ignored)");
102       }
103     else if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "entry")
104       {
105         DOM::Element el = p;
106         assert(el);
107         assert(el.hasAttribute("name"));
108
109         std::string name = el.getAttribute("name");
110         if (entries.find(name) != entries.end())
111           logger.info("Dictionary: `" + name + "' is being redefined");
112
113         Entry entry;
114
115         if (el.hasAttribute("class"))
116           {
117             std::string cls = el.getAttribute("class");
118             if (cls == "o") entry.cls = OPERATOR;
119             else if (cls == "i") entry.cls = IDENTIFIER;
120             else if (cls == "n") entry.cls == NUMBER;
121             else entry.cls = MACRO;
122           }
123         else
124           entry.cls = MACRO;
125
126         if (el.hasAttribute("val"))
127           {
128             entry.value = el.getAttribute("val");
129             if (entry.cls == MACRO)
130               logger.warning("Dictionary: `" + name + "' has a specified value, but is classified as macro");
131           }
132
133         if (el.hasAttribute("pattern"))
134           {
135             if (entry.cls != MACRO)
136               logger.warning("Dictionary: `" + name + "' has a specified pattern, but is not classified as macro");
137
138             std::string pattern = el.getAttribute("pattern");
139             if (pattern == "{}")
140               entry.leftOpen = entry.rightOpen = 1;
141             else if (pattern == "{")
142               entry.leftOpen = 1;
143             else if (pattern == "}")
144               entry.rightOpen = 1;
145             else
146               entry.pattern = tokenizer.tokenize(pattern);
147           }
148
149 #if 0
150         if (el.hasAttribute("infix"))
151           {
152             std::istringstream is(el.getAttribute("infix"));
153             unsigned infix;
154             is >> infix;
155             entry.infix = infix;
156             if (!el.hasAttribute("prefix")) entry.prefix = infix;
157             if (!el.hasAttribute("postfix")) entry.postfix = infix;
158           }
159
160         if (el.hasAttribute("prefix"))
161           {
162             std::istringstream is(el.getAttribute("prefix"));
163             unsigned prefix;
164             is >> prefix;
165             entry.prefix = prefix;
166             if (!el.hasAttribute("infix"))
167               {
168                 entry.infix = prefix;
169                 if (!el.hasAttribute("postfix")) entry.postfix = prefix;
170               }
171           }
172
173         if (el.hasAttribute("postfix"))
174           {
175             std::istringstream is(el.getAttribute("postfix"));
176             unsigned postfix;
177             is >> postfix;
178             entry.postfix = postfix;
179             if (!el.hasAttribute("infix"))
180               {
181                 entry.infix = postfix;
182                 if (!el.hasAttribute("prefix")) entry.prefix = postfix;
183               }
184           }
185 #endif
186
187         if (el.hasAttribute("limits"))
188           {
189             std::istringstream is(el.getAttribute("limits"));
190             unsigned limits;
191             is >> limits;
192             entry.limits = limits;
193           }
194
195         if (el.hasAttribute("embellishment"))
196           {
197             std::istringstream is(el.getAttribute("embellishment"));
198             unsigned embellishment;
199             is >> embellishment;
200             entry.embellishment = embellishment;
201           }
202
203         if (el.hasAttribute("delimiter"))
204           {
205             if (entry.cls != OPERATOR && !entry.embellishment)
206               logger.warning("Dictionary: `" + name + "' delimiter ignored for non-operator");
207
208             std::istringstream is(el.getAttribute("delimiter"));
209             unsigned delimiter;
210             is >> delimiter;
211             entry.delimiter = delimiter;
212           }
213
214         if (el.hasAttribute("table"))
215           {
216             if (entry.cls != MACRO)
217               logger.warning("Dictionary: `" + name + "' table ignored for non-macro");
218
219             std::istringstream is(el.getAttribute("table"));
220             unsigned table;
221             is >> table;
222             entry.table = table;
223           }
224
225         entries[name] = entry;
226       }
227 }
228
229 const TDictionary::Entry&
230 TDictionary::find(const std::string& name) const
231 {
232   Dictionary::const_iterator p = entries.find(name);
233   if (p != entries.end()) return (*p).second;
234   else
235     {
236       logger.warning("unknown entry `" + name + "'");
237       return undefinedEntry;
238     }
239 }
240
241 std::string
242 TDictionary::complete(const std::string prefix, std::list<std::string>& complete_list) const
243 {
244   bool no_match = true;
245   std::string new_prefix = "";
246   for (Dictionary::const_iterator i = entries.begin(); i != entries.end(); i++)
247     {
248       if ((*i).first.find(prefix) == 0)
249         {
250           complete_list.push_front((*i).first);
251           if (no_match)
252             {
253               // it's the first match
254               no_match = false;
255               new_prefix = (*i).first;
256             }
257           else
258             {
259               // in this case, new_prefix has been set yet.
260               std::string s1 = (*i).first.substr(prefix.length()); // s1 is the high part of the matching string
261               std::string s2 = new_prefix.substr(prefix.length()); // s2 is the high part of new_prefix
262 #if 0
263               long j = 0; // it's the number of common characters
264               while (s1[j] == s2[j]) j++;
265 #endif
266               std::string::const_iterator i1 = s1.begin();
267               std::string::const_iterator i2 = s2.begin();
268               while (i1 != s1.end() && i2 != s2.end() && *i1 == *i2) i1++, i2++;
269               new_prefix = prefix + s1.substr(0, i1 - s1.begin());
270               //new_prefix = (j) ? prefix + s1.substr(0, i1 - s1.begin()) : prefix;
271             }
272         }
273     }
274
275   return new_prefix;
276 }
277
278 bool
279 TDictionary::Entry::paramDelimited(unsigned i) const
280 {
281   assert(i < pattern.size());
282   assert(pattern[i].category == TToken::PARAMETER);
283   // a parameter is delimited if it is NOT the last one
284   // AND the next argument is not a parameter
285   return i + 1 < pattern.size() && pattern[i + 1].category != TToken::PARAMETER;
286 }
287
288 bool
289 TDictionary::Entry::lastDelimiter(unsigned i) const
290 {
291   assert(i < pattern.size());
292   assert(pattern[i].category != TToken::PARAMETER);
293   // a token is the last delimiter if it is the last token 
294   // of the pattern or if the next token is a parameter)
295   return i + 1 == pattern.size() || pattern[i + 1].category == TToken::PARAMETER;
296 }
297
298 unsigned
299 TDictionary::Entry::previousParam(unsigned i) const
300 {
301   // this method return the position in the pattern of the 
302   // parameter placed in a position preceding i.
303   // If no preceding i parameter present, the method return
304   // pattern.size().
305   // To know the position of the last parameter, call this 
306   // method with i == pattern.size()
307   unsigned j = i - 1;
308
309   while (pattern[j].category != TToken::PARAMETER)
310     {
311       if (j) j--;
312       else return pattern.size();
313     }
314   return j;
315 }