source: branches/corba/gsdl/lib/display.cpp@ 1074

Last change on this file since 1074 was 1067, checked in by cs025, 24 years ago

Corba first commit

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