source: trunk/greenorg/lib/display.cpp@ 13640

Last change on this file since 13640 was 5503, checked in by sjboddie, 21 years ago

* empty log message *

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