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

Last change on this file since 1495 was 1495, checked in by sjboddie, 24 years ago

Disabled a warning message from within the macro language stuff

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 45.1 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 = &cerr;
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 &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()) fin.get(c1);
627 if (!fin.eof()) fin.get(c2);
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 fin.get(c1);
646 if (c1 == 0xfe || c1 == 0xff) {
647 // switch to unicode
648 isunicode = 1;
649 if (!fin.eof()) fin.get(c2);
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()) fin.get(c2);
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()) fin.get(c2);
671 if (!fin.eof()) fin.get(c3);
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
702 if (fin.fail()) return -1; // read failed
703
704 text_t package = "Global";
705 int line = 1;
706 int isunicode = 0, bigendian = 1;
707
708 // pre-fetch the next character
709 unsigned short c = my_uni_get(fin, line, isunicode, bigendian);
710
711 text_t macropackage, macroname, macroparameters, macrovalue;
712 int err; // for keeping track of whether an error occurred somewhere
713
714 while (!fin.eof()) {
715 // expect: white space, comment, "package", or macroname
716 if (is_unicode_space(c)) {
717 // found some white-space
718 c = my_uni_get(fin, line, isunicode, bigendian);
719
720 } else if (c == '#') {
721 // found the start of a comment
722 // skip all characters up to the end of the line
723 c = my_uni_get(fin, line, isunicode, bigendian); // skip the '#'
724 while (!fin.eof ()) {
725 if (c == '\n') break;
726 c = my_uni_get(fin, line, isunicode, bigendian);
727 }
728
729 } else if (c == 'p') {
730 // found the start of 'package' (hopefully)
731 // get everything up to the next space
732 text_t tmp;
733 while (!fin.eof() && my_isalpha(c)) {
734 tmp.push_back(c);
735 c = my_uni_get(fin, line, isunicode, bigendian);
736 }
737 // see if we have a package name
738 if (tmp == "package") {
739 // skip all white space
740 while (!fin.eof() && is_unicode_space(c))
741 c = my_uni_get(fin, line, isunicode, bigendian);
742
743 // get the package name
744 tmp.clear(); // init tmp
745 while (!fin.eof() && my_isalpha(c)) {
746 tmp.push_back(c);
747 c = my_uni_get(fin, line, isunicode, bigendian);
748 }
749 package = tmp;
750 if (package.empty()) package = "Global";
751
752 } else {
753 // error
754 if (logout != NULL) {
755 (*logout) << text_t2ascii << "Expected 'package' on line " << line
756 << " of " << thisfilename << "\n";
757 }
758 }
759
760 } else if (c == '_') {
761 // found the start of a macro (hopefully)
762 c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
763
764 // init variables
765 err = 0;
766 macropackage = package;
767 macroname.clear(); // init macroname
768 macroparameters.clear(); // init macroname
769 macrovalue.clear(); // init macroname
770
771 // get the macro name
772 while ((!fin.eof()) && (!is_unicode_space(c)) &&
773 (c != '\\') && (c != '_') &&(c != ':') &&
774 (macroname.size() < 80)) {
775 macroname.push_back(c);
776 c = my_uni_get(fin, line, isunicode, bigendian);
777 }
778
779 if (c == ':') {
780 // we actually had the macro package
781 c = my_uni_get(fin, line, isunicode, bigendian); // skip :
782 macropackage = macroname;
783 macroname.clear ();
784
785 // get the macro name (honest!)
786 while ((!fin.eof()) && (!is_unicode_space(c)) &&
787 (c != '\\') && (c != '_') &&(c != ':') &&
788 (macroname.size() < 80)) {
789 macroname.push_back(c);
790 c = my_uni_get(fin, line, isunicode, bigendian);
791 }
792 }
793
794 if (!err && c == '_') {
795 c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
796
797 // skip all white space
798 while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
799 } else if (!err) err = 1;
800
801 // get the macro parameters (optional)
802 if (!err && c == '[') {
803 c = my_uni_get(fin, line, isunicode, bigendian); // skip the [
804 while ((!fin.eof()) && (c != '\n') && (c != '\\') && (c != ']')) {
805 macroparameters.push_back(c);
806 c = my_uni_get(fin, line, isunicode, bigendian);
807 }
808
809 if (c == ']') {
810 c = my_uni_get(fin, line, isunicode, bigendian); // skip the ]
811
812 // skip all white space
813 while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
814 }
815 else if (!err) err = 2;
816 }
817
818 // get the macro value
819 if (!err && c == '{') {
820 c = my_uni_get(fin, line, isunicode, bigendian); // skip the {
821 while ((!fin.eof()) && (c != '}')) {
822 if (c == '\\') {
823 macrovalue.push_back(c); // keep the '\'
824 c = my_uni_get(fin, line, isunicode, bigendian); // store the *next* value regardless
825 if (!fin.eof()) macrovalue.push_back(c);
826 c = my_uni_get(fin, line, isunicode, bigendian);
827 }
828 macrovalue.push_back(c);
829 c = my_uni_get(fin, line, isunicode, bigendian);
830 }
831
832 if (c == '}') {
833 c = my_uni_get(fin, line, isunicode, bigendian); // skip the }
834
835 // define the macro
836 err = setdefaultmacro (macropackage, macroname, macroparameters,
837 thisfilename, macrovalue);
838 if ((err == -1 || err == -3) && logout != NULL) {
839 (*logout) << text_t2ascii << "Warning: redefinition of _" <<
840 package << ":" << macroname << "_[" << macroparameters <<
841 "] on line ";
842 (*logout) << line;
843 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
844
845 } else if (err == -2 && logout != NULL) {
846 // I don't think we really want this warning since it's a very
847 // common occurance - Stefan.
848
849 // (*logout) << text_t2ascii << "Warning: _" <<
850 // package << ":" << macroname << "_[" << macroparameters <<
851 // "] on line ";
852 // (*logout) << line;
853 // (*logout) << text_t2ascii << " of " <<
854 // thisfilename << " hides a Global macro with the same name\n";
855
856 } else if (err == -4 && logout != NULL) {
857 (*logout) << text_t2ascii << "Error: macro name expected on line ";
858 (*logout) << line ;
859 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
860 }
861
862 err = 0; // for the test below
863 }
864 else if (!err) err = 3;
865 }
866 else if (!err) err = 4;
867
868 if (err) {
869 // found an error, skip to the end of the line
870 if (logout != NULL) {
871 (*logout) << text_t2ascii << "Error: ";
872 if (err == 1) (*logout) << text_t2ascii << "'_'";
873 else if (err == 2) (*logout) << text_t2ascii << "']'";
874 else if (err == 3) (*logout) << text_t2ascii << "'}'";
875 else if (err == 4) (*logout) << text_t2ascii << "'{'";
876 (*logout) << text_t2ascii << " expected on line ";
877 (*logout) << line ;
878 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
879 }
880 while (!fin.eof ()) {
881 if (c == '\n') break;
882 c = my_uni_get(fin, line, isunicode, bigendian);
883 }
884 }
885
886 } else {
887 // found an error, skip to the end of the line
888 if (logout != NULL) {
889 (*logout) << text_t2ascii << "Error: Unexpected input on line " << line
890 << " of " << thisfilename << "\n";
891 }
892 while (!fin.eof ()) {
893 if (c == '\n') break;
894 c = my_uni_get(fin, line, isunicode, bigendian);
895 }
896
897 }
898 }
899
900 fin.close ();
901
902 // free up memory
903 delete filenamestr;
904 return 0;
905}
906
907
908// prepares to create a page.
909void displayclass::openpage (const text_t &thispageparams,
910 const text_t &thisprecedence)
911{
912 // init variables
913 currentmacros->clear();
914
915 // reload any default macro files which have changed.
916 if (checkdefaultmacrofiles() < 0)
917 {
918 // print error message
919 }
920
921 setpageparams (thispageparams, thisprecedence);
922}
923
924
925// changes the parameters for the current page.
926void displayclass::setpageparams (text_t thispageparams,
927 text_t thisprecedence)
928{
929 paramhashtype thissplitparams, splittheseparams;
930 precedencetype precedhash;
931 text_tset::iterator text_tsetit;
932 paramspec tmpps;
933
934 precedence = thisprecedence;
935 calcprecedence(thisprecedence, precedhash);
936
937 splitparams(thispageparams, thissplitparams);
938 joinparams(thissplitparams, thispageparams);
939 params = thispageparams;
940
941 // get a list of parameters with their specificness
942 orderparamlist->erase(orderparamlist->begin(), orderparamlist->end());
943 for (text_tsetit=allparams.begin();
944 text_tsetit!=allparams.end();
945 text_tsetit++)
946 {
947 tmpps.param = (*text_tsetit);
948 splitparams(tmpps.param, splittheseparams);
949 tmpps.spec = getspecificness(thissplitparams, splittheseparams, precedhash);
950 if (tmpps.spec >= 0)
951 {
952 orderparamlist->push_back (tmpps);
953 }
954 }
955
956 // sort the list
957 sort(orderparamlist->begin(), orderparamlist->end());
958
959// paramspeclist::iterator pshere = orderparamlist->begin();
960// paramspeclist::iterator psend = orderparamlist->end();
961// while (pshere != psend)
962// {
963// cerr << text_t2ascii << "param=" << (*pshere).param;
964// cerr << " spec=" << (int)((*pshere).spec) << "\n";
965// pshere++;
966// }
967}
968
969
970// overrides (or sets) a macro for the current page.
971// returns 0 if there was no error,
972// -1 if it redefined a macro
973// -4 if no macroname was supplied
974int displayclass::setmacro (const text_t &macroname,
975 text_t package,
976 const text_t &macrovalue)
977{
978 // make sure a macroname was supplied
979 if (macroname.empty()) return -4;
980
981 // make package "Global" if it doesn't point to anything yet
982 if (package.empty()) package = "Global";
983
984 // set the macro
985 return currentmacros->setmacro(package, macroname, "memory", macrovalue);
986}
987
988
989void displayclass::expandstring (const text_t &inputtext, text_t &outputtext)
990{
991 expandstring("", inputtext, outputtext);
992}
993
994
995void displayclass::expandstring (text_t package, const text_t &inputtext,
996 text_t &outputtext, int recursiondepth)
997{
998 text_t macroname, macropackage, macroargs;
999 text_t::const_iterator tthere = inputtext.begin();
1000 text_t::const_iterator ttend = inputtext.end();
1001 unsigned short c = '\0';
1002
1003 if (package.empty()) package = "Global";
1004
1005 outputtext.clear();
1006
1007 // use one-character lookahead
1008 if (tthere != ttend) c = (*tthere);
1009 while (tthere != ttend)
1010 {
1011 if (c == '\\')
1012 {
1013 // found an escape character
1014 c = my_ttnextchar (tthere, ttend); // skip the escape character
1015 if (tthere != ttend)
1016 {
1017 if (c == 'n') outputtext.push_back('\n');
1018 else if (c == 't') outputtext.push_back('\t');
1019 else outputtext.push_back(c);
1020 }
1021 c = my_ttnextchar (tthere, ttend);
1022
1023 }
1024 else if (c == '_')
1025 {
1026 // might have found the start of a macro
1027
1028 // embedded macros (macros within the names
1029 // of other macros) are no longer supported -- Rodger.
1030
1031 // save the current state (in case we need to back out)
1032 text_t::const_iterator savedtthere = tthere;
1033 unsigned short savedc = c;
1034
1035 macroname.clear();
1036 macropackage = package;
1037 macroargs.clear();
1038
1039 c = my_ttnextchar (tthere, ttend); // skip the '_'
1040
1041 // get the macroname
1042 while (tthere != ttend && (!is_unicode_space(c)) &&
1043 (c != '\\') && (c != '_') &&(c != ':') &&
1044 (macroname.size() < 80))
1045 {
1046 macroname.push_back((unsigned char)c);
1047 c = my_ttnextchar (tthere, ttend);
1048 }
1049
1050 if (c == ':')
1051 {
1052 // we actually had the macro package
1053 c = my_ttnextchar (tthere, ttend);
1054 macropackage = macroname;
1055 macroname.clear ();
1056
1057 // get the macro name (honest!)
1058 while ((tthere != ttend) && (!is_unicode_space(c)) &&
1059 (c != '\\') && (c != '_') &&(c != ':') &&
1060 (macroname.size() < 80))
1061 {
1062 macroname.push_back((unsigned char)c);
1063 c = my_ttnextchar (tthere, ttend);
1064 }
1065 }
1066
1067 if ((tthere != ttend) && (c == '_') &&
1068 (macroname.size() > 0))
1069 {
1070 // found a macro!!!! (maybe)
1071
1072 c = my_ttnextchar (tthere, ttend); // skip the '_'
1073
1074 // get the parameters (if there are any)
1075 if ((tthere != ttend) && (c == '('))
1076 {
1077 c = my_ttnextchar (tthere, ttend); // skip '('
1078
1079 // have to be careful of quotes
1080 unsigned short quote = '\0';
1081 while (tthere != ttend)
1082 {
1083 if (c == '\\')
1084 {
1085 // have an escape character, save escape
1086 // character and next character as well
1087 macroargs.push_back (c);
1088 c = my_ttnextchar (tthere, ttend);
1089
1090 }
1091 else if (quote == '\0')
1092 {
1093 // not in a quote at the moment
1094 if (c == ')')
1095 {
1096 // found end of the arguments
1097 c = my_ttnextchar (tthere, ttend); // skip ')'
1098 break;
1099
1100 }
1101 else if (c == '\'' || c == '\"')
1102 {
1103 // found a quote
1104 quote = c;
1105 }
1106
1107 }
1108 else
1109 {
1110 // we are in a quote
1111 if (c == quote) quote = '\0';
1112 }
1113
1114 // save this character
1115 if (tthere != ttend) macroargs.push_back (c);
1116 c = my_ttnextchar (tthere, ttend);
1117 }
1118 }
1119
1120 //
1121 // we now have the macropackage, macroname, and macroargs
1122 //
1123
1124 // try to expand out this macro
1125 text_t expandedmacro;
1126 if (macro (macroname, macropackage, macroargs, expandedmacro, recursiondepth))
1127 {
1128 // append the expanded macro
1129 outputtext += expandedmacro;
1130 }
1131 else
1132 {
1133 // wasn't a macro
1134 tthere = savedtthere;
1135 c = savedc;
1136 outputtext.push_back(c); // the '_'
1137 c = my_ttnextchar (tthere, ttend);
1138 }
1139
1140
1141 }
1142 else
1143 {
1144 // wasn't a macro
1145 tthere = savedtthere;
1146 c = savedc;
1147 outputtext.push_back(c); // the '_'
1148 c = my_ttnextchar (tthere, ttend);
1149 }
1150
1151 }
1152 else
1153 {
1154 // nothing of interest
1155 outputtext.push_back(c); // the '_'
1156 c = my_ttnextchar (tthere, ttend);
1157 }
1158 }
1159}
1160
1161ostream *displayclass::setlogout (ostream *thelogout) {
1162
1163 ostream *oldlogout = logout;
1164 logout = thelogout;
1165 return oldlogout;
1166}
1167
1168// protected methods for display
1169
1170// reloads any default macro files which have changed
1171// returns 0 no errors occurred
1172// -1 an error occurred while trying to load one of the files
1173int displayclass::checkdefaultmacrofiles ()
1174{
1175 // this isn't implemented yet
1176 return 0;
1177}
1178
1179// isdefaultmacro sees if there is an entry in the list of
1180// default macros with the given package and macro name
1181// returns 0 if no macros in the package or in the global package
1182// were found
1183// 1 if no macros in the package were found but a macro
1184// in the global package was found
1185// 2 if a macro in the given package was found
1186int displayclass::isdefaultmacro (text_t package, const text_t &macroname) {
1187 // make sure a macroname was supplied
1188 if (macroname.empty()) return 0;
1189
1190 // make package "Global" if it doesn't point to anything yet
1191 if (package.empty()) package = "Global";
1192
1193 // check the given package
1194 if (defaultmacros->macro_find(package, macroname) != NULL) return 2;
1195
1196 // check the Global package
1197 if (defaultmacros->macro_find("Global", macroname) != NULL) return 1;
1198
1199 return 0;
1200}
1201
1202
1203// setdefaultmacro adds an entry to the list of default macros
1204// returns 0 if there was no error,
1205// -1 if it redefined a macro
1206// -2 if it hid a Global macro
1207// -3 if it redefined a macro and hid a Global macro
1208// -4 if no macroname was supplied
1209int displayclass::setdefaultmacro (text_t package, const text_t &macroname,
1210 text_t params, const text_t &filename,
1211 const text_t &macrovalue)
1212{
1213 // make sure a macroname was supplied
1214 if (macroname.empty()) return -4;
1215
1216 // put the parameters in a standard form
1217 paramhashtype paramhash;
1218 if (params.empty()) params = "ignore=yes";
1219 splitparams (params, paramhash);
1220 joinparams (paramhash, params);
1221
1222 // make package "Global" if it doesn't point to anything yet
1223 if (package.empty()) package = "Global";
1224
1225 // remember these parameters
1226 allparams.insert (params);
1227
1228 // remember this filename (this part isn't finished yet -- Rodger).
1229
1230 // set the macro
1231 return defaultmacros->setmacro(package, macroname, params, filename, macrovalue);
1232}
1233
1234
1235// evaluates a boolean expression
1236// returns false if expr equals "" or "0".
1237// otherwise returns true *unless* expr is
1238// format "XXXX" eq/ne "dddd" in which case
1239// the two quoted strings are compared
1240bool displayclass::boolexpr (text_t package, const text_t &expr, int recursiondepth) {
1241
1242 if (expr.empty()) return false;
1243
1244 text_t expexpr;
1245 if (package.empty()) package = "Global";
1246 expandstring (package, expr, expexpr, recursiondepth);
1247
1248 if (expexpr.empty() || expexpr == "0") return false;
1249 if (expr[0] != '\"') return true;
1250
1251 // don't use expexpr while separating quoted parts of
1252 // expression just in case expanded out macros contain
1253 // quotes
1254 text_t::const_iterator here = expr.begin();
1255 text_t::const_iterator end = expr.end();
1256
1257 int quotecount = 0;
1258 text_t string1, expstring1;
1259 text_t string2, expstring2;
1260 text_t op;
1261 text_t combineop;
1262 bool result = false; // an empty string is false
1263 bool result2 = false;
1264
1265 while (here != end) {
1266 // get a comparison
1267 quotecount = 0;
1268 string1.clear();
1269 string2.clear();
1270 op.clear();
1271 while (here != end) {
1272 if (*here == '"') quotecount++;
1273 else if (quotecount == 1) string1.push_back(*here);
1274 else if ((quotecount == 2) && !is_unicode_space (*here))
1275 op.push_back(*here);
1276 else if (quotecount == 3) string2.push_back(*here);
1277 else if (quotecount >= 4) break;
1278 here ++;
1279 }
1280
1281 expandstring (package, string1, expstring1, recursiondepth);
1282 expandstring (package, string2, expstring2, recursiondepth);
1283
1284 // get next result
1285 result2 = true; // any badly formatted string will return true
1286 if (op == "eq") result2 = (expstring1 == expstring2);
1287 else if (op == "ne") result2 = (expstring1 != expstring2);
1288 else if (op == "gt") result2 = (expstring1 > expstring2);
1289 else if (op == "ge") result2 = (expstring1 >= expstring2);
1290 else if (op == "lt") result2 = (expstring1 < expstring2);
1291 else if (op == "le") result2 = (expstring1 <= expstring2);
1292 else if (op == "==") result2 = (expstring1.getint() == expstring2.getint());
1293 else if (op == "!=") result2 = (expstring1.getint() != expstring2.getint());
1294 else if (op == ">") result2 = (expstring1.getint() > expstring2.getint());
1295 else if (op == ">=") result2 = (expstring1.getint() >= expstring2.getint());
1296 else if (op == "<") result2 = (expstring1.getint() < expstring2.getint());
1297 else if (op == "<=") result2 = (expstring1.getint() <= expstring2.getint());
1298
1299 // combine the results
1300 if (combineop == "&&") result = (result && result2);
1301 else if (combineop == "||") result = (result || result2);
1302 else result = result2;
1303
1304 // get next combination operator
1305 combineop.clear();
1306 while (here != end && *here != '"') {
1307 if (!is_unicode_space(*here)) combineop.push_back(*here);
1308 here++;
1309 }
1310 }
1311
1312 return result;
1313}
1314
1315
1316// (recursively) expand out a macro
1317// returns true if the macro was found
1318// false if the macro was not found
1319bool displayclass::macro (const text_t &macroname, text_t macropackage,
1320 const text_t &macroparam, text_t &outputtext,
1321 int recursiondepth)
1322{
1323 outconvertclass text_t2ascii;
1324 text_tlist splitmacroparam;
1325 text_t::const_iterator hereit, endit;
1326 text_t aparam;
1327 unsigned short c = '\0', quote = '\0';
1328
1329 // cerr << "r: " << recursiondepth << "\n";
1330
1331 // check for deep recursion
1332 if (recursiondepth >= MAXRECURSIONDEPTH)
1333 {
1334 if (logout != NULL)
1335 (*logout) << "Warning: deep recursion, limiting macro expansion\n";
1336 return false;
1337 }
1338
1339 // check the macropackage
1340 if (macropackage.empty()) macropackage = "Global";
1341
1342 // get the parameters (but don't expand them)
1343 if (macroparam.size() > 0) {
1344 // set up for loop
1345 hereit = macroparam.begin();
1346 endit = macroparam.end();
1347 if (hereit != endit) c = (*hereit);
1348
1349 while (hereit != endit) {
1350 // get the next parameter
1351 aparam.clear();
1352 quote = '\0'; // not-quoted unless proven quoted
1353
1354 // ignore initial whitespace
1355 while ((hereit!=endit)&&is_unicode_space(c)) c=my_ttnextchar(hereit,endit);
1356
1357 // look for the end of the parameter
1358 while (hereit != endit) {
1359 if (c == '\\') {
1360 // found escape character, also get next character
1361 aparam.push_back(c);
1362 c = my_ttnextchar (hereit, endit);
1363 if (hereit != endit) aparam.push_back(c);
1364
1365 } else if (quote=='\0' && (c=='\'' /*|| c=='"'*/)) {
1366 // found a quoted section
1367 quote = c;
1368 // aparam.push_back(c);
1369
1370 } else if (quote!='\0' && c==quote) {
1371 // found the end of a quote
1372 quote = '\0';
1373 // aparam.push_back(c);
1374
1375 } else if (quote=='\0' && c==',') {
1376 // found the end of a parameter
1377 c = my_ttnextchar (hereit, endit);
1378 break;
1379
1380 } else {
1381 // ordinary character
1382 aparam.push_back(c);
1383 }
1384
1385 c = my_ttnextchar (hereit, endit);
1386 }
1387
1388 // add this parameter to the list
1389 splitmacroparam.push_back(aparam);
1390 }
1391 }
1392
1393 if (macroname == "If") {
1394 // get the condition, then clause and else clause
1395 text_tlist::iterator paramcond = splitmacroparam.begin();
1396 text_tlist::iterator paramend = splitmacroparam.end();
1397 text_tlist::iterator paramthen = paramend;
1398 text_tlist::iterator paramelse = paramend;
1399
1400 if (paramcond != paramend) {
1401 paramthen = paramcond;
1402 paramthen++;
1403 }
1404 if (paramthen != paramend) {
1405 paramelse = paramthen;
1406 paramelse++;
1407 }
1408
1409 // will always output something
1410 outputtext.clear();
1411
1412 // expand out the first parameter
1413 if (paramcond != paramend) {
1414 text_t tmpoutput;
1415 expandstring (macropackage, *paramcond, tmpoutput, recursiondepth+1);
1416 lc (tmpoutput);
1417
1418 // test the expanded string
1419 if (boolexpr (macropackage, *paramcond, recursiondepth+1)) {
1420 //(tmpoutput.size()) && (tmpoutput != "false") && (tmpoutput != "0")) {
1421 // true
1422 if (paramthen != paramend)
1423 expandstring (macropackage, *paramthen, outputtext, recursiondepth+1);
1424
1425 } else {
1426 // false
1427 if (paramelse != paramend)
1428 expandstring (macropackage, *paramelse, outputtext, recursiondepth+1);
1429 }
1430 }
1431
1432 return true;
1433 }
1434
1435 // try and find this macro
1436
1437 // this list might be replaced by something a little more
1438 // sophisticated in the future.
1439 text_tlist packagelist;
1440 packagelist.push_back (macropackage);
1441 packagelist.push_back ("Global");
1442
1443 paramspeclist::iterator paramhere, paramend;
1444 text_tlist::iterator packagehere = packagelist.begin();
1445 text_tlist::iterator packageend = packagelist.end();
1446 mvalue *macrovalue = NULL;
1447 while ((macrovalue == NULL) && (packagehere != packageend))
1448 {
1449 // first look in the currentmacros
1450 macrovalue = currentmacros->macro_find(*packagehere, macroname);
1451 if (macrovalue == NULL)
1452 macrovalue = currentmacros->macro_find("Style", macroname);
1453
1454 // look in the default macros
1455 if (macrovalue == NULL)
1456 {
1457 // next look in the defaultmacros
1458 if (defaultmacros->macro_find (*packagehere, macroname) != NULL)
1459 {
1460 paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
1461 while ((macrovalue == NULL) && (paramhere != paramend))
1462 {
1463// cerr << text_t2ascii << "\npackage: " << *packagehere << "\n";
1464// cerr << text_t2ascii << "macroname: " << macroname << "\n";
1465// cerr << text_t2ascii << "param: " << (*paramhere).param << "\n";
1466// cerr << "spec: " << (int)((*paramhere).spec) << "\n";
1467 macrovalue = defaultmacros->parameter_find(*packagehere, macroname,
1468 (*paramhere).param);
1469 paramhere++;
1470 }
1471 }
1472 }
1473
1474 // and again in the package "Style"
1475 if (macrovalue == NULL)
1476 {
1477 // next look in the defaultmacros
1478 if (defaultmacros->macro_find ("Style", macroname) != NULL)
1479 {
1480 paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
1481 while ((macrovalue == NULL) && (paramhere != paramend))
1482 {
1483 macrovalue = defaultmacros->parameter_find("Style", macroname,
1484 (*paramhere).param);
1485 paramhere++;
1486 }
1487 }
1488 }
1489 if (macrovalue == NULL) packagehere++;
1490 }
1491
1492 if (macrovalue != NULL)
1493 {
1494 // we found a macro
1495
1496 // replace all the option macros (_1_, _2_, ...) in the value of this macro
1497 // and decide if we need to expand the value of this macro
1498 bool needsexpansion = false;
1499 text_t tempmacrovalue;
1500 tempmacrovalue.clear();
1501 hereit = macrovalue->value.begin();
1502 endit = macrovalue->value.end();
1503 if (hereit != endit) c = (*hereit);
1504 while (hereit != endit)
1505 {
1506 if (c == '\\')
1507 {
1508 // found an escape character
1509 needsexpansion = true;
1510 tempmacrovalue.push_back(c);
1511 c = my_ttnextchar (hereit, endit);
1512 if (hereit != endit) tempmacrovalue.push_back(c);
1513 c = my_ttnextchar (hereit, endit);
1514 }
1515 else if (c == '_')
1516 {
1517 text_t::const_iterator savedhereit = hereit;
1518
1519 // attempt to get a number
1520 int argnum = 0;
1521 unsigned short digc = my_ttnextchar (hereit, endit);
1522 while (digc >= '0' && digc <= '9') {
1523 argnum = argnum*10 + digc - '0';
1524 digc = my_ttnextchar (hereit, endit);
1525 }
1526 if (digc == '_' && argnum > 0) {
1527 // found an option macro, append the appropriate text
1528 text_tlist::iterator ttlisthere = splitmacroparam.begin();
1529 text_tlist::iterator ttlistend = splitmacroparam.end();
1530 while ((argnum > 1) && (ttlisthere != ttlistend)) {
1531 argnum--;
1532 ttlisthere++;
1533 }
1534 if (ttlisthere != ttlistend) {
1535 tempmacrovalue.append(*ttlisthere);
1536 if (findchar((*ttlisthere).begin(), (*ttlisthere).end(), '_') != (*ttlisthere).end())
1537 needsexpansion = true;
1538 }
1539
1540 c = my_ttnextchar (hereit, endit);
1541
1542 } else {
1543 // wasn't a option macro
1544 needsexpansion = true;
1545 tempmacrovalue.push_back(c);
1546 hereit = savedhereit;
1547 c = my_ttnextchar (hereit, endit);
1548 }
1549 }
1550 else
1551 {
1552 tempmacrovalue.push_back(c);
1553 c = my_ttnextchar (hereit, endit);
1554 }
1555 }
1556
1557 // recursively replace this macro (if we need to)
1558 if (needsexpansion) {
1559 expandstring (*packagehere, tempmacrovalue, outputtext, recursiondepth+1);
1560 } else {
1561 outputtext += tempmacrovalue;
1562 }
1563
1564 return true;
1565 }
1566
1567 if (logout != NULL) {
1568 (*logout) << text_t2ascii << "Warning: _" <<
1569 macropackage << ":" << macroname << "_ not found\n";
1570 }
1571
1572 return false; // didn't find the macro
1573}
1574
1575
1576void displayclass::printdefaultmacros ()
1577{
1578 defpackagemap::const_iterator packagemapit;
1579 defmacromap::const_iterator macromapit;
1580 defparammap::const_iterator parammapit;
1581 const mvalue *mvalueptr;
1582 outconvertclass text_t2ascii;
1583
1584 text_t packagename, macroname, macroparam;
1585
1586 for (packagemapit = defaultmacros->package_begin();
1587 packagemapit != defaultmacros->package_end();
1588 packagemapit++)
1589 {
1590 packagename = (*packagemapit).first;
1591 // cerr << "***package : \"" << packagename << "\"\n";
1592
1593 for (macromapit = (*packagemapit).second.begin();
1594 macromapit != (*packagemapit).second.end();
1595 macromapit++)
1596 {
1597 macroname = (*macromapit).first;
1598 // cerr << "***macroname : \"" << macroname << "\"\n";
1599
1600 for (parammapit = (*macromapit).second.begin();
1601 parammapit != (*macromapit).second.end();
1602 parammapit++)
1603 {
1604 macroparam = (*parammapit).first;
1605 mvalueptr = &((*parammapit).second);
1606 cerr << text_t2ascii << "package : \"" << packagename << "\"\n";
1607 cerr << text_t2ascii << "macroname : \"" << macroname << "\"\n";
1608 cerr << text_t2ascii << "parameters: [" << macroparam << "]\n";
1609 cerr << text_t2ascii << "filename : \"" << mvalueptr->filename << "\"\n";
1610 cerr << text_t2ascii << "value : {" << mvalueptr->value << "}\n\n";
1611 }
1612 }
1613 }
1614}
1615
1616void displayclass::printallparams ()
1617{
1618 text_tset::iterator text_tsetit;
1619 outconvertclass text_t2ascii;
1620
1621 cerr << text_t2ascii << "** allparams\n";
1622 for (text_tsetit=allparams.begin();
1623 text_tsetit!=allparams.end();
1624 text_tsetit++) {
1625 cerr << text_t2ascii << (*text_tsetit) << "\n";
1626 }
1627 cerr << text_t2ascii << "\n";
1628}
1629
1630
1631
1632/////////////////////////////////////
1633// stuff to do tricky output
1634/////////////////////////////////////
1635
1636displayclass &operator<< (outconvertclass &theoutc, displayclass &display)
1637{
1638 display.setconvertclass (&theoutc);
1639 return display;
1640}
1641
1642displayclass &operator<< (displayclass &display, const text_t &t)
1643{
1644 outconvertclass *theoutc = display.getconvertclass();
1645
1646 if (theoutc == NULL) return display;
1647
1648 text_t output;
1649 display.expandstring (t, output);
1650 (*theoutc) << output;
1651
1652 return display;
1653}
Note: See TracBrowser for help on using the repository browser.