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

Last change on this file since 943 was 791, checked in by sjboddie, 25 years ago

fixed bug in logout

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