source: main/tags/2.13/gsdl/lib/display.cpp@ 24552

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

fixed some compiler warnings

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