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

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

removed limitation on the number of arguments that a macro can have

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