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

Last change on this file since 534 was 534, checked in by sjboddie, 25 years ago

added gpl notice

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