source: tags/gsdl-2_30d-distribution/gsdl/lib/display.cpp@ 2308

Last change on this file since 2308 was 1860, checked in by cs025, 23 years ago

Included CORBA branch for first time

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