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

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

Correcting a correction - reinstated all lib files due to silly
CVS confusion.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 46.8 KB
Line 
1/**********************************************************************
2 *
3 * display.cpp -- Context sensitive macro language
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * $Id: display.cpp 1076 2000-04-06 19:58:04Z cs025 $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.19 2000/04/06 19:57:58 cs025
31 Correcting a correction - reinstated all lib files due to silly
32 CVS confusion.
33
34 Revision 1.17 2000/02/29 21:00:38 sjboddie
35 fixed some compiler warnings
36
37 Revision 1.16 1999/11/25 21:53:08 sjboddie
38 fixed bug in logout
39
40 Revision 1.15 1999/09/24 02:25:35 rjmcnab
41 removed limitation on the number of arguments that a macro can have
42
43 Revision 1.14 1999/09/07 04:57:41 sjboddie
44 added gpl notice
45
46 Revision 1.13 1999/08/31 07:59:11 rjmcnab
47 Generalised spaces to unicode spaces, added ability to automatically detect
48 whether the input file is Unicode or UTF-8 and read the file in the
49 appropriate way, and improved the error messages slightly.
50
51 Revision 1.12 1999/07/21 20:46:12 rjmcnab
52 fixed small bug
53
54 Revision 1.11 1999/07/21 07:26:30 rjmcnab
55 Added more operators to _If_, changed quoting of parameters so that
56 ' can be used to quote but it is removed, and made slight optimisation
57 so that macros that don't contain other macros aren't expanded.
58
59 Revision 1.10 1999/03/01 20:39:54 sjboddie
60
61 Added eq and ne functionality to _If_
62
63 Revision 1.9 1999/03/01 01:18:09 sjboddie
64
65 Fixed bug in _If_ when value being tested was only one character
66 long (e.g. "0" or "1")
67
68 Revision 1.8 1999/02/28 23:15:29 rjmcnab
69
70 Made _If_ recognise 'false' and '0' as being false.
71
72 Revision 1.7 1999/02/08 01:26:11 rjmcnab
73
74 Improved the error reporting.
75
76 Revision 1.6 1999/01/19 08:30:23 rjmcnab
77
78 Added a method to determine whether a macro has been defined.
79
80 Revision 1.5 1999/01/19 01:38:12 rjmcnab
81
82 Made the source more portable.
83
84 Revision 1.4 1999/01/12 01:50:57 rjmcnab
85
86 Standard header.
87
88 Revision 1.3 1999/01/08 02:33:13 rjmcnab
89
90 Added standard header to source files.
91
92 */
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 (istream &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 if (!fin.eof()) fin.get(c1);
695 if (!fin.eof()) fin.get(c2);
696 else c1 = 0;
697
698 // if they indicate the order get the next character
699 // otherwise just get these characters
700 if (c1 == 0xff && c2 == 0xfe) {
701 bigendian = 0;
702 c = my_uni_get (fin, line, isunicode, bigendian);
703 } else if (c1 == 0xfe && c2 == 0xff) {
704 bigendian = 1;
705 c = my_uni_get (fin, line, isunicode, bigendian);
706 } else c = (bigendian) ? (c1*256+c2) : (c2*256+c1);
707
708 } else {
709 // utf-8 text
710 // how many characters we get depends on what we find
711 unsigned char c1 = 0, c2 = 0, c3 = 0;
712 while (!fin.eof()) {
713 fin.get(c1);
714 if (c1 == 0xfe || c1 == 0xff) {
715 // switch to unicode
716 isunicode = 1;
717 if (!fin.eof()) fin.get(c2);
718
719 if (c1 == 0xff && c2 == 0xfe) bigendian = 0;
720 else bigendian = 1;
721
722 c = my_uni_get (fin, line, isunicode, bigendian);
723 break;
724
725 } else if (c1 <= 0x7f) {
726 // one byte character
727 c = c1;
728 break;
729
730 } else if (c1 >= 0xc0 && c1 <= 0xdf) {
731 // two byte character
732 if (!fin.eof()) fin.get(c2);
733 c = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
734 break;
735
736 } else if (c1 >= 0xe0 && c1 <= 0xef) {
737 // three byte character
738 if (!fin.eof()) fin.get(c2);
739 if (!fin.eof()) fin.get(c3);
740 c = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) + (c3 & 0x3f);
741 break;
742 }
743
744 // if we get here there was an error in the file, we should
745 // be able to recover from it however, maybe the file is in
746 // another encoding
747 }
748 }
749
750 if (c == '\n') line++;
751 return c;
752}
753
754
755
756// loads a default macro file (if it isn't already loaded)
757// returns 0 if didn't need to load the file (it was already loaded)
758// 1 if was (re)loaded
759// -1 an error occurred while trying to load the file
760int displayclass::loaddefaultmacros (text_t thisfilename) {
761 // convert the filename to a C string
762 char *filenamestr = thisfilename.getcstr();
763 outconvertclass text_t2ascii;
764
765 // see if we need to open this file -- this isn't implemented yet
766
767 // open the file
768 ifstream fin(filenamestr);
769 if (fin.fail()) return -1; // read failed
770
771 text_t package = "Global";
772 int line = 1;
773 int isunicode = 0, bigendian = 1;
774
775 // pre-fetch the next character
776 unsigned short c = my_uni_get(fin, line, isunicode, bigendian);
777
778 text_t macropackage, macroname, macroparameters, macrovalue;
779 int err; // for keeping track of whether an error occurred somewhere
780
781 while (!fin.eof()) {
782 // expect: white space, comment, "package", or macroname
783 if (is_unicode_space(c)) {
784 // found some white-space
785 c = my_uni_get(fin, line, isunicode, bigendian);
786
787 } else if (c == '#') {
788 // found the start of a comment
789 // skip all characters up to the end of the line
790 c = my_uni_get(fin, line, isunicode, bigendian); // skip the '#'
791 while (!fin.eof ()) {
792 if (c == '\n') break;
793 c = my_uni_get(fin, line, isunicode, bigendian);
794 }
795
796 } else if (c == 'p') {
797 // found the start of 'package' (hopefully)
798 // get everything up to the next space
799 text_t tmp;
800 while (!fin.eof() && my_isalpha(c)) {
801 tmp.push_back(c);
802 c = my_uni_get(fin, line, isunicode, bigendian);
803 }
804 // see if we have a package name
805 if (tmp == "package") {
806 // skip all white space
807 while (!fin.eof() && is_unicode_space(c))
808 c = my_uni_get(fin, line, isunicode, bigendian);
809
810 // get the package name
811 tmp.clear(); // init tmp
812 while (!fin.eof() && my_isalpha(c)) {
813 tmp.push_back(c);
814 c = my_uni_get(fin, line, isunicode, bigendian);
815 }
816 package = tmp;
817 if (package.empty()) package = "Global";
818
819 } else {
820 // error
821 if (logout != NULL) {
822 (*logout) << text_t2ascii << "Expected 'package' on line " << line
823 << " of " << thisfilename << "\n";
824 }
825 }
826
827 } else if (c == '_') {
828 // found the start of a macro (hopefully)
829 c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
830
831 // init variables
832 err = 0;
833 macropackage = package;
834 macroname.clear(); // init macroname
835 macroparameters.clear(); // init macroname
836 macrovalue.clear(); // init macroname
837
838 // get the macro name
839 while ((!fin.eof()) && (!is_unicode_space(c)) &&
840 (c != '\\') && (c != '_') &&(c != ':') &&
841 (macroname.size() < 80)) {
842 macroname.push_back(c);
843 c = my_uni_get(fin, line, isunicode, bigendian);
844 }
845
846 if (c == ':') {
847 // we actually had the macro package
848 c = my_uni_get(fin, line, isunicode, bigendian); // skip :
849 macropackage = macroname;
850 macroname.clear ();
851
852 // get the macro name (honest!)
853 while ((!fin.eof()) && (!is_unicode_space(c)) &&
854 (c != '\\') && (c != '_') &&(c != ':') &&
855 (macroname.size() < 80)) {
856 macroname.push_back(c);
857 c = my_uni_get(fin, line, isunicode, bigendian);
858 }
859 }
860
861 if (!err && c == '_') {
862 c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
863
864 // skip all white space
865 while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
866 } else if (!err) err = 1;
867
868 // get the macro parameters (optional)
869 if (!err && c == '[') {
870 c = my_uni_get(fin, line, isunicode, bigendian); // skip the [
871 while ((!fin.eof()) && (c != '\n') && (c != '\\') && (c != ']')) {
872 macroparameters.push_back(c);
873 c = my_uni_get(fin, line, isunicode, bigendian);
874 }
875
876 if (c == ']') {
877 c = my_uni_get(fin, line, isunicode, bigendian); // skip the ]
878
879 // skip all white space
880 while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
881 }
882 else if (!err) err = 2;
883 }
884
885 // get the macro value
886 if (!err && c == '{') {
887 c = my_uni_get(fin, line, isunicode, bigendian); // skip the {
888 while ((!fin.eof()) && (c != '}')) {
889 if (c == '\\') {
890 macrovalue.push_back(c); // keep the '\'
891 c = my_uni_get(fin, line, isunicode, bigendian); // store the *next* value regardless
892 if (!fin.eof()) macrovalue.push_back(c);
893 c = my_uni_get(fin, line, isunicode, bigendian);
894 }
895 macrovalue.push_back(c);
896 c = my_uni_get(fin, line, isunicode, bigendian);
897 }
898
899 if (c == '}') {
900 c = my_uni_get(fin, line, isunicode, bigendian); // skip the }
901
902 // define the macro
903 err = setdefaultmacro (macropackage, macroname, macroparameters,
904 thisfilename, macrovalue);
905 if ((err == -1 || err == -3) && logout != NULL) {
906 (*logout) << text_t2ascii << "Warning: redefinition of _" <<
907 package << ":" << macroname << "_[" << macroparameters <<
908 "] on line ";
909 (*logout) << line;
910 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
911
912 } else if (err == -2 && logout != NULL) {
913 (*logout) << text_t2ascii << "Warning: _" <<
914 package << ":" << macroname << "_[" << macroparameters <<
915 "] on line ";
916 (*logout) << line;
917 (*logout) << text_t2ascii << " of " <<
918 thisfilename << " hides a Global macro with the same name\n";
919
920 } else if (err == -4 && logout != NULL) {
921 (*logout) << text_t2ascii << "Error: macro name expected on line ";
922 (*logout) << line ;
923 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
924 }
925
926 err = 0; // for the test below
927 }
928 else if (!err) err = 3;
929 }
930 else if (!err) err = 4;
931
932 if (err) {
933 // found an error, skip to the end of the line
934 if (logout != NULL) {
935 (*logout) << text_t2ascii << "Error: ";
936 if (err == 1) (*logout) << text_t2ascii << "'_'";
937 else if (err == 2) (*logout) << text_t2ascii << "']'";
938 else if (err == 3) (*logout) << text_t2ascii << "'}'";
939 else if (err == 4) (*logout) << text_t2ascii << "'{'";
940 (*logout) << text_t2ascii << " expected on line ";
941 (*logout) << line ;
942 (*logout) << text_t2ascii << " of " << thisfilename << "\n";
943 }
944 while (!fin.eof ()) {
945 if (c == '\n') break;
946 c = my_uni_get(fin, line, isunicode, bigendian);
947 }
948 }
949
950 } else {
951 // found an error, skip to the end of the line
952 if (logout != NULL) {
953 (*logout) << text_t2ascii << "Error: Unexpected input on line " << line
954 << " of " << thisfilename << "\n";
955 }
956 while (!fin.eof ()) {
957 if (c == '\n') break;
958 c = my_uni_get(fin, line, isunicode, bigendian);
959 }
960
961 }
962 }
963
964 fin.close ();
965
966 // free up memory
967 delete filenamestr;
968 return 0;
969}
970
971
972// prepares to create a page.
973void displayclass::openpage (const text_t &thispageparams,
974 const text_t &thisprecedence)
975{
976 // init variables
977 currentmacros->clear();
978
979 // reload any default macro files which have changed.
980 if (checkdefaultmacrofiles() < 0)
981 {
982 // print error message
983 }
984
985 setpageparams (thispageparams, thisprecedence);
986}
987
988
989// changes the parameters for the current page.
990void displayclass::setpageparams (text_t thispageparams,
991 text_t thisprecedence)
992{
993 paramhashtype thissplitparams, splittheseparams;
994 precedencetype precedhash;
995 text_tset::iterator text_tsetit;
996 paramspec tmpps;
997
998 precedence = thisprecedence;
999 calcprecedence(thisprecedence, precedhash);
1000
1001 splitparams(thispageparams, thissplitparams);
1002 joinparams(thissplitparams, thispageparams);
1003 params = thispageparams;
1004
1005 // get a list of parameters with their specificness
1006 orderparamlist->erase(orderparamlist->begin(), orderparamlist->end());
1007 for (text_tsetit=allparams.begin();
1008 text_tsetit!=allparams.end();
1009 text_tsetit++)
1010 {
1011 tmpps.param = (*text_tsetit);
1012 splitparams(tmpps.param, splittheseparams);
1013 tmpps.spec = getspecificness(thissplitparams, splittheseparams, precedhash);
1014 if (tmpps.spec >= 0)
1015 {
1016 orderparamlist->push_back (tmpps);
1017 }
1018 }
1019
1020 // sort the list
1021 sort(orderparamlist->begin(), orderparamlist->end());
1022
1023// paramspeclist::iterator pshere = orderparamlist->begin();
1024// paramspeclist::iterator psend = orderparamlist->end();
1025// while (pshere != psend)
1026// {
1027// cerr << text_t2ascii << "param=" << (*pshere).param;
1028// cerr << " spec=" << (int)((*pshere).spec) << "\n";
1029// pshere++;
1030// }
1031}
1032
1033
1034// overrides (or sets) a macro for the current page.
1035// returns 0 if there was no error,
1036// -1 if it redefined a macro
1037// -4 if no macroname was supplied
1038int displayclass::setmacro (const text_t &macroname,
1039 text_t package,
1040 const text_t &macrovalue)
1041{
1042 // make sure a macroname was supplied
1043 if (macroname.empty()) return -4;
1044
1045 // make package "Global" if it doesn't point to anything yet
1046 if (package.empty()) package = "Global";
1047
1048 // set the macro
1049 return currentmacros->setmacro(package, macroname, "memory", macrovalue);
1050}
1051
1052
1053void displayclass::expandstring (const text_t &inputtext, text_t &outputtext)
1054{
1055 expandstring("", inputtext, outputtext);
1056}
1057
1058
1059void displayclass::expandstring (text_t package, const text_t &inputtext,
1060 text_t &outputtext, int recursiondepth)
1061{
1062 text_t macroname, macropackage, macroargs;
1063 text_t::const_iterator tthere = inputtext.begin();
1064 text_t::const_iterator ttend = inputtext.end();
1065 unsigned short c = '\0';
1066
1067 if (package.empty()) package = "Global";
1068
1069 outputtext.clear();
1070
1071 // use one-character lookahead
1072 if (tthere != ttend) c = (*tthere);
1073 while (tthere != ttend)
1074 {
1075 if (c == '\\')
1076 {
1077 // found an escape character
1078 c = my_ttnextchar (tthere, ttend); // skip the escape character
1079 if (tthere != ttend)
1080 {
1081 if (c == 'n') outputtext.push_back('\n');
1082 else if (c == 't') outputtext.push_back('\t');
1083 else outputtext.push_back(c);
1084 }
1085 c = my_ttnextchar (tthere, ttend);
1086
1087 }
1088 else if (c == '_')
1089 {
1090 // might have found the start of a macro
1091
1092 // embedded macros (macros within the names
1093 // of other macros) are no longer supported -- Rodger.
1094
1095 // save the current state (in case we need to back out)
1096 text_t::const_iterator savedtthere = tthere;
1097 unsigned short savedc = c;
1098
1099 macroname.clear();
1100 macropackage = package;
1101 macroargs.clear();
1102
1103 c = my_ttnextchar (tthere, ttend); // skip the '_'
1104
1105 // get the macroname
1106 while (tthere != ttend && (!is_unicode_space(c)) &&
1107 (c != '\\') && (c != '_') &&(c != ':') &&
1108 (macroname.size() < 80))
1109 {
1110 macroname.push_back((unsigned char)c);
1111 c = my_ttnextchar (tthere, ttend);
1112 }
1113
1114 if (c == ':')
1115 {
1116 // we actually had the macro package
1117 c = my_ttnextchar (tthere, ttend);
1118 macropackage = macroname;
1119 macroname.clear ();
1120
1121 // get the macro name (honest!)
1122 while ((tthere != ttend) && (!is_unicode_space(c)) &&
1123 (c != '\\') && (c != '_') &&(c != ':') &&
1124 (macroname.size() < 80))
1125 {
1126 macroname.push_back((unsigned char)c);
1127 c = my_ttnextchar (tthere, ttend);
1128 }
1129 }
1130
1131 if ((tthere != ttend) && (c == '_') &&
1132 (macroname.size() > 0))
1133 {
1134 // found a macro!!!! (maybe)
1135
1136 c = my_ttnextchar (tthere, ttend); // skip the '_'
1137
1138 // get the parameters (if there are any)
1139 if ((tthere != ttend) && (c == '('))
1140 {
1141 c = my_ttnextchar (tthere, ttend); // skip '('
1142
1143 // have to be careful of quotes
1144 unsigned short quote = '\0';
1145 while (tthere != ttend)
1146 {
1147 if (c == '\\')
1148 {
1149 // have an escape character, save escape
1150 // character and next character as well
1151 macroargs.push_back (c);
1152 c = my_ttnextchar (tthere, ttend);
1153
1154 }
1155 else if (quote == '\0')
1156 {
1157 // not in a quote at the moment
1158 if (c == ')')
1159 {
1160 // found end of the arguments
1161 c = my_ttnextchar (tthere, ttend); // skip ')'
1162 break;
1163
1164 }
1165 else if (c == '\'' || c == '\"')
1166 {
1167 // found a quote
1168 quote = c;
1169 }
1170
1171 }
1172 else
1173 {
1174 // we are in a quote
1175 if (c == quote) quote = '\0';
1176 }
1177
1178 // save this character
1179 if (tthere != ttend) macroargs.push_back (c);
1180 c = my_ttnextchar (tthere, ttend);
1181 }
1182 }
1183
1184 //
1185 // we now have the macropackage, macroname, and macroargs
1186 //
1187
1188 // try to expand out this macro
1189 text_t expandedmacro;
1190 if (macro (macroname, macropackage, macroargs, expandedmacro, recursiondepth))
1191 {
1192 // append the expanded macro
1193 outputtext += expandedmacro;
1194 }
1195 else
1196 {
1197 // wasn't a macro
1198 tthere = savedtthere;
1199 c = savedc;
1200 outputtext.push_back(c); // the '_'
1201 c = my_ttnextchar (tthere, ttend);
1202 }
1203
1204
1205 }
1206 else
1207 {
1208 // wasn't a macro
1209 tthere = savedtthere;
1210 c = savedc;
1211 outputtext.push_back(c); // the '_'
1212 c = my_ttnextchar (tthere, ttend);
1213 }
1214
1215 }
1216 else
1217 {
1218 // nothing of interest
1219 outputtext.push_back(c); // the '_'
1220 c = my_ttnextchar (tthere, ttend);
1221 }
1222 }
1223}
1224
1225ostream *displayclass::setlogout (ostream *thelogout) {
1226
1227 ostream *oldlogout = logout;
1228 logout = thelogout;
1229 return oldlogout;
1230}
1231
1232// protected methods for display
1233
1234// reloads any default macro files which have changed
1235// returns 0 no errors occurred
1236// -1 an error occurred while trying to load one of the files
1237int displayclass::checkdefaultmacrofiles ()
1238{
1239 // this isn't implemented yet
1240 return 0;
1241}
1242
1243// isdefaultmacro sees if there is an entry in the list of
1244// default macros with the given package and macro name
1245// returns 0 if no macros in the package or in the global package
1246// were found
1247// 1 if no macros in the package were found but a macro
1248// in the global package was found
1249// 2 if a macro in the given package was found
1250int displayclass::isdefaultmacro (text_t package, const text_t &macroname) {
1251 // make sure a macroname was supplied
1252 if (macroname.empty()) return 0;
1253
1254 // make package "Global" if it doesn't point to anything yet
1255 if (package.empty()) package = "Global";
1256
1257 // check the given package
1258 if (defaultmacros->macro_find(package, macroname) != NULL) return 2;
1259
1260 // check the Global package
1261 if (defaultmacros->macro_find("Global", macroname) != NULL) return 1;
1262
1263 return 0;
1264}
1265
1266
1267// setdefaultmacro adds an entry to the list of default macros
1268// returns 0 if there was no error,
1269// -1 if it redefined a macro
1270// -2 if it hid a Global macro
1271// -3 if it redefined a macro and hid a Global macro
1272// -4 if no macroname was supplied
1273int displayclass::setdefaultmacro (text_t package, const text_t &macroname,
1274 text_t params, const text_t &filename,
1275 const text_t &macrovalue)
1276{
1277 // make sure a macroname was supplied
1278 if (macroname.empty()) return -4;
1279
1280 // put the parameters in a standard form
1281 paramhashtype paramhash;
1282 if (params.empty()) params = "ignore=yes";
1283 splitparams (params, paramhash);
1284 joinparams (paramhash, params);
1285
1286 // make package "Global" if it doesn't point to anything yet
1287 if (package.empty()) package = "Global";
1288
1289 // remember these parameters
1290 allparams.insert (params);
1291
1292 // remember this filename (this part isn't finished yet -- Rodger).
1293
1294 // set the macro
1295 return defaultmacros->setmacro(package, macroname, params, filename, macrovalue);
1296}
1297
1298
1299// evaluates a boolean expression
1300// returns false if expr equals "" or "0".
1301// otherwise returns true *unless* expr is
1302// format "XXXX" eq/ne "dddd" in which case
1303// the two quoted strings are compared
1304bool displayclass::boolexpr (text_t package, const text_t &expr, int recursiondepth) {
1305
1306 if (expr.empty()) return false;
1307
1308 text_t expexpr;
1309 if (package.empty()) package = "Global";
1310 expandstring (package, expr, expexpr, recursiondepth);
1311
1312 if (expexpr.empty() || expexpr == "0") return false;
1313 if (expr[0] != '\"') return true;
1314
1315 // don't use expexpr while separating quoted parts of
1316 // expression just in case expanded out macros contain
1317 // quotes
1318 text_t::const_iterator here = expr.begin();
1319 text_t::const_iterator end = expr.end();
1320
1321 int quotecount = 0;
1322 text_t string1, expstring1;
1323 text_t string2, expstring2;
1324 text_t op;
1325 text_t combineop;
1326 bool result = false; // an empty string is false
1327 bool result2 = false;
1328
1329 while (here != end) {
1330 // get a comparison
1331 quotecount = 0;
1332 string1.clear();
1333 string2.clear();
1334 op.clear();
1335 while (here != end) {
1336 if (*here == '"') quotecount++;
1337 else if (quotecount == 1) string1.push_back(*here);
1338 else if ((quotecount == 2) && !is_unicode_space (*here))
1339 op.push_back(*here);
1340 else if (quotecount == 3) string2.push_back(*here);
1341 else if (quotecount >= 4) break;
1342 here ++;
1343 }
1344
1345 expandstring (package, string1, expstring1, recursiondepth);
1346 expandstring (package, string2, expstring2, recursiondepth);
1347
1348 // get next result
1349 result2 = true; // any badly formatted string will return true
1350 if (op == "eq") result2 = (expstring1 == expstring2);
1351 else if (op == "ne") result2 = (expstring1 != expstring2);
1352 else if (op == "gt") result2 = (expstring1 > expstring2);
1353 else if (op == "ge") result2 = (expstring1 >= expstring2);
1354 else if (op == "lt") result2 = (expstring1 < expstring2);
1355 else if (op == "le") result2 = (expstring1 <= expstring2);
1356 else if (op == "==") result2 = (expstring1.getint() == expstring2.getint());
1357 else if (op == "!=") result2 = (expstring1.getint() != expstring2.getint());
1358 else if (op == ">") result2 = (expstring1.getint() > expstring2.getint());
1359 else if (op == ">=") result2 = (expstring1.getint() >= expstring2.getint());
1360 else if (op == "<") result2 = (expstring1.getint() < expstring2.getint());
1361 else if (op == "<=") result2 = (expstring1.getint() <= expstring2.getint());
1362
1363 // combine the results
1364 if (combineop == "&&") result = (result && result2);
1365 else if (combineop == "||") result = (result || result2);
1366 else result = result2;
1367
1368 // get next combination operator
1369 combineop.clear();
1370 while (here != end && *here != '"') {
1371 if (!is_unicode_space(*here)) combineop.push_back(*here);
1372 here++;
1373 }
1374 }
1375
1376 return result;
1377}
1378
1379
1380// (recursively) expand out a macro
1381// returns true if the macro was found
1382// false if the macro was not found
1383bool displayclass::macro (const text_t &macroname, text_t macropackage,
1384 const text_t &macroparam, text_t &outputtext,
1385 int recursiondepth)
1386{
1387 outconvertclass text_t2ascii;
1388 text_tlist splitmacroparam;
1389 text_t::const_iterator hereit, endit;
1390 text_t aparam;
1391 unsigned short c = '\0', quote = '\0';
1392
1393 // cerr << "r: " << recursiondepth << "\n";
1394
1395 // check for deep recursion
1396 if (recursiondepth >= MAXRECURSIONDEPTH)
1397 {
1398 if (logout != NULL)
1399 (*logout) << "Warning: deep recursion, limiting macro expansion\n";
1400 return false;
1401 }
1402
1403 // check the macropackage
1404 if (macropackage.empty()) macropackage = "Global";
1405
1406 // get the parameters (but don't expand them)
1407 if (macroparam.size() > 0) {
1408 // set up for loop
1409 hereit = macroparam.begin();
1410 endit = macroparam.end();
1411 if (hereit != endit) c = (*hereit);
1412
1413 while (hereit != endit) {
1414 // get the next parameter
1415 aparam.clear();
1416 quote = '\0'; // not-quoted unless proven quoted
1417
1418 // ignore initial whitespace
1419 while ((hereit!=endit)&&is_unicode_space(c)) c=my_ttnextchar(hereit,endit);
1420
1421 // look for the end of the parameter
1422 while (hereit != endit) {
1423 if (c == '\\') {
1424 // found escape character, also get next character
1425 aparam.push_back(c);
1426 c = my_ttnextchar (hereit, endit);
1427 if (hereit != endit) aparam.push_back(c);
1428
1429 } else if (quote=='\0' && (c=='\'' /*|| c=='"'*/)) {
1430 // found a quoted section
1431 quote = c;
1432 // aparam.push_back(c);
1433
1434 } else if (quote!='\0' && c==quote) {
1435 // found the end of a quote
1436 quote = '\0';
1437 // aparam.push_back(c);
1438
1439 } else if (quote=='\0' && c==',') {
1440 // found the end of a parameter
1441 c = my_ttnextchar (hereit, endit);
1442 break;
1443
1444 } else {
1445 // ordinary character
1446 aparam.push_back(c);
1447 }
1448
1449 c = my_ttnextchar (hereit, endit);
1450 }
1451
1452 // add this parameter to the list
1453 splitmacroparam.push_back(aparam);
1454 }
1455 }
1456
1457 if (macroname == "If") {
1458 // get the condition, then clause and else clause
1459 text_tlist::iterator paramcond = splitmacroparam.begin();
1460 text_tlist::iterator paramend = splitmacroparam.end();
1461 text_tlist::iterator paramthen = paramend;
1462 text_tlist::iterator paramelse = paramend;
1463
1464 if (paramcond != paramend) {
1465 paramthen = paramcond;
1466 paramthen++;
1467 }
1468 if (paramthen != paramend) {
1469 paramelse = paramthen;
1470 paramelse++;
1471 }
1472
1473 // will always output something
1474 outputtext.clear();
1475
1476 // expand out the first parameter
1477 if (paramcond != paramend) {
1478 text_t tmpoutput;
1479 expandstring (macropackage, *paramcond, tmpoutput, recursiondepth+1);
1480 lc (tmpoutput);
1481
1482 // test the expanded string
1483 if (boolexpr (macropackage, *paramcond, recursiondepth+1)) {
1484 //(tmpoutput.size()) && (tmpoutput != "false") && (tmpoutput != "0")) {
1485 // true
1486 if (paramthen != paramend)
1487 expandstring (macropackage, *paramthen, outputtext, recursiondepth+1);
1488
1489 } else {
1490 // false
1491 if (paramelse != paramend)
1492 expandstring (macropackage, *paramelse, outputtext, recursiondepth+1);
1493 }
1494 }
1495
1496 return true;
1497 }
1498
1499 // try and find this macro
1500
1501 // this list might be replaced by something a little more
1502 // sophisticated in the future.
1503 text_tlist packagelist;
1504 packagelist.push_back (macropackage);
1505 packagelist.push_back ("Global");
1506
1507 paramspeclist::iterator paramhere, paramend;
1508 text_tlist::iterator packagehere = packagelist.begin();
1509 text_tlist::iterator packageend = packagelist.end();
1510 mvalue *macrovalue = NULL;
1511 while ((macrovalue == NULL) && (packagehere != packageend))
1512 {
1513 // first look in the currentmacros
1514 macrovalue = currentmacros->macro_find(*packagehere, macroname);
1515 if (macrovalue == NULL)
1516 macrovalue = currentmacros->macro_find("Style", macroname);
1517
1518 // look in the default macros
1519 if (macrovalue == NULL)
1520 {
1521 // next look in the defaultmacros
1522 if (defaultmacros->macro_find (*packagehere, macroname) != NULL)
1523 {
1524 paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
1525 while ((macrovalue == NULL) && (paramhere != paramend))
1526 {
1527// cerr << text_t2ascii << "\npackage: " << *packagehere << "\n";
1528// cerr << text_t2ascii << "macroname: " << macroname << "\n";
1529// cerr << text_t2ascii << "param: " << (*paramhere).param << "\n";
1530// cerr << "spec: " << (int)((*paramhere).spec) << "\n";
1531 macrovalue = defaultmacros->parameter_find(*packagehere, macroname,
1532 (*paramhere).param);
1533 paramhere++;
1534 }
1535 }
1536 }
1537
1538 // and again in the package "Style"
1539 if (macrovalue == NULL)
1540 {
1541 // next look in the defaultmacros
1542 if (defaultmacros->macro_find ("Style", macroname) != NULL)
1543 {
1544 paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
1545 while ((macrovalue == NULL) && (paramhere != paramend))
1546 {
1547 macrovalue = defaultmacros->parameter_find("Style", macroname,
1548 (*paramhere).param);
1549 paramhere++;
1550 }
1551 }
1552 }
1553 if (macrovalue == NULL) packagehere++;
1554 }
1555
1556 if (macrovalue != NULL)
1557 {
1558 // we found a macro
1559
1560 // replace all the option macros (_1_, _2_, ...) in the value of this macro
1561 // and decide if we need to expand the value of this macro
1562 bool needsexpansion = false;
1563 text_t tempmacrovalue;
1564 tempmacrovalue.clear();
1565 hereit = macrovalue->value.begin();
1566 endit = macrovalue->value.end();
1567 if (hereit != endit) c = (*hereit);
1568 while (hereit != endit)
1569 {
1570 if (c == '\\')
1571 {
1572 // found an escape character
1573 needsexpansion = true;
1574 tempmacrovalue.push_back(c);
1575 c = my_ttnextchar (hereit, endit);
1576 if (hereit != endit) tempmacrovalue.push_back(c);
1577 c = my_ttnextchar (hereit, endit);
1578 }
1579 else if (c == '_')
1580 {
1581 text_t::const_iterator savedhereit = hereit;
1582
1583 // attempt to get a number
1584 int argnum = 0;
1585 unsigned short digc = my_ttnextchar (hereit, endit);
1586 while (digc >= '0' && digc <= '9') {
1587 argnum = argnum*10 + digc - '0';
1588 digc = my_ttnextchar (hereit, endit);
1589 }
1590 if (digc == '_' && argnum > 0) {
1591 // found an option macro, append the appropriate text
1592 text_tlist::iterator ttlisthere = splitmacroparam.begin();
1593 text_tlist::iterator ttlistend = splitmacroparam.end();
1594 while ((argnum > 1) && (ttlisthere != ttlistend)) {
1595 argnum--;
1596 ttlisthere++;
1597 }
1598 if (ttlisthere != ttlistend) {
1599 tempmacrovalue.append(*ttlisthere);
1600 if (findchar((*ttlisthere).begin(), (*ttlisthere).end(), '_') != (*ttlisthere).end())
1601 needsexpansion = true;
1602 }
1603
1604 c = my_ttnextchar (hereit, endit);
1605
1606 } else {
1607 // wasn't a option macro
1608 needsexpansion = true;
1609 tempmacrovalue.push_back(c);
1610 hereit = savedhereit;
1611 c = my_ttnextchar (hereit, endit);
1612 }
1613 }
1614 else
1615 {
1616 tempmacrovalue.push_back(c);
1617 c = my_ttnextchar (hereit, endit);
1618 }
1619 }
1620
1621 // recursively replace this macro (if we need to)
1622 if (needsexpansion) {
1623 expandstring (*packagehere, tempmacrovalue, outputtext, recursiondepth+1);
1624 } else {
1625 outputtext += tempmacrovalue;
1626 }
1627
1628 return true;
1629 }
1630
1631 if (logout != NULL) {
1632 (*logout) << text_t2ascii << "Warning: _" <<
1633 macropackage << ":" << macroname << "_ not found\n";
1634 }
1635
1636 return false; // didn't find the macro
1637}
1638
1639
1640void displayclass::printdefaultmacros ()
1641{
1642 defpackagemap::const_iterator packagemapit;
1643 defmacromap::const_iterator macromapit;
1644 defparammap::const_iterator parammapit;
1645 const mvalue *mvalueptr;
1646 outconvertclass text_t2ascii;
1647
1648 text_t packagename, macroname, macroparam;
1649
1650 for (packagemapit = defaultmacros->package_begin();
1651 packagemapit != defaultmacros->package_end();
1652 packagemapit++)
1653 {
1654 packagename = (*packagemapit).first;
1655 // cerr << "***package : \"" << packagename << "\"\n";
1656
1657 for (macromapit = (*packagemapit).second.begin();
1658 macromapit != (*packagemapit).second.end();
1659 macromapit++)
1660 {
1661 macroname = (*macromapit).first;
1662 // cerr << "***macroname : \"" << macroname << "\"\n";
1663
1664 for (parammapit = (*macromapit).second.begin();
1665 parammapit != (*macromapit).second.end();
1666 parammapit++)
1667 {
1668 macroparam = (*parammapit).first;
1669 mvalueptr = &((*parammapit).second);
1670 cerr << text_t2ascii << "package : \"" << packagename << "\"\n";
1671 cerr << text_t2ascii << "macroname : \"" << macroname << "\"\n";
1672 cerr << text_t2ascii << "parameters: [" << macroparam << "]\n";
1673 cerr << text_t2ascii << "filename : \"" << mvalueptr->filename << "\"\n";
1674 cerr << text_t2ascii << "value : {" << mvalueptr->value << "}\n\n";
1675 }
1676 }
1677 }
1678}
1679
1680void displayclass::printallparams ()
1681{
1682 text_tset::iterator text_tsetit;
1683 outconvertclass text_t2ascii;
1684
1685 cerr << text_t2ascii << "** allparams\n";
1686 for (text_tsetit=allparams.begin();
1687 text_tsetit!=allparams.end();
1688 text_tsetit++) {
1689 cerr << text_t2ascii << (*text_tsetit) << "\n";
1690 }
1691 cerr << text_t2ascii << "\n";
1692}
1693
1694
1695
1696/////////////////////////////////////
1697// stuff to do tricky output
1698/////////////////////////////////////
1699
1700displayclass &operator<< (outconvertclass &theoutc, displayclass &display)
1701{
1702 display.setconvertclass (&theoutc);
1703 return display;
1704}
1705
1706displayclass &operator<< (displayclass &display, const text_t &t)
1707{
1708 outconvertclass *theoutc = display.getconvertclass();
1709
1710 if (theoutc == NULL) return display;
1711
1712 text_t output;
1713 display.expandstring (t, output);
1714 (*theoutc) << output;
1715
1716 return display;
1717}
1718
Note: See TracBrowser for help on using the repository browser.