1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2009-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_text_engine_h)
27 #define octave_text_engine_h 1
28 
29 #include "octave-config.h"
30 
31 #include <memory>
32 #include <string>
33 
34 #include "base-list.h"
35 #include "caseless-str.h"
36 #include "dMatrix.h"
37 
38 namespace octave
39 {
40   class text_element;
41   class text_element_string;
42   class text_element_symbol;
43   class text_element_list;
44   class text_element_subscript;
45   class text_element_superscript;
46   class text_element_combined;
47   class text_element_fontname;
48   class text_element_fontsize;
49   class text_element_fontstyle;
50   class text_element_color;
51 
52   class text_processor;
53 
54   class
55   OCTINTERP_API
56   text_element
57   {
58   public:
text_element(void)59     text_element (void) { }
60 
61     virtual ~text_element (void) = default;
62 
63     virtual void accept (text_processor& p) = 0;
64 
65   private:
66     text_element (const text_element&);
67   };
68 
69   class
70   OCTINTERP_API
71   text_element_string : public text_element
72   {
73   public:
74     text_element_string (const std::string& s = "")
text_element()75       : text_element (), str (s) { }
76 
77     ~text_element_string (void) = default;
78 
string_value(void)79     std::string string_value (void) const { return str; }
80 
81     void accept (text_processor& p);
82 
83   private:
84     std::string str;
85 
86   private:
87     text_element_string (const text_element_string &);
88   };
89 
90   class
91   OCTINTERP_API
92   text_element_symbol : public text_element
93   {
94   public:
95     enum { invalid_code = 0xFFFFFFFFU };
96 
97   public:
text_element_symbol(int sym)98     text_element_symbol (int sym)
99       : text_element (), symbol (sym) { }
100 
101     ~text_element_symbol (void) = default;
102 
get_symbol(void)103     int get_symbol (void) const { return symbol; }
104 
105     uint32_t get_symbol_code (void) const;
106 
107     void accept (text_processor& p);
108 
109   private:
110     int symbol;
111   };
112 
113   class
114   OCTINTERP_API
115   text_element_list
116     : public text_element, public base_list<text_element *>
117   {
118   public:
text_element_list(void)119     text_element_list (void)
120       : text_element (), base_list<text_element*> () { }
121 
text_element_list(text_element * e)122     text_element_list (text_element *e)
123       : text_element (), base_list<text_element*> ()
124     {
125       push_back (e);
126     }
127 
~text_element_list(void)128     ~text_element_list (void)
129     {
130       while (! empty ())
131         {
132           auto it = begin ();
133           delete (*it);
134           erase (it);
135         }
136     }
137 
138     void accept (text_processor& p);
139   };
140 
141   class
142   OCTINTERP_API
143   text_element_subscript : public text_element
144   {
145   public:
text_element_subscript(text_element * e)146     text_element_subscript (text_element *e)
147       : text_element (), elem (e) { }
148 
text_element_subscript(char c)149     text_element_subscript (char c)
150       : text_element ()
151     { elem = new text_element_string (std::string (1, c)); }
152 
~text_element_subscript(void)153     ~text_element_subscript (void)
154     { delete elem; }
155 
156     void accept (text_processor& p);
157 
get_element(void)158     text_element * get_element (void) { return elem; }
159 
160   private:
161     text_element *elem;
162 
163   private:
164     text_element_subscript (void);
165   };
166 
167   class
168   OCTINTERP_API
169   text_element_superscript : public text_element
170   {
171   public:
text_element_superscript(text_element * e)172     text_element_superscript (text_element *e)
173       : text_element (), elem (e) { }
174 
text_element_superscript(char c)175     text_element_superscript (char c)
176       : text_element ()
177     { elem = new text_element_string (std::string (1, c)); }
178 
~text_element_superscript(void)179     ~text_element_superscript (void)
180     { delete elem; }
181 
182     void accept (text_processor& p);
183 
get_element(void)184     text_element * get_element (void) { return elem; }
185 
186   private:
187     text_element *elem;
188 
189   private:
190     text_element_superscript (void);
191   };
192 
193   class
194   OCTINTERP_API
195   text_element_combined : public text_element_list
196   {
197   public:
text_element_combined(text_element * e)198     text_element_combined (text_element *e)
199       : text_element_list (e) { }
200 
text_element_combined(text_element * e1,text_element * e2)201     text_element_combined (text_element *e1, text_element *e2)
202       : text_element_list(e1)
203     { push_back (e2); }
204 
205     void accept (text_processor& p);
206   };
207 
208   class
209   OCTINTERP_API
210   text_element_fontstyle : public text_element
211   {
212   public:
213     enum fontstyle
214     {
215       normal,
216       bold,
217       italic,
218       oblique
219     };
220 
text_element_fontstyle(fontstyle st)221     text_element_fontstyle (fontstyle st)
222       : text_element (), style (st) { }
223 
224     ~text_element_fontstyle (void) = default;
225 
get_fontstyle(void)226     fontstyle get_fontstyle (void) const { return style; }
227 
228     void accept (text_processor& p);
229 
230   private:
231     fontstyle style;
232 
233   private:
234     text_element_fontstyle (void);
235   };
236 
237   class
238   OCTINTERP_API
239   text_element_fontname : public text_element
240   {
241   public:
text_element_fontname(const std::string & fname)242     text_element_fontname (const std::string& fname)
243       : text_element (), name (fname) { }
244 
245     ~text_element_fontname (void) = default;
246 
get_fontname(void)247     const std::string& get_fontname (void) const { return name; }
248 
249     void accept (text_processor& p);
250 
251   private:
252     std::string name;
253 
254   private:
255     text_element_fontname (void);
256   };
257 
258   class
259   OCTINTERP_API
260   text_element_fontsize : public text_element
261   {
262   public:
text_element_fontsize(double fsize)263     text_element_fontsize (double fsize)
264       : text_element (), size (fsize) { }
265 
266     ~text_element_fontsize (void) = default;
267 
get_fontsize(void)268     double get_fontsize (void) const { return size; }
269 
270     void accept (text_processor& p);
271 
272   private:
273     double size;
274 
275   private:
276     text_element_fontsize (void);
277   };
278 
279   class
280   OCTINTERP_API
281   text_element_color : public text_element
282   {
283   public:
text_element_color(double r,double g,double b)284     text_element_color (double r, double g, double b)
285       : text_element (), rgb (1, 3, 0.0)
286     {
287       rgb(0) = r;
288       rgb(1) = g;
289       rgb(2) = b;
290     }
291 
text_element_color(const std::string & cname)292     text_element_color (const std::string& cname)
293       : text_element (), rgb (1, 3, 0.0)
294     {
295 #define ASSIGN_COLOR(r,g,b) { rgb(0) = r; rgb(1) = g; rgb(2) = b; }
296       if (cname == "red") ASSIGN_COLOR(1, 0, 0)
297       else if (cname == "green") ASSIGN_COLOR(0, 1, 0)
298       else if (cname == "yellow") ASSIGN_COLOR(1, 1, 0)
299       else if (cname == "magenta") ASSIGN_COLOR(1, 0, 1)
300       else if (cname == "blue") ASSIGN_COLOR(0, 0, 1)
301       else if (cname == "black") ASSIGN_COLOR(0, 0, 0)
302       else if (cname == "white") ASSIGN_COLOR(1, 1, 1)
303       else if (cname == "gray") ASSIGN_COLOR(.5, .5, .5)
304       else if (cname == "darkGreen") ASSIGN_COLOR(0, .5, 0)
305       else if (cname == "orange") ASSIGN_COLOR(1, .65, 0)
306       else if (cname == "lightBlue") ASSIGN_COLOR(0.68, .85, .9)
307 #undef ASSIGN_COLOR
308     }
309 
310     ~text_element_color (void) = default;
311 
get_color(void)312     Matrix get_color (void) { return rgb; }
313 
314     void accept (text_processor& p);
315 
316   private:
317     Matrix rgb;
318   };
319 
320   class
321   OCTINTERP_API
322   text_processor
323   {
324   public:
325     virtual void visit (text_element_string& e) = 0;
326 
visit(text_element_symbol &)327     virtual void visit (text_element_symbol&) { }
328 
visit(text_element_list & e)329     virtual void visit (text_element_list& e)
330     {
331       for (auto& el_p : e)
332         {
333           el_p->accept (*this);
334         }
335     }
336 
visit(text_element_subscript & e)337     virtual void visit (text_element_subscript& e)
338     { e.get_element ()->accept (*this); }
339 
visit(text_element_superscript & e)340     virtual void visit (text_element_superscript& e)
341     { e.get_element ()->accept (*this); }
342 
visit(text_element_combined &)343     virtual void visit (text_element_combined&) { }
344 
visit(text_element_fontstyle &)345     virtual void visit (text_element_fontstyle&) { }
346 
visit(text_element_fontname &)347     virtual void visit (text_element_fontname&) { }
348 
visit(text_element_fontsize &)349     virtual void visit (text_element_fontsize&) { }
350 
visit(text_element_color &)351     virtual void visit (text_element_color&) { }
352 
reset(void)353     virtual void reset (void) { }
354 
355   protected:
text_processor(void)356     text_processor (void) { }
357 
358     virtual ~text_processor (void) = default;
359   };
360 
361 #define TEXT_ELEMENT_ACCEPT(cls)                \
362   inline void                                   \
363   cls::accept (text_processor& p)               \
364   {                                             \
365     p.visit (*this);                            \
366   }
367 
368   TEXT_ELEMENT_ACCEPT(text_element_string)
TEXT_ELEMENT_ACCEPT(text_element_symbol)369   TEXT_ELEMENT_ACCEPT(text_element_symbol)
370   TEXT_ELEMENT_ACCEPT(text_element_list)
371   TEXT_ELEMENT_ACCEPT(text_element_subscript)
372   TEXT_ELEMENT_ACCEPT(text_element_superscript)
373   TEXT_ELEMENT_ACCEPT(text_element_combined)
374   TEXT_ELEMENT_ACCEPT(text_element_fontstyle)
375   TEXT_ELEMENT_ACCEPT(text_element_fontname)
376   TEXT_ELEMENT_ACCEPT(text_element_fontsize)
377   TEXT_ELEMENT_ACCEPT(text_element_color)
378 
379   class
380   OCTINTERP_API
381   text_parser
382   {
383   public:
384     text_parser (void) { }
385 
386     virtual ~text_parser (void) = default;
387 
388     virtual text_element * parse (const std::string& s) = 0;
389 
390   public:
391     static text_element * parse (const std::string& s,
392                                  const caseless_str& interpreter);
393   };
394 
395   class
396   OCTINTERP_API
397   text_parser_none : public text_parser
398   {
399   public:
text_parser_none(void)400     text_parser_none (void) : text_parser () { }
401 
402     ~text_parser_none (void) = default;
403 
404     // FIXME: is it possible to use reference counting to manage the
405     // memory for the object returned by the text parser?  That would be
406     // preferable to having to know when and where to delete the object it
407     // creates...
408 
parse(const std::string & s)409     text_element * parse (const std::string& s)
410     {
411       return new text_element_string (s);
412     }
413   };
414 
415   class
416   OCTINTERP_API
417   text_parser_tex : public text_parser
418   {
419   public:
text_parser_tex(void)420     text_parser_tex (void)
421       : text_parser (), scanner (nullptr), buffer_state (nullptr), result (nullptr)
422     { }
423 
~text_parser_tex(void)424     ~text_parser_tex (void)
425     { destroy_lexer (); }
426 
427     text_element * parse (const std::string& s);
428 
get_scanner(void)429     void * get_scanner (void) { return scanner; }
430 
set_parse_result(text_element * e)431     void set_parse_result (text_element *e) { result = e; }
432 
get_parse_result(void)433     text_element * get_parse_result (void) { return result; }
434 
435   private:
436     bool init_lexer (const std::string& s);
437 
438     void destroy_lexer (void);
439 
440   private:
441     void *scanner;
442 
443     void *buffer_state;
444 
445     text_element *result;
446   };
447 
448   inline text_element*
parse(const std::string & s,const caseless_str & interpreter)449   text_parser::parse (const std::string& s, const caseless_str& interpreter)
450   {
451     std::unique_ptr<text_parser> parser;
452 
453     if (interpreter.compare ("tex"))
454       parser.reset (new text_parser_tex ());
455     else
456       parser.reset (new text_parser_none ());
457 
458     return parser->parse (s);
459   }
460 }
461 
462 #if defined (OCAVE_USE_DEPRECATED_FUNCTIONS)
463 
464 OCTAVE_DEPRECATED (5, "use 'octave::text_element' instead")
465 typedef octave::text_element text_element;
466 
467 OCTAVE_DEPRECATED (5, "use 'octave::text_element_string' instead")
468 typedef octave::text_element_string text_element_string;
469 
470 OCTAVE_DEPRECATED (5, "use 'octave::text_element_symbol' instead")
471 typedef octave::text_element_symbol text_element_symbol;
472 
473 OCTAVE_DEPRECATED (5, "use 'octave::text_element_list' instead")
474 typedef octave::text_element_list text_element_list;
475 
476 OCTAVE_DEPRECATED (5, "use 'octave::text_element_subscript' instead")
477 typedef octave::text_element_subscript text_element_subscript;
478 
479 OCTAVE_DEPRECATED (5, "use 'octave::text_element_superscript' instead")
480 typedef octave::text_element_superscript text_element_superscript;
481 
482 OCTAVE_DEPRECATED (5, "use 'octave::text_element_combined' instead")
483 typedef octave::text_element_combined text_element_combined;
484 
485 OCTAVE_DEPRECATED (5, "use 'octave::text_element_fontstyle' instead")
486 typedef octave::text_element_fontstyle text_element_fontstyle;
487 
488 OCTAVE_DEPRECATED (5, "use 'octave::text_element_fontname' instead")
489 typedef octave::text_element_fontname text_element_fontname;
490 
491 OCTAVE_DEPRECATED (5, "use 'octave::text_element_fontsize' instead")
492 typedef octave::text_element_fontsize text_element_fontsize;
493 
494 OCTAVE_DEPRECATED (5, "use 'octave::text_element_color' instead")
495 typedef octave::text_element_color text_element_color;
496 
497 OCTAVE_DEPRECATED (5, "use 'octave::text_processor' instead")
498 typedef octave::text_processor text_processor;
499 
500 OCTAVE_DEPRECATED (5, "use 'octave::text_parser' instead")
501 typedef octave::text_parser text_parser;
502 
503 OCTAVE_DEPRECATED (5, "use 'octave::text_parser_none' instead")
504 typedef octave::text_parser_none text_parser_none;
505 
506 OCTAVE_DEPRECATED (5, "use 'octave::text_parser_tex' instead")
507 typedef octave::text_parser_tex text_parser_tex;
508 
509 #endif
510 
511 #endif
512