source: trunk/gsdl/lib/display.cpp@ 481

Last change on this file since 481 was 477, checked in by rjmcnab, 25 years ago

Generalised spaces to unicode spaces, added ability to automatically detect
whether the input file is Unicode or UTF-8 and read the file in the
appropriate way, and improved the error messages slightly.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 45.3 KB
Line 
1/**********************************************************************
2 *
3 * display.cpp -- Context sensitive macro language
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * PUT COPYRIGHT NOTICE HERE
7 *
8 * $Id: display.cpp 477 1999-08-31 07:59:11Z rjmcnab $
9 *
10 *********************************************************************/
11
12/*
13 $Log$
14 Revision 1.13 1999/08/31 07:59:11 rjmcnab
15 Generalised spaces to unicode spaces, added ability to automatically detect
16 whether the input file is Unicode or UTF-8 and read the file in the
17 appropriate way, and improved the error messages slightly.
18
19 Revision 1.12 1999/07/21 20:46:12 rjmcnab
20 fixed small bug
21
22 Revision 1.11 1999/07/21 07:26:30 rjmcnab
23 Added more operators to _If_, changed quoting of parameters so that
24 ' can be used to quote but it is removed, and made slight optimisation
25 so that macros that don't contain other macros aren't expanded.
26
27 Revision 1.10 1999/03/01 20:39:54 sjboddie
28
29 Added eq and ne functionality to _If_
30
31 Revision 1.9 1999/03/01 01:18:09 sjboddie
32
33 Fixed bug in _If_ when value being tested was only one character
34 long (e.g. "0" or "1")
35
36 Revision 1.8 1999/02/28 23:15:29 rjmcnab
37
38 Made _If_ recognise 'false' and '0' as being false.
39
40 Revision 1.7 1999/02/08 01:26:11 rjmcnab
41
42 Improved the error reporting.
43
44 Revision 1.6 1999/01/19 08:30:23 rjmcnab
45
46 Added a method to determine whether a macro has been defined.
47
48 Revision 1.5 1999/01/19 01:38:12 rjmcnab
49
50 Made the source more portable.
51
52 Revision 1.4 1999/01/12 01:50:57 rjmcnab
53
54 Standard header.
55
56 Revision 1.3 1999/01/08 02:33:13 rjmcnab
57
58 Added standard header to source files.
59
60 */
61
62
63#include "display.h"
64#include "gsdlunicode.h"
65#include "unitool.h"
66#include <assert.h>
67
68// include to get NULL
69#include <stdlib.h>
70
71
72
73/////////////////////////////////////
74// misc classes
75/////////////////////////////////////
76
77
78// precedencetype defines a 'precedence value' for each parameter
79typedef map<text_t, double, lttext_t> precedencetype;
80
81
82// macro value structure
83struct mvalue
84{
85 text_t filename;
86 text_t value;
87};
88
89inline bool operator==(const mvalue &x, const mvalue &y) {
90 return (x.filename==y.filename && x.value==y.value);
91}
92
93inline bool operator<(const mvalue &x, const mvalue &y) {
94 return (x.filename<y.filename ||
95 (x.filename==y.filename && x.filename<y.filename));
96}
97
98
99
100/////////////////////////////////////
101// stuff for defaultmacros_t
102/////////////////////////////////////
103
104typedef map<text_t, mvalue, lttext_t> defparammap;
105typedef map<text_t, defparammap, lttext_t> defmacromap;
106typedef map<text_t, defmacromap, lttext_t> defpackagemap;
107
108// all methods in defaultmacros_t assume the parameters
109// and packages in a standard form and not empty
110class defaultmacros_t
111{
112protected:
113 defpackagemap macros;
114
115public:
116 typedef defpackagemap::const_iterator const_package_iterator;
117 typedef defpackagemap::size_type package_size_type;
118
119 // setmacro returns 0 if there was no error,
120 // -1 if it redefined a macro
121 // -2 if it hid a Global macro
122 // -3 if it redefined a macro and hid a Global macro
123 // -4 if either a package, macroname, or params were not supplied
124 int setmacro(const text_t &package,
125 const text_t &macroname,
126 const text_t &params,
127 const text_t &filename,
128 const text_t &macrovalue);
129
130 void delmacro(const text_t &package,
131 const text_t &macroname,
132 const text_t &params);
133
134 void clear () {macros.erase(macros.begin(), macros.end());}
135
136 // top level stuff
137 const_package_iterator package_begin () const {return macros.begin();}
138 const_package_iterator package_end () const {return macros.end();}
139 bool package_empty () const {return macros.empty();}
140 package_size_type package_size() const {return macros.size();}
141
142 // methods to find things
143 defmacromap *package_find (const text_t &packagename);
144 defparammap *macro_find (const text_t &packagename,
145 const text_t &macroname);
146 mvalue *parameter_find (const text_t &packagename,
147 const text_t &macroname,
148 const text_t &parametername);
149};
150
151
152// setmacro returns 0 if there was no error,
153// -1 if it redefined a macro
154// -2 if it hid a Global macro
155// -3 if it redefined a macro and hid a Global macro
156// -4 if either a package, macroname, or params were not supplied
157int defaultmacros_t::setmacro(const text_t &package,
158 const text_t &macroname,
159 const text_t &params,
160 const text_t &filename,
161 const text_t &macrovalue)
162{
163 paramhashtype paramhash;
164
165 defmacromap *macromapptr;
166 defparammap *parammapptr;
167 mvalue *mvalueptr;
168
169 int warning = 0;
170
171 // check to see if we would be hiding a Global macro with the
172 // same name. Note: it doesn't matter what parameters are used
173 // a Global macro will still be hid by a non-Global one with
174 // the same name.
175 if ((package != "Global") &&
176 (macro_find ("Global", macroname) != NULL))
177 {
178 warning -= 2; // found the macroname
179 }
180
181 // define this macro
182 macromapptr = &(macros[package]); // -- package
183 parammapptr = &((*macromapptr)[macroname]); // -- macro name
184 // -- parameters
185 if ((*parammapptr).find(params) != (*parammapptr).end()) {
186 warning -= 1; // found the parameters
187 }
188 mvalueptr = &((*parammapptr)[params]);
189
190 // -- value
191 (*mvalueptr).filename = filename;
192 (*mvalueptr).value = macrovalue;
193
194 return warning;
195}
196
197void defaultmacros_t::delmacro(const text_t &package,
198 const text_t &macroname,
199 const text_t &params)
200{
201 // make sure everything was supplied
202 if (package.empty() || macroname.empty() || params.empty()) return;
203
204 // find the package and macroname
205 defparammap *parammapptr = macro_find(package, macroname);
206 if (parammapptr == NULL) return;
207
208 // find the parameters
209 defparammap::iterator parammapit = parammapptr->find(params);
210 if (parammapit == parammapptr->end()) return;
211
212 // finally delete this element
213 parammapptr->erase(parammapit);
214}
215
216defmacromap *defaultmacros_t::package_find (const text_t &packagename)
217{
218 if (packagename.empty()) return NULL;
219
220 defpackagemap::iterator it = macros.find(packagename);
221 if (it == macros.end()) return NULL;
222
223 return &((*it).second);
224}
225
226defparammap *defaultmacros_t::macro_find (const text_t &packagename,
227 const text_t &macroname)
228{
229 defmacromap *macromapptr = package_find(packagename);
230 if (macromapptr == NULL || macroname.empty()) return NULL;
231
232 defmacromap::iterator it = (*macromapptr).find(macroname);
233 if (it == (*macromapptr).end()) return NULL;
234
235 return &((*it).second);
236}
237
238mvalue *defaultmacros_t::parameter_find (const text_t &packagename,
239 const text_t &macroname,
240 const text_t &parametername)
241{
242 defparammap *parammapptr = macro_find(packagename, macroname);
243 if (parammapptr == NULL || parametername.empty()) return NULL;
244
245 defparammap::iterator it = (*parammapptr).find(parametername);
246 if (it == (*parammapptr).end()) return NULL;
247
248 return &((*it).second);
249}
250
251
252
253/////////////////////////////////////
254// stuff for currentmacros_t
255/////////////////////////////////////
256
257typedef map<text_t, mvalue, lttext_t> curmacromap;
258typedef map<text_t, curmacromap, lttext_t> curpackagemap;
259
260// all methods in currentmacros_t assume the parameters
261// and packages in a standard form and not empty
262class currentmacros_t
263{
264protected:
265 curpackagemap macros;
266
267public:
268 typedef curpackagemap::const_iterator const_package_iterator;
269 typedef curpackagemap::size_type package_size_type;
270
271 // setmacro returns 0 if there was no error,
272 // -1 if it redefined a macro
273 // -4 if either a package, or macroname were not supplied
274 int setmacro(const text_t &package,
275 const text_t &macroname,
276 const text_t &filename,
277 const text_t &macrovalue);
278
279 void delmacro(const text_t &package,
280 const text_t &macroname);
281
282 void clear () {macros.erase(macros.begin(), macros.end());}
283
284 // top level stuff
285 const_package_iterator package_begin () const {return macros.begin();}
286 const_package_iterator package_end () const {return macros.end();}
287 bool package_empty () const {return macros.empty();}
288 package_size_type package_size() const {return macros.size();}
289
290 // methods to find things
291 curmacromap *package_find (const text_t &packagename);
292 mvalue *macro_find (const text_t &packagename,
293 const text_t &macroname);
294};
295
296
297// setmacro returns 0 if there was no error,
298// -1 if it redefined a macro
299// -4 if either a package, or macroname were not supplied
300int currentmacros_t::setmacro(const text_t &package,
301 const text_t &macroname,
302 const text_t &filename,
303 const text_t &macrovalue)
304{
305 int warning = 0;
306
307 // make sure everything was supplied
308 if (package.empty() || macroname.empty()) return -4;
309
310 // define this macro
311 curmacromap *macromapptr = &(macros[package]);
312 if ((*macromapptr).find(macroname) != (*macromapptr).end())
313 {
314 warning -= 1; // found the macroname
315 }
316 mvalue *mvalueptr = &((*macromapptr)[macroname]);
317
318 // -- value
319 (*mvalueptr).filename = filename;
320 (*mvalueptr).value = macrovalue;
321
322 return warning;
323}
324
325void currentmacros_t::delmacro(const text_t &package,
326 const text_t &macroname)
327{
328 // make sure everything was supplied
329 if (package.empty() || macroname.empty()) return;
330
331 // find the package
332 curmacromap *macromapptr = package_find(package);
333 if (macromapptr == NULL) return;
334
335 // find the macroname
336 curmacromap::iterator macromapit = macromapptr->find(macroname);
337 if (macromapit == macromapptr->end()) return;
338
339 // finally delete this element
340 macromapptr->erase(macromapit);
341}
342
343curmacromap *currentmacros_t::package_find (const text_t &packagename)
344{
345 if (packagename.empty()) return NULL;
346
347 curpackagemap::iterator it = macros.find(packagename);
348 if (it == macros.end()) return NULL;
349
350 return &((*it).second);
351}
352
353mvalue *currentmacros_t::macro_find (const text_t &packagename,
354 const text_t &macroname)
355{
356 curmacromap *macromapptr = package_find(packagename);
357 if (macromapptr == NULL || macroname.empty()) return NULL;
358
359 curmacromap::iterator it = (*macromapptr).find(macroname);
360 if (it == (*macromapptr).end()) return NULL;
361
362 return &((*it).second);
363}
364
365
366
367
368/////////////////////////////////////
369// support functions
370/////////////////////////////////////
371
372// this calculation of precedence will make one occurance of a high
373// precedence item override many occurances of lower precedence items
374void calcprecedence (const text_t &precedstr, precedencetype &precedhash)
375{
376 text_t param;
377 double multiple = 5.0;
378 double nextprec = multiple;
379
380 text_t::const_iterator here, end;
381
382 // set precedhash to an empty hash
383 precedhash.erase(precedhash.begin(), precedhash.end());
384
385 // iterate through paramstring ignoring space and extracting
386 // out key value pairs.
387 here = precedstr.begin();
388 end = precedstr.end();
389 while (here != end)
390 {
391 // get the next parameter
392 param.clear(); // set param to an empty string
393
394 while (here != end)
395 {
396 if (*here == ',')
397 {
398 // found the end of the parameter
399 here++;
400 break;
401 }
402 else if (*here == ' ')
403 {
404 // do nothing (ignore spaces)
405 }
406 else
407 {
408 // character in parameter
409 param.push_back (*here); // copy this character
410 }
411
412 here++;
413 }
414
415 // if a parameter was found insert its value
416 if (!param.empty())
417 {
418 precedhash[param] = nextprec;
419 nextprec *= multiple;
420 }
421 }
422}
423
424
425// decides how specific any given parameter is to the page parameters. Returns
426// negative if any options are different or else the sum of the precedence for
427// the options which match.
428double getspecificness(const paramhashtype &pageparams,
429 const paramhashtype &theseparams,
430 const precedencetype &precedhash)
431{
432 double specificness = 0.0;
433 paramhashtype::const_iterator here, pagevalueit;
434 precedencetype::const_iterator precedit;
435 text_t thesekey, thesevalue, constignore("ignore");
436
437 here = theseparams.begin();
438 while (here != theseparams.end())
439 {
440 thesekey = (*here).first;
441 thesevalue = (*here).second;
442
443 if (thesekey == constignore)
444 {
445 // do nothing, this is a placeholder
446 }
447 else
448 {
449 pagevalueit = pageparams.find(thesekey);
450 if ((pagevalueit != pageparams.end()) &&
451 ((*pagevalueit).second == thesevalue))
452 {
453 // this parameter fits, add its precedence value
454 precedit = precedhash.find(thesekey);
455 if (precedit == precedhash.end())
456 specificness += 1.0; // no precedence defined
457 else
458 specificness += (*precedit).second;
459 }
460 else
461 {
462 return -1.0; // did not match
463 }
464 }
465
466 here++;
467 }
468
469 return specificness;
470}
471
472
473void splitparams (const text_t &paramstring, paramhashtype &paramhash)
474{
475 text_t key;
476 text_t value;
477
478 text_t::const_iterator here, end;
479
480 // set paramhash to an empty hash
481 paramhash.erase(paramhash.begin(), paramhash.end());
482
483 // iterate through paramstring ignoring space and extracting
484 // out key value pairs.
485 here = paramstring.begin();
486 end = paramstring.end();
487 while (here != end)
488 {
489 // reset key and value
490 key.clear();
491 value.clear();
492
493 // get key
494 while (here != end)
495 {
496 if (*here == ',')
497 {
498 // have a key with no value
499 break;
500 }
501 else if (*here == '=')
502 {
503 // found the end of the key
504 here ++;
505 break;
506 }
507 else if (*here == ' ')
508 {
509 // do nothing (ignore spaces)
510 }
511 else
512 {
513 // character in key
514 key.push_back (*here); // copy this character
515 }
516 here ++;
517 }
518
519 // get value
520 while (here != end)
521 {
522 if (*here == '=')
523 {
524 // multiple values for one key, ignore previous
525 // values
526 value.clear();
527 }
528 else if (*here == ',')
529 {
530 // found the end of the value
531 here ++;
532 break;
533 }
534 else if (*here == ' ')
535 {
536 // do nothing (ignore spaces)
537 }
538 else
539 {
540 // character in value
541 value.push_back (*here); // copy this character
542 }
543 here ++;
544 }
545
546 // if a key was found insert the key/value pair in
547 // the map
548 if (!key.empty())
549 {
550 paramhash[key] = value;
551 }
552 }
553}
554
555
556void joinparams (const paramhashtype &paramhash, text_t &paramstring)
557{
558 //set paramstring to an empty string
559 paramstring.clear();
560
561 //iterate through the paramhash
562 paramhashtype::const_iterator thepair;
563 int firstparam = 1;
564
565 for (thepair=paramhash.begin();thepair!=paramhash.end(); thepair++)
566 {
567 if (!firstparam) paramstring.push_back(',');
568 firstparam = 0;
569
570 // insert pairs of "key=value"
571 text_t thevalue;
572 paramstring.append((*thepair).first);
573 paramstring.push_back('=');
574 paramstring.append((*thepair).second);
575 }
576}
577
578
579
580/////////////////////////////////////
581// parsing support functions
582/////////////////////////////////////
583
584inline int my_isalpha (unsigned short c)
585{
586 return ((c >= 'A' && c <= 'Z') ||
587 (c >= 'a' && c <= 'z'));
588}
589
590
591
592inline unsigned short my_ttnextchar (text_t::const_iterator &here,
593 text_t::const_iterator &end)
594{
595 if (here != end)
596 {
597 here++;
598 if (here != end) return (*here);
599 }
600 return '\0';
601}
602
603
604
605/////////////////////////////////////
606// methods for display
607/////////////////////////////////////
608
609// public methods for display
610
611displayclass::displayclass ()
612{
613 defaultmacros = new defaultmacros_t;
614 defaultfiles = new fileinfomap;
615
616 orderparamlist = new paramspeclist;
617 currentmacros = new currentmacros_t;
618
619 outc = NULL;
620
621 logout = &cerr;
622}
623
624
625displayclass::~displayclass ()
626{
627 delete defaultmacros;
628 delete defaultfiles;
629
630 delete orderparamlist;
631 delete currentmacros;
632}
633
634// setdefaultmacro adds an entry to the list of default macros
635// returns 0 if there was no error,
636// -1 if it redefined a macro
637// -2 if it hid a Global macro
638// -3 if it redefined a macro and hid a Global macro
639// -4 if no macroname was supplied
640int displayclass::setdefaultmacro (text_t package, const text_t &macroname,
641 text_t params, const text_t &macrovalue)
642{
643 return setdefaultmacro (macroname, package, params, macrovalue, "memory");
644}
645
646
647
648// as we are using one character lookahead the
649// value of line might be off by one.
650// the input file must be in the utf-8 or unicode format
651// initially for each file isunicode should be set to 0 and
652// bigendian should be set to 1
653// 0 will be returned when the end of the file has been found
654unsigned short my_uni_get (istream &fin, int &line,
655 int &isunicode, int &bigendian) {
656 unsigned short c = 0;
657
658 if (isunicode) {
659 // unicode text
660 // get the next two characters
661 unsigned char c1 = 0, c2 = 0;
662 if (!fin.eof()) fin.get(c1);
663 if (!fin.eof()) fin.get(c2);
664 else c1 = 0;
665
666 // if they indicate the order get the next character
667 // otherwise just get these characters
668 if (c1 == 0xff && c2 == 0xfe) {
669 bigendian = 0;
670 c = my_uni_get (fin, line, isunicode, bigendian);
671 } else if (c1 == 0xfe && c2 == 0xff) {
672 bigendian = 1;
673 c = my_uni_get (fin, line, isunicode, bigendian);
674 } else c = (bigendian) ? (c1*256+c2) : (c2*256+c1);
675
676 } else {
677 // utf-8 text
678 // how many characters we get depends on what we find
679 unsigned char c1 = 0, c2 = 0, c3 = 0;
680 while (!fin.eof()) {
681 fin.get(c1);
682 if (c1 == 0xfe || c1 == 0xff) {
683 // switch to unicode
684 isunicode = 1;
685 if (!fin.eof()) fin.get(c2);
686
687 if (c1 == 0xff && c2 == 0xfe) bigendian = 0;
688 else bigendian = 1;
689
690 c = my_uni_get (fin, line, isunicode, bigendian);
691 break;
692
693 } else if (c1 <= 0x7f) {
694 // one byte character
695 c = c1;
696 break;
697
698 } else if (c1 >= 0xc0 && c1 <= 0xdf) {
699 // two byte character
700 if (!fin.eof()) fin.get(c2);
701 c = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
702 break;
703
704 } else if (c1 >= 0xe0 && c1 <= 0xef) {
705 // three byte character
706 if (!fin.eof()) fin.get(c2);
707 if (!fin.eof()) fin.get(c3);
708 c = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) + (c3 & 0x3f);
709 break;
710 }
711
712 // if we get here there was an error in the file, we should
713 // be able to recover from it however, maybe the file is in
714 // another encoding
715 }
716 }
717
718 if (c == '\n') line++;
719 return c;
720}
721
722
723
724// loads a default macro file (if it isn't already loaded)
725// returns 0 if didn't need to load the file (it was already loaded)
726// 1 if was (re)loaded
727// -1 an error occurred while trying to load the file
728int displayclass::loaddefaultmacros (text_t thisfilename) {
729 // convert the filename to a C string
730 char *filenamestr = thisfilename.getcstr();
731 outconvertclass text_t2ascii;
732
733 // see if we need to open this file -- this isn't implemented yet
734
735 // open the file
736 ifstream fin(filenamestr);
737 if (fin.fail()) return -1; // read failed
738
739 text_t package = "Global";
740 int line = 1;
741 int isunicode = 0, bigendian = 1;
742
743 // pre-fetch the next character
744 unsigned short c = my_uni_get(fin, line, isunicode, bigendian);
745
746 text_t macropackage, macroname, macroparameters, macrovalue;
747 int err; // for keeping track of whether an error occurred somewhere
748
749 while (!fin.eof()) {
750 // expect: white space, comment, "package", or macroname
751 if (is_unicode_space(c)) {
752 // found some white-space
753 c = my_uni_get(fin, line, isunicode, bigendian);
754
755 } else if (c == '#') {
756 // found the start of a comment
757 // skip all characters up to the end of the line
758 c = my_uni_get(fin, line, isunicode, bigendian); // skip the '#'
759 while (!fin.eof ()) {
760 if (c == '\n') break;
761 c = my_uni_get(fin, line, isunicode, bigendian);
762 }
763
764 } else if (c == 'p') {
765 // found the start of 'package' (hopefully)
766 // get everything up to the next space
767 text_t tmp;
768 while (!fin.eof() && my_isalpha(c)) {
769 tmp.push_back(c);
770 c = my_uni_get(fin, line, isunicode, bigendian);
771 }
772 // see if we have a package name
773 if (tmp == "package") {
774 // skip all white space
775 while (!fin.eof() && is_unicode_space(c))
776 c = my_uni_get(fin, line, isunicode, bigendian);
777
778 // get the package name
779 tmp.clear(); // init tmp
780 while (!fin.eof() && my_isalpha(c)) {
781 tmp.push_back(c);
782 c = my_uni_get(fin, line, isunicode, bigendian);
783 }
784 package = tmp;
785 if (package.empty()) package = "Global";
786
787 } else {
788 // error
789 if (logout != NULL) {
790 (*logout) << text_t2ascii << "Expected 'package' on line " << line
791 << " of " << thisfilename << "\n";
792 }
793 }
794
795 } else if (c == '_') {
796 // found the start of a macro (hopefully)
797 c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
798
799 // init variables
800 err = 0;
801 macropackage = package;
802 macroname.clear(); // init macroname
803 macroparameters.clear(); // init macroname
804 macrovalue.clear(); // init macroname
805
806 // get the macro name
807 while ((!fin.eof()) && (!is_unicode_space(c)) &&
808 (c != '\\') && (c != '_') &&(c != ':') &&
809 (macroname.size() < 80)) {
810 macroname.push_back(c);
811 c = my_uni_get(fin, line, isunicode, bigendian);
812 }
813
814 if (c == ':') {
815 // we actually had the macro package
816 c = my_uni_get(fin, line, isunicode, bigendian); // skip :
817 macropackage = macroname;
818 macroname.clear ();
819
820 // get the macro name (honest!)
821 while ((!fin.eof()) && (!is_unicode_space(c)) &&
822 (c != '\\') && (c != '_') &&(c != ':') &&
823 (macroname.size() < 80)) {
824 macroname.push_back(c);
825 c = my_uni_get(fin, line, isunicode, bigendian);
826 }
827 }
828
829 if (!err && c == '_') {
830 c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
831
832 // skip all white space
833 while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
834 } else if (!err) err = 1;
835
836 // get the macro parameters (optional)
837 if (!err && c == '[') {
838 c = my_uni_get(fin, line, isunicode, bigendian); // skip the [
839 while ((!fin.eof()) && (c != '\n') && (c != '\\') && (c != ']')) {
840 macroparameters.push_back(c);
841 c = my_uni_get(fin, line, isunicode, bigendian);
842 }
843
844 if (c == ']') {
845 c = my_uni_get(fin, line, isunicode, bigendian); // skip the ]
846
847 // skip all white space
848 while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
849 }
850 else if (!err) err = 2;
851 }
852
853 // get the macro value
854 if (!err && c == '{') {
855 c = my_uni_get(fin, line, isunicode, bigendian); // skip the {
856 while ((!fin.eof()) && (c != '}')) {
857 if (c == '\\') {
858 macrovalue.push_back(c); // keep the '\'
859 c = my_uni_get(fin, line, isunicode, bigendian); // store the *next* value regardless
860 if (!fin.eof()) macrovalue.push_back(c);
861 c = my_uni_get(fin, line, isunicode, bigendian);
862 }
863 macrovalue.push_back(c);
864 c = my_uni_get(fin, line, isunicode, bigendian);
865 }
866
867 if (c == '}') {
868 c = my_uni_get(fin, line, isunicode, bigendian); // skip the }
869
870 // define the macro
871 err = setdefaultmacro (macropackage, macroname, macroparameters,
872 thisfilename, macrovalue);
873 if ((err == -1 || err == -3) && logout != NULL) {
874 (*logout) << text_t2ascii << "Warning: redefinition of _" <<
875 package << ":" << macroname << "_[" << macroparameters <<
876 "] on line ";
877 (*logout) << line;
878 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
879
880 } else if (err == -2 && logout != NULL) {
881 (*logout) << text_t2ascii << "Warning: _" <<
882 package << ":" << macroname << "_[" << macroparameters <<
883 "] on line ";
884 (*logout) << line;
885 (*logout) << text_t2ascii << " of " <<
886 thisfilename << " hides a Global macro with the same name\n";
887
888 } else if (err == -4 && logout != NULL) {
889 (*logout) << text_t2ascii << "Error: macro name expected on line ";
890 (*logout) << line ;
891 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
892 }
893
894 err = 0; // for the test below
895 }
896 else if (!err) err = 3;
897 }
898 else if (!err) err = 4;
899
900 if (err) {
901 // found an error, skip to the end of the line
902 if (logout != NULL) {
903 (*logout) << text_t2ascii << "Error: ";
904 if (err == 1) (*logout) << text_t2ascii << "'_'";
905 else if (err == 2) (*logout) << text_t2ascii << "']'";
906 else if (err == 3) (*logout) << text_t2ascii << "'}'";
907 else if (err == 4) (*logout) << text_t2ascii << "'{'";
908 (*logout) << text_t2ascii << " expected on line ";
909 (*logout) << line ;
910 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
911 }
912 while (!fin.eof ()) {
913 if (c == '\n') break;
914 c = my_uni_get(fin, line, isunicode, bigendian);
915 }
916 }
917
918 } else {
919 // found an error, skip to the end of the line
920 if (logout != NULL) {
921 (*logout) << text_t2ascii << "Error: Unexpected input on line " << line
922 << " of " << thisfilename << "\n";
923 }
924 while (!fin.eof ()) {
925 if (c == '\n') break;
926 c = my_uni_get(fin, line, isunicode, bigendian);
927 }
928
929 }
930 }
931
932 fin.close ();
933
934 // free up memory
935 delete filenamestr;
936 return 0;
937}
938
939
940// prepares to create a page.
941void displayclass::openpage (const text_t &thispageparams,
942 const text_t &thisprecedence)
943{
944 // init variables
945 currentmacros->clear();
946
947 // reload any default macro files which have changed.
948 if (checkdefaultmacrofiles() < 0)
949 {
950 // print error message
951 }
952
953 setpageparams (thispageparams, thisprecedence);
954}
955
956
957// changes the parameters for the current page.
958void displayclass::setpageparams (text_t thispageparams,
959 text_t thisprecedence)
960{
961 paramhashtype thissplitparams, splittheseparams;
962 precedencetype precedhash;
963 text_tset::iterator text_tsetit;
964 paramspec tmpps;
965
966 precedence = thisprecedence;
967 calcprecedence(thisprecedence, precedhash);
968
969 splitparams(thispageparams, thissplitparams);
970 joinparams(thissplitparams, thispageparams);
971 params = thispageparams;
972
973 // get a list of parameters with their specificness
974 orderparamlist->erase(orderparamlist->begin(), orderparamlist->end());
975 for (text_tsetit=allparams.begin();
976 text_tsetit!=allparams.end();
977 text_tsetit++)
978 {
979 tmpps.param = (*text_tsetit);
980 splitparams(tmpps.param, splittheseparams);
981 tmpps.spec = getspecificness(thissplitparams, splittheseparams, precedhash);
982 if (tmpps.spec >= 0)
983 {
984 orderparamlist->push_back (tmpps);
985 }
986 }
987
988 // sort the list
989 sort(orderparamlist->begin(), orderparamlist->end());
990
991// paramspeclist::iterator pshere = orderparamlist->begin();
992// paramspeclist::iterator psend = orderparamlist->end();
993// while (pshere != psend)
994// {
995// cerr << text_t2ascii << "param=" << (*pshere).param;
996// cerr << " spec=" << (int)((*pshere).spec) << "\n";
997// pshere++;
998// }
999}
1000
1001
1002// overrides (or sets) a macro for the current page.
1003// returns 0 if there was no error,
1004// -1 if it redefined a macro
1005// -4 if no macroname was supplied
1006int displayclass::setmacro (const text_t &macroname,
1007 text_t package,
1008 const text_t &macrovalue)
1009{
1010 // make sure a macroname was supplied
1011 if (macroname.empty()) return -4;
1012
1013 // make package "Global" if it doesn't point to anything yet
1014 if (package.empty()) package = "Global";
1015
1016 // set the macro
1017 return currentmacros->setmacro(package, macroname, "memory", macrovalue);
1018}
1019
1020
1021void displayclass::expandstring (const text_t &inputtext, text_t &outputtext)
1022{
1023 expandstring("", inputtext, outputtext);
1024}
1025
1026
1027void displayclass::expandstring (text_t package, const text_t &inputtext,
1028 text_t &outputtext, int recursiondepth)
1029{
1030 text_t macroname, macropackage, macroargs;
1031 text_t::const_iterator tthere = inputtext.begin();
1032 text_t::const_iterator ttend = inputtext.end();
1033 unsigned short c;
1034
1035 if (package.empty()) package = "Global";
1036
1037 outputtext.clear();
1038
1039 // use one-character lookahead
1040 if (tthere != ttend) c = (*tthere);
1041 while (tthere != ttend)
1042 {
1043 if (c == '\\')
1044 {
1045 // found an escape character
1046 c = my_ttnextchar (tthere, ttend); // skip the escape character
1047 if (tthere != ttend)
1048 {
1049 if (c == 'n') outputtext.push_back('\n');
1050 else if (c == 't') outputtext.push_back('\t');
1051 else outputtext.push_back(c);
1052 }
1053 c = my_ttnextchar (tthere, ttend);
1054
1055 }
1056 else if (c == '_')
1057 {
1058 // might have found the start of a macro
1059
1060 // embedded macros (macros within the names
1061 // of other macros) are no longer supported -- Rodger.
1062
1063 // save the current state (in case we need to back out)
1064 text_t::const_iterator savedtthere = tthere;
1065 unsigned short savedc = c;
1066
1067 macroname.clear();
1068 macropackage = package;
1069 macroargs.clear();
1070
1071 c = my_ttnextchar (tthere, ttend); // skip the '_'
1072
1073 // get the macroname
1074 while (tthere != ttend && (!is_unicode_space(c)) &&
1075 (c != '\\') && (c != '_') &&(c != ':') &&
1076 (macroname.size() < 80))
1077 {
1078 macroname.push_back((unsigned char)c);
1079 c = my_ttnextchar (tthere, ttend);
1080 }
1081
1082 if (c == ':')
1083 {
1084 // we actually had the macro package
1085 c = my_ttnextchar (tthere, ttend);
1086 macropackage = macroname;
1087 macroname.clear ();
1088
1089 // get the macro name (honest!)
1090 while ((tthere != ttend) && (!is_unicode_space(c)) &&
1091 (c != '\\') && (c != '_') &&(c != ':') &&
1092 (macroname.size() < 80))
1093 {
1094 macroname.push_back((unsigned char)c);
1095 c = my_ttnextchar (tthere, ttend);
1096 }
1097 }
1098
1099 if ((tthere != ttend) && (c == '_') &&
1100 (macroname.size() > 0))
1101 {
1102 // found a macro!!!! (maybe)
1103
1104 c = my_ttnextchar (tthere, ttend); // skip the '_'
1105
1106 // get the parameters (if there are any)
1107 if ((tthere != ttend) && (c == '('))
1108 {
1109 c = my_ttnextchar (tthere, ttend); // skip '('
1110
1111 // have to be careful of quotes
1112 unsigned short quote = '\0';
1113 while (tthere != ttend)
1114 {
1115 if (c == '\\')
1116 {
1117 // have an escape character, save escape
1118 // character and next character as well
1119 macroargs.push_back (c);
1120 c = my_ttnextchar (tthere, ttend);
1121
1122 }
1123 else if (quote == '\0')
1124 {
1125 // not in a quote at the moment
1126 if (c == ')')
1127 {
1128 // found end of the arguments
1129 c = my_ttnextchar (tthere, ttend); // skip ')'
1130 break;
1131
1132 }
1133 else if (c == '\'' || c == '\"')
1134 {
1135 // found a quote
1136 quote = c;
1137 }
1138
1139 }
1140 else
1141 {
1142 // we are in a quote
1143 if (c == quote) quote = '\0';
1144 }
1145
1146 // save this character
1147 if (tthere != ttend) macroargs.push_back (c);
1148 c = my_ttnextchar (tthere, ttend);
1149 }
1150 }
1151
1152 //
1153 // we now have the macropackage, macroname, and macroargs
1154 //
1155
1156 // try to expand out this macro
1157 text_t expandedmacro;
1158 if (macro (macroname, macropackage, macroargs, expandedmacro, recursiondepth))
1159 {
1160 // append the expanded macro
1161 outputtext += expandedmacro;
1162 }
1163 else
1164 {
1165 // wasn't a macro
1166 tthere = savedtthere;
1167 c = savedc;
1168 outputtext.push_back(c); // the '_'
1169 c = my_ttnextchar (tthere, ttend);
1170 }
1171
1172
1173 }
1174 else
1175 {
1176 // wasn't a macro
1177 tthere = savedtthere;
1178 c = savedc;
1179 outputtext.push_back(c); // the '_'
1180 c = my_ttnextchar (tthere, ttend);
1181 }
1182
1183 }
1184 else
1185 {
1186 // nothing of interest
1187 outputtext.push_back(c); // the '_'
1188 c = my_ttnextchar (tthere, ttend);
1189 }
1190 }
1191}
1192
1193
1194// protected methods for display
1195
1196// reloads any default macro files which have changed
1197// returns 0 no errors occurred
1198// -1 an error occurred while trying to load one of the files
1199int displayclass::checkdefaultmacrofiles ()
1200{
1201 // this isn't implemented yet
1202 return 0;
1203}
1204
1205// isdefaultmacro sees if there is an entry in the list of
1206// default macros with the given package and macro name
1207// returns 0 if no macros in the package or in the global package
1208// were found
1209// 1 if no macros in the package were found but a macro
1210// in the global package was found
1211// 2 if a macro in the given package was found
1212int displayclass::isdefaultmacro (text_t package, const text_t &macroname) {
1213 // make sure a macroname was supplied
1214 if (macroname.empty()) return 0;
1215
1216 // make package "Global" if it doesn't point to anything yet
1217 if (package.empty()) package = "Global";
1218
1219 // check the given package
1220 if (defaultmacros->macro_find(package, macroname) != NULL) return 2;
1221
1222 // check the Global package
1223 if (defaultmacros->macro_find("Global", macroname) != NULL) return 1;
1224
1225 return 0;
1226}
1227
1228
1229// setdefaultmacro adds an entry to the list of default macros
1230// returns 0 if there was no error,
1231// -1 if it redefined a macro
1232// -2 if it hid a Global macro
1233// -3 if it redefined a macro and hid a Global macro
1234// -4 if no macroname was supplied
1235int displayclass::setdefaultmacro (text_t package, const text_t &macroname,
1236 text_t params, const text_t &filename,
1237 const text_t &macrovalue)
1238{
1239 // make sure a macroname was supplied
1240 if (macroname.empty()) return -4;
1241
1242 // put the parameters in a standard form
1243 paramhashtype paramhash;
1244 if (params.empty()) params = "ignore=yes";
1245 splitparams (params, paramhash);
1246 joinparams (paramhash, params);
1247
1248 // make package "Global" if it doesn't point to anything yet
1249 if (package.empty()) package = "Global";
1250
1251 // remember these parameters
1252 allparams.insert (params);
1253
1254 // remember this filename (this part isn't finished yet -- Rodger).
1255
1256 // set the macro
1257 return defaultmacros->setmacro(package, macroname, params, filename, macrovalue);
1258}
1259
1260
1261// evaluates a boolean expression
1262// returns false if expr equals "" or "0".
1263// otherwise returns true *unless* expr is
1264// format "XXXX" eq/ne "dddd" in which case
1265// the two quoted strings are compared
1266bool displayclass::boolexpr (text_t package, const text_t &expr, int recursiondepth) {
1267
1268 if (expr.empty()) return false;
1269
1270 text_t expexpr;
1271 if (package.empty()) package = "Global";
1272 expandstring (package, expr, expexpr, recursiondepth);
1273
1274 if (expexpr.empty() || expexpr == "0") return false;
1275 if (expr[0] != '\"') return true;
1276
1277 // don't use expexpr while separating quoted parts of
1278 // expression just in case expanded out macros contain
1279 // quotes
1280 text_t::const_iterator here = expr.begin();
1281 text_t::const_iterator end = expr.end();
1282
1283 int quotecount = 0;
1284 text_t string1, expstring1;
1285 text_t string2, expstring2;
1286 text_t op;
1287 text_t combineop;
1288 bool result = false; // an empty string is false
1289 bool result2 = false;
1290
1291 while (here != end) {
1292 // get a comparison
1293 quotecount = 0;
1294 string1.clear();
1295 string2.clear();
1296 op.clear();
1297 while (here != end) {
1298 if (*here == '"') quotecount++;
1299 else if (quotecount == 1) string1.push_back(*here);
1300 else if ((quotecount == 2) && !is_unicode_space (*here))
1301 op.push_back(*here);
1302 else if (quotecount == 3) string2.push_back(*here);
1303 else if (quotecount >= 4) break;
1304 here ++;
1305 }
1306
1307 expandstring (package, string1, expstring1, recursiondepth);
1308 expandstring (package, string2, expstring2, recursiondepth);
1309
1310 // get next result
1311 result2 = true; // any badly formatted string will return true
1312 if (op == "eq") result2 = (expstring1 == expstring2);
1313 else if (op == "ne") result2 = (expstring1 != expstring2);
1314 else if (op == "gt") result2 = (expstring1 > expstring2);
1315 else if (op == "ge") result2 = (expstring1 >= expstring2);
1316 else if (op == "lt") result2 = (expstring1 < expstring2);
1317 else if (op == "le") result2 = (expstring1 <= expstring2);
1318 else if (op == "==") result2 = (expstring1.getint() == expstring2.getint());
1319 else if (op == "!=") result2 = (expstring1.getint() != expstring2.getint());
1320 else if (op == ">") result2 = (expstring1.getint() > expstring2.getint());
1321 else if (op == ">=") result2 = (expstring1.getint() >= expstring2.getint());
1322 else if (op == "<") result2 = (expstring1.getint() < expstring2.getint());
1323 else if (op == "<=") result2 = (expstring1.getint() <= expstring2.getint());
1324
1325 // combine the results
1326 if (combineop == "&&") result = (result && result2);
1327 else if (combineop == "||") result = (result || result2);
1328 else result = result2;
1329
1330 // get next combination operator
1331 combineop.clear();
1332 while (here != end && *here != '"') {
1333 if (!is_unicode_space(*here)) combineop.push_back(*here);
1334 here++;
1335 }
1336 }
1337
1338 return result;
1339}
1340
1341
1342// (recursively) expand out a macro
1343// returns true if the macro was found
1344// false if the macro was not found
1345bool displayclass::macro (const text_t &macroname, text_t macropackage,
1346 const text_t &macroparam, text_t &outputtext,
1347 int recursiondepth)
1348{
1349 outconvertclass text_t2ascii;
1350 text_tlist splitmacroparam;
1351 text_t::const_iterator hereit, endit;
1352 text_t aparam;
1353 unsigned short c, quote;
1354
1355 // cerr << "r: " << recursiondepth << "\n";
1356
1357 // check for deep recursion
1358 if (recursiondepth >= MAXRECURSIONDEPTH)
1359 {
1360 if (logout != NULL)
1361 (*logout) << "Warning: deep recursion, limiting macro expansion\n";
1362 return false;
1363 }
1364
1365 // check the macropackage
1366 if (macropackage.empty()) macropackage = "Global";
1367
1368 // get the parameters (but don't expand them)
1369 if (macroparam.size() > 0) {
1370 // set up for loop
1371 hereit = macroparam.begin();
1372 endit = macroparam.end();
1373 if (hereit != endit) c = (*hereit);
1374
1375 while (hereit != endit) {
1376 // get the next parameter
1377 aparam.clear();
1378 quote = '\0'; // not-quoted unless proven quoted
1379
1380 // ignore initial whitespace
1381 while ((hereit!=endit)&&is_unicode_space(c)) c=my_ttnextchar(hereit,endit);
1382
1383 // look for the end of the parameter
1384 while (hereit != endit) {
1385 if (c == '\\') {
1386 // found escape character, also get next character
1387 aparam.push_back(c);
1388 c = my_ttnextchar (hereit, endit);
1389 if (hereit != endit) aparam.push_back(c);
1390
1391 } else if (quote=='\0' && (c=='\'' /*|| c=='"'*/)) {
1392 // found a quoted section
1393 quote = c;
1394 // aparam.push_back(c);
1395
1396 } else if (quote!='\0' && c==quote) {
1397 // found the end of a quote
1398 quote = '\0';
1399 // aparam.push_back(c);
1400
1401 } else if (quote=='\0' && c==',') {
1402 // found the end of a parameter
1403 c = my_ttnextchar (hereit, endit);
1404 break;
1405
1406 } else {
1407 // ordinary character
1408 aparam.push_back(c);
1409 }
1410
1411 c = my_ttnextchar (hereit, endit);
1412 }
1413
1414 // add this parameter to the list
1415 splitmacroparam.push_back(aparam);
1416 }
1417 }
1418
1419 if (macroname == "If") {
1420 // get the condition, then clause and else clause
1421 text_tlist::iterator paramcond = splitmacroparam.begin();
1422 text_tlist::iterator paramend = splitmacroparam.end();
1423 text_tlist::iterator paramthen = paramend;
1424 text_tlist::iterator paramelse = paramend;
1425
1426 if (paramcond != paramend) {
1427 paramthen = paramcond;
1428 paramthen++;
1429 }
1430 if (paramthen != paramend) {
1431 paramelse = paramthen;
1432 paramelse++;
1433 }
1434
1435 // will always output something
1436 outputtext.clear();
1437
1438 // expand out the first parameter
1439 if (paramcond != paramend) {
1440 text_t tmpoutput;
1441 expandstring (macropackage, *paramcond, tmpoutput, recursiondepth+1);
1442 lc (tmpoutput);
1443
1444 // test the expanded string
1445 if (boolexpr (macropackage, *paramcond, recursiondepth+1)) {
1446 //(tmpoutput.size()) && (tmpoutput != "false") && (tmpoutput != "0")) {
1447 // true
1448 if (paramthen != paramend)
1449 expandstring (macropackage, *paramthen, outputtext, recursiondepth+1);
1450
1451 } else {
1452 // false
1453 if (paramelse != paramend)
1454 expandstring (macropackage, *paramelse, outputtext, recursiondepth+1);
1455 }
1456 }
1457
1458 return true;
1459 }
1460
1461 // try and find this macro
1462
1463 // this list might be replaced by something a little more
1464 // sophisticated in the future.
1465 text_tlist packagelist;
1466 packagelist.push_back (macropackage);
1467 packagelist.push_back ("Global");
1468
1469 paramspeclist::iterator paramhere, paramend;
1470 text_tlist::iterator packagehere = packagelist.begin();
1471 text_tlist::iterator packageend = packagelist.end();
1472 mvalue *macrovalue = NULL;
1473 while ((macrovalue == NULL) && (packagehere != packageend))
1474 {
1475 // first look in the currentmacros
1476 macrovalue = currentmacros->macro_find(*packagehere, macroname);
1477 if (macrovalue == NULL)
1478 macrovalue = currentmacros->macro_find("Style", macroname);
1479
1480 // look in the default macros
1481 if (macrovalue == NULL)
1482 {
1483 // next look in the defaultmacros
1484 if (defaultmacros->macro_find (*packagehere, macroname) != NULL)
1485 {
1486 paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
1487 while ((macrovalue == NULL) && (paramhere != paramend))
1488 {
1489// cerr << text_t2ascii << "\npackage: " << *packagehere << "\n";
1490// cerr << text_t2ascii << "macroname: " << macroname << "\n";
1491// cerr << text_t2ascii << "param: " << (*paramhere).param << "\n";
1492// cerr << "spec: " << (int)((*paramhere).spec) << "\n";
1493 macrovalue = defaultmacros->parameter_find(*packagehere, macroname,
1494 (*paramhere).param);
1495 paramhere++;
1496 }
1497 }
1498 }
1499
1500 // and again in the package "Style"
1501 if (macrovalue == NULL)
1502 {
1503 // next look in the defaultmacros
1504 if (defaultmacros->macro_find ("Style", macroname) != NULL)
1505 {
1506 paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
1507 while ((macrovalue == NULL) && (paramhere != paramend))
1508 {
1509 macrovalue = defaultmacros->parameter_find("Style", macroname,
1510 (*paramhere).param);
1511 paramhere++;
1512 }
1513 }
1514 }
1515 if (macrovalue == NULL) packagehere++;
1516 }
1517
1518 if (macrovalue != NULL)
1519 {
1520 // we found a macro
1521
1522 // replace all the option macros (_1_, _2_, ...) in the value of this macro
1523 // and decide if we need to expand the value of this macro
1524 bool needsexpansion = false;
1525 text_t tempmacrovalue;
1526 tempmacrovalue.clear();
1527 hereit = macrovalue->value.begin();
1528 endit = macrovalue->value.end();
1529 if (hereit != endit) c = (*hereit);
1530 while (hereit != endit)
1531 {
1532 if (c == '\\')
1533 {
1534 // found an escape character
1535 needsexpansion = true;
1536 tempmacrovalue.push_back(c);
1537 c = my_ttnextchar (hereit, endit);
1538 if (hereit != endit) tempmacrovalue.push_back(c);
1539 c = my_ttnextchar (hereit, endit);
1540 }
1541 else if (c == '_')
1542 {
1543 text_t::const_iterator savedhereit = hereit;
1544 unsigned short c2 = my_ttnextchar (hereit, endit);
1545 unsigned short c3 = my_ttnextchar (hereit, endit);
1546 if ((c2 >= '1') && (c2 <= '9') && (c3 == '_'))
1547 {
1548 // found an option macro, append the appropriate text
1549 text_tlist::iterator ttlisthere = splitmacroparam.begin();
1550 text_tlist::iterator ttlistend = splitmacroparam.end();
1551 while ((c2 > '1') && (ttlisthere != ttlistend))
1552 {
1553 c2--;
1554 ttlisthere++;
1555 }
1556 if (ttlisthere != ttlistend) {
1557 tempmacrovalue.append(*ttlisthere);
1558 if (findchar((*ttlisthere).begin(), (*ttlisthere).end(), '_') != (*ttlisthere).end())
1559 needsexpansion = true;
1560 }
1561
1562 c = my_ttnextchar (hereit, endit);
1563
1564 }
1565 else
1566 {
1567 // wasn't a option macro
1568 needsexpansion = true;
1569 tempmacrovalue.push_back(c);
1570 hereit = savedhereit;
1571 c = my_ttnextchar (hereit, endit);
1572 }
1573 }
1574 else
1575 {
1576 tempmacrovalue.push_back(c);
1577 c = my_ttnextchar (hereit, endit);
1578 }
1579 }
1580
1581 // recursively replace this macro (if we need to)
1582 if (needsexpansion) {
1583 expandstring (*packagehere, tempmacrovalue, outputtext, recursiondepth+1);
1584 } else {
1585 outputtext += tempmacrovalue;
1586 }
1587
1588 return true;
1589 }
1590
1591 if (logout != NULL) {
1592 (*logout) << text_t2ascii << "Warning: _" <<
1593 macropackage << ":" << macroname << "_ not found\n";
1594 }
1595
1596 return false; // didn't find the macro
1597}
1598
1599
1600void displayclass::printdefaultmacros ()
1601{
1602 defpackagemap::const_iterator packagemapit;
1603 defmacromap::const_iterator macromapit;
1604 defparammap::const_iterator parammapit;
1605 const mvalue *mvalueptr;
1606 outconvertclass text_t2ascii;
1607
1608 text_t packagename, macroname, macroparam;
1609
1610 for (packagemapit = defaultmacros->package_begin();
1611 packagemapit != defaultmacros->package_end();
1612 packagemapit++)
1613 {
1614 packagename = (*packagemapit).first;
1615 // cerr << "***package : \"" << packagename << "\"\n";
1616
1617 for (macromapit = (*packagemapit).second.begin();
1618 macromapit != (*packagemapit).second.end();
1619 macromapit++)
1620 {
1621 macroname = (*macromapit).first;
1622 // cerr << "***macroname : \"" << macroname << "\"\n";
1623
1624 for (parammapit = (*macromapit).second.begin();
1625 parammapit != (*macromapit).second.end();
1626 parammapit++)
1627 {
1628 macroparam = (*parammapit).first;
1629 mvalueptr = &((*parammapit).second);
1630 cerr << text_t2ascii << "package : \"" << packagename << "\"\n";
1631 cerr << text_t2ascii << "macroname : \"" << macroname << "\"\n";
1632 cerr << text_t2ascii << "parameters: [" << macroparam << "]\n";
1633 cerr << text_t2ascii << "filename : \"" << mvalueptr->filename << "\"\n";
1634 cerr << text_t2ascii << "value : {" << mvalueptr->value << "}\n\n";
1635 }
1636 }
1637 }
1638}
1639
1640void displayclass::printallparams ()
1641{
1642 text_tset::iterator text_tsetit;
1643 outconvertclass text_t2ascii;
1644
1645 cerr << text_t2ascii << "** allparams\n";
1646 for (text_tsetit=allparams.begin();
1647 text_tsetit!=allparams.end();
1648 text_tsetit++) {
1649 cerr << text_t2ascii << (*text_tsetit) << "\n";
1650 }
1651 cerr << text_t2ascii << "\n";
1652}
1653
1654
1655
1656/////////////////////////////////////
1657// stuff to do tricky output
1658/////////////////////////////////////
1659
1660displayclass &operator<< (outconvertclass &theoutc, displayclass &display)
1661{
1662 display.setconvertclass (&theoutc);
1663 return display;
1664}
1665
1666displayclass &operator<< (displayclass &display, const text_t &t)
1667{
1668 outconvertclass *theoutc = display.getconvertclass();
1669
1670 if (theoutc == NULL) return display;
1671
1672 text_t output;
1673 display.expandstring (t, output);
1674 (*theoutc) << output;
1675
1676 return display;
1677}
1678
Note: See TracBrowser for help on using the repository browser.