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

Last change on this file since 6021 was 6021, checked in by sjboddie, 20 years ago

Added an unloaddefaultmacros() function to displayclass to allow us to
unload all the macros before reloading them again from the macro files.

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