added Info.plist
[TestXSLT.git] / libsablot / src / engine / tree.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable 
23  * instead of those above.  If you wish to allow use of your 
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32
33 #include "tree.h"
34 #include "proc.h"
35 #include "guard.h"
36 #include "key.h"
37
38 /* ------------------------------------------------------------ */
39 /* SpaceNameList */
40 /* -------------------------------------------------------------*/
41
42 Bool SpaceNameList::findName(EQName &ename, double &prio)
43 {
44   int num = number();
45   prio = -10;
46   Bool found = 0;
47   for (int i = 0; i < num; i++)
48     {
49       EQName *aux = operator[](i);
50       if (aux -> getLocal() == (const char*) "*")
51         {
52           if (aux -> getUri() == (const char*) "")
53             {
54               found = 1;
55               prio = -0.5;
56             }
57           else
58             if (ename.getUri() == aux -> getUri())
59               {
60                 found = 1;
61                 prio = -0.25;
62               }
63         }
64       else
65         {
66           if (ename.getLocal() == aux -> getLocal() && 
67               ename.getUri() == aux -> getUri())
68             {
69               found = 1;
70               prio = 0; 
71               break; //exit loop, we can't get better match
72             }
73         }
74     }
75   return found;
76 }
77
78 /* ------------------------------------------------------------ */
79 /* StylesheetStructure */
80 /* -------------------------------------------------------------*/
81
82 //
83 //
84 //  SubtreeInfo
85 //
86 //
87
88 SubtreeInfo::~SubtreeInfo()
89 {
90   excludedNS.deppendall();
91   extensionNS.deppendall();
92   excludedCount.deppendall();
93   extensionCount.deppendall();
94 }
95
96 void SubtreeInfo::pushNamespaceMarks()
97 {
98   excludedCount.append(excludedNS.number());
99   extensionCount.append(extensionNS.number());
100 }
101
102 void SubtreeInfo::popNamespaceMarks()
103 {
104   //excluded
105   int limit = excludedCount.number() ? excludedCount.last() : 0;
106   int idx;
107   for (idx = excludedNS.number() - 1; idx >= limit; idx--)
108     excludedNS.deppend();
109   if (excludedCount.number()) excludedCount.deppend();
110   //extensions
111   limit = extensionCount.number() ? extensionCount.last() : 0;
112   for (idx = extensionNS.number() - 1; idx >= limit; idx--)
113     extensionNS.deppend();
114   if (extensionCount.number()) extensionCount.deppend();
115 }
116
117 //
118 //
119 //  StylesheetSructure
120 //
121 //
122
123 eFlag StylesheetStructure::findBestRule(
124     Sit S, 
125     XSLElement *&ret, 
126     Context *c,
127     QName *currMode,
128     Bool importsOnly)
129 {
130     int i;
131     ret = NULL;
132     // if we don't process imports only, look at the rules in this
133     // structure
134     if (!importsOnly)
135     {
136         int rulesNumber = rulesList.number();
137         int bestRule = -1;
138         double bestPrio = 0;
139         Expression *pattern = NULL;
140         QName *thisMode;
141         XSLElement *therule;
142         for (i = 0; i < rulesNumber; i++)
143         {
144             if (
145                 (bestRule != -1) &&
146                 (fcomp(rulesList[i] -> priority, bestPrio) == -1)  
147                 // current < best
148                 )
149                 break;
150             therule = rulesList[i] -> rule;
151             Attribute *a = rulesList[i] -> match;
152             if (a) 
153                 pattern = a -> expr;
154             else 
155                 continue;
156
157             thisMode = rulesList[i] -> mode;
158             if ((!thisMode) ^ (!currMode))
159                 continue;
160             if (thisMode && !((*thisMode) == (*currMode)))
161                 continue;
162             // else both thisMode and currMode are NULL which is OK
163             if (pattern)
164             {
165                 Bool result;
166                 E( pattern -> matchesPattern(S, c, result) );
167                 if (result)
168                 {
169                     bestRule = i;
170                     bestPrio = rulesList[i] -> priority;
171                 }
172             };
173         };
174         if (bestRule != -1) 
175             ret = rulesList[bestRule] -> rule; // else remains NULL
176     }
177     
178     // if no match was found, look at the imported stylesheets
179     if (!ret)
180     {
181         int importCount = importChildren.number();
182         for (i = 0; i < importCount && !ret; i++)
183         {
184             // call findBestRule recursively, setting importsOnly to FALSE
185             E( importChildren[i] -> findBestRule(
186                 S, ret, c, currMode, FALSE));
187         }
188     }
189     return OK;
190 };
191
192 XSLElement* StylesheetStructure::findRuleByName(Tree &t, QName &q)
193 {
194     XSLElement* ret = rulesList.findByName(t,q);
195     int importCount = importChildren.number(),
196         i;
197     for (i = 0; !ret && i < importCount; i++)
198         ret = importChildren[i] -> rulesList.findByName(t,q);
199     return ret;
200 }
201
202 Bool StylesheetStructure::hasAnyStripped()
203 {
204   Bool ret = strippedNamesList.number();
205   if (!ret)
206     {
207       int importCount = importChildren.number();
208       for (int i = 0; i < importCount && !ret; i++)
209         {
210           ret = importChildren[i] -> hasAnyStripped();
211         }
212     }
213   return ret;
214 }
215
216 Bool StylesheetStructure::hasAnyPreserved()
217 {
218   Bool ret = preservedNamesList.number();
219   if (!ret)
220     {
221       int importCount = importChildren.number();
222       for (int i = 0; i < importCount && !ret; i++)
223         {
224           ret = importChildren[i] -> hasAnyPreserved();
225         }
226     }
227   return ret;
228 }
229
230 Bool StylesheetStructure::findStrippedName(EQName &ename, int &prec, double &pri)
231 {
232   Bool ret = FALSE;
233   if (strippedNamesList.findName(ename, pri)) {
234     prec = importPrecedence;
235     ret = TRUE;
236   }
237   else
238     {
239       int importCount = importChildren.number();
240       for (int i = 0; i < importCount && !ret; i++)
241         {
242           // call findBestRule recursively, setting importsOnly to FALSE
243           ret = importChildren[i] -> findStrippedName(ename, prec, pri);
244         }
245     }
246   return ret;
247 }
248
249 Bool StylesheetStructure::findPreservedName(EQName &ename, int &prec, double &pri)
250 {
251   Bool ret = FALSE;
252   if (preservedNamesList.findName(ename, pri)) {
253     prec = importPrecedence;
254     ret = TRUE;
255   }
256   else
257     {
258       int importCount = importChildren.number();
259       for (int i = 0; i < importCount && !ret; i++)
260         {
261           // call findBestRule recursively, setting importsOnly to FALSE
262           ret = importChildren[i] -> findPreservedName(ename, prec, pri);
263         }
264     }
265   return ret;
266 }
267
268
269 //
270 //
271 //  SubtreeList
272 //
273 //
274
275
276 //
277 //
278 //  VarDirectory
279 //
280 //
281
282 VarDirectory::VarDirectory()
283 {
284 }
285
286 VarDirectory::~VarDirectory()
287 {
288     freeall(FALSE);
289 }
290
291 XSLElement* VarDirectory::find(QName& name)
292 {
293     int i = findNdx(name);
294     return (i == -1)? NULL : (*this)[i] -> getElement();
295 }
296
297 eFlag VarDirectory::insert(Sit S, QName &name, XSLElement* var)
298 {
299     int i = findNdx(name);
300     if (i == -1)
301         append(new VarDirectoryItem(name, var));
302     else
303     {
304         // if precedences are equal, raise error
305         int 
306             oldPrec = (*this)[i] -> getElement() -> getImportPrecedence(),
307             newPrec = var -> getImportPrecedence();
308         // due to immediate resolution of xsl:import, new must be <= old
309         assert(newPrec <= oldPrec);
310         (*this)[i] -> setElement(var);
311         if (newPrec == oldPrec)
312         {
313             Str fullName;
314             var -> getOwner().expandQStr(name, fullName);
315             Err1(S, E1_MULT_ASSIGNMENT, fullName);
316         }
317     }
318     return OK;
319 }
320
321
322 int VarDirectory::findNdx(const QName& name)
323 {
324     int i;
325     for (i = 0; i < number(); i++)
326     {
327         if ( (*this)[i] -> getName() == name )
328             return i;
329     }
330     return -1;
331 }
332
333 /*****************************************************************
334
335   Attribute Sets
336
337 *****************************************************************/
338
339 //
340 //
341 //  AttSetMember implementation
342 //
343 //
344
345 void AttSetMember::set(XSLElement *newAttDef)
346 {
347     int oldPrec = attDef ? 
348         attDef -> getImportPrecedence() : -1;
349     int newPrec = newAttDef -> getImportPrecedence();
350     if (oldPrec == newPrec && !redefinition)
351         redefinition = newAttDef;
352     if (newPrec <= oldPrec || oldPrec == -1)
353         attDef = newAttDef;
354     if (newPrec < oldPrec)
355         redefinition = NULL;
356 }
357
358 //
359 //
360 //  AttSet
361 //
362 //
363
364 AttSet::AttSet(QName &name_)
365 : name(name_)
366 {
367 };
368
369 AttSet::~AttSet()
370 {
371     freeall(FALSE);
372     //don't free this list items, these are copies of 
373     //pointers stored with xsl:attribute-set element
374     //usedSets.freeall(FALSE); 
375     usedSets.deppendall(); 
376 }
377
378 eFlag AttSet::checkRedefinitions(Sit S)
379 {
380     for (int i = 0; i < number(); i++)
381         if ((*this)[i] -> getRedefinition())
382         {
383             XSLElement *redef = (*this)[i] -> getRedefinition(); 
384             Str fullNameAtt, fullNameThis;
385             redef -> getOwner().expandQStr((*this)[i] -> getAttName(), fullNameAtt);
386             redef -> getOwner().expandQStr(getName(), fullNameThis);
387             S.setCurrVDoc(redef);
388             Warn2(S, W2_ATTSET_REDEF, fullNameAtt, fullNameThis);
389         }
390     return OK;
391 }
392
393 eFlag AttSet::execute(Sit S, Context *c, Tree& sheet, QNameList& history, Bool resolvingGlobals)
394 {
395   if (history.findNdx(name) != -1)
396     {
397       Str fullName;
398       sheet.expandQStr(name, fullName);
399       Err1(S, E1_CIRCULAR_ASET_REF, fullName);
400     }
401   history.append(&name);
402   int i;
403   for (i = 0; i < usedSets.number(); i++)
404     E( sheet.attSets().executeAttSet(S, *(usedSets[i]), c, 
405                                      sheet, history, resolvingGlobals) );
406   history.deppend();
407
408   for (i = 0; i < number(); i++)
409     {
410       XSLElement *def = (*this)[i] -> getAttributeDef();
411       //execute the content
412       E( def -> execute(S, c, resolvingGlobals) );
413     }
414   return OK;
415 }
416
417 int AttSet::findNdx(QName &attName)
418 {
419     for (int i = 0; i < number(); i++)
420         if ((*this)[i] -> getAttName() == attName)
421             return i;
422     return -1;
423 }
424
425 void AttSet::insertAttributeDef(XSLElement *attDef, QName &attName)
426 {
427     int ndx = findNdx(name);
428     if (ndx == -1)
429     {
430         append(new AttSetMember(attName));
431         ndx = number() - 1;
432     }
433     (*this)[ndx] -> set(attDef);
434 }
435
436 void AttSet::insertUses(QName &usedSet)
437
438     if (usedSets.findNdx(usedSet) == -1) 
439         usedSets.append(&usedSet); 
440 }
441
442
443 //
444 //
445 //  AttSetList
446 //
447 //
448
449 AttSetList::AttSetList()
450 :
451 PList<AttSet*>(LIST_SIZE_LARGE)
452 {};
453
454 AttSetList::~AttSetList()
455 {
456     freeall(FALSE);
457 }
458
459 eFlag AttSetList::checkRedefinitions(Sit S)
460 {
461     for (int i = 0; i < number(); i++)
462         E( (*this)[i] -> checkRedefinitions(S) );
463     return OK;
464 }
465
466 AttSet* AttSetList::insert(QName &name)
467 {
468     int ndx = findNdx(name);
469     AttSet *ptr = NULL;
470     if (ndx == -1)
471         append(ptr = new AttSet(name));
472     else
473         ptr = (*this)[ndx];
474     return ptr;
475 }
476
477 eFlag AttSetList::executeAttSet(Sit S, QName &name, Context *c, Tree &sheet, QNameList& history, Bool resolvingGlobals)
478 {
479     int ndx = findNdx(name);
480     if (ndx == -1)
481     {
482         Str fullName;
483         sheet.expandQStr(name, fullName);
484         Err1(S, E1_NONEX_ASET_NAME, fullName);
485     }
486     E( (*this)[ndx] -> execute(S, c, sheet, history, resolvingGlobals) );
487     return OK;
488 }
489
490 int AttSetList::findNdx(const QName &what) const
491 {
492     int count = number();
493     for (int i = 0; i < count; i++)
494         if ((*this)[i] -> getName() == what)
495             return i;
496     return -1;
497 }
498
499 //
500 //
501 //  AliasItem implementation
502 //
503 //
504
505 void AliasItem::set(Phrase newKey, Phrase newValue, Phrase newPrefix,
506                     int newPrecedence, XSLElement *source)
507 {
508     assert(newPrecedence >= 0);
509     if (key == UNDEF_PHRASE) key = newKey;
510     if (precedence == newPrecedence && value != newValue && !redefinition)
511         redefinition = source;
512     if (newPrecedence <= precedence || precedence == -1)
513     {
514         value = newValue;
515         precedence = newPrecedence;
516         prefix = newPrefix;
517     }
518     if (newPrecedence < precedence)
519         redefinition = NULL;
520 }
521
522 //
523 //
524 //  AliasList implementation
525 //
526 //
527
528 int AliasList::findNdx(Phrase key_) const
529 {
530     int i, count = number();
531     for (i = 0; (i < count) && !(key_ == ((*this)[i] -> getKey())); i++);
532     return (i < count) ? i : -1;
533 }
534
535 Phrase AliasList::find(Phrase key_) const
536 {
537     int ndx = findNdx(key_);
538     return (ndx != -1) ? (*this)[ndx] -> getValue() : PHRASE_NOT_FOUND;
539 }
540
541 void AliasList::insertAlias(Phrase key, Phrase value, Phrase prefix,
542                             int precedence, XSLElement *source)
543 {
544     AliasItem *newItem;
545     int ndx = findNdx(key);
546     if (ndx == -1)
547         append(newItem = new AliasItem);
548     else
549         newItem = (*this)[ndx];
550     newItem -> set(key, value, prefix, precedence, source);
551 }
552
553 eFlag AliasList::checkRedefinitions(Sit S, Tree &sheet)
554 {
555     for (int i = 0; i < number(); i++)
556         if ((*this)[i] -> getRedefinition())
557         {
558             S.setCurrVDoc((*this)[i] -> getRedefinition());
559             Str fullName;
560             sheet.expand((*this)[i] -> getKey());
561             Warn1(S, W1_ALIAS_REDEF, fullName);
562         }
563     return OK;
564 }
565
566 /****************************************
567 T r e e   methods
568 ****************************************/
569
570 Tree::Tree(const Str &aname, BOOL aXSLTree)
571     : theArena(TREE_ARENA_SIZE), theDictionary(&theArena, TREE_DICT_LOGSIZE),
572       structure(0)
573 {
574     // theDictionary.initialize();
575     QName &rootname = (QName&) getTheEmptyQName();
576     root = new(&theArena) RootNode(*this, rootname);
577     XSLTree = aXSLTree;
578     stackTop = &getRoot();
579     pendingTextNode = NULL;
580     getRoot().stamp = 0;
581     vcount = 1;
582     QName dummyName;
583     theDummyElement = new(&theArena) Element(*this, dummyName);
584     initDict();
585
586     // append entry for 'the whole tree' to subtrees
587     subtrees.push(new SubtreeInfo(
588         aname, XSL_NONE, &structure, FALSE));
589     getRoot().setSubtreeInfo(subtrees.last());
590
591     excludeStdNamespaces();
592
593     pendingNSList.append(new(&theArena) NSList());
594
595     stripped = aXSLTree;
596     hasAnyStripped = hasAnyPreserved = -1;// means 'who knows?'
597     importUnique = 0xFFFF;
598 };
599
600 Tree::~Tree()
601 {
602     getRoot().~RootNode();
603     // this is just in case there's a processing error:
604     //pendingNSList.freeall(FALSE);
605     delete theDummyElement;
606     // clear subtree information
607     subtrees.freeall(FALSE);
608     aliasesList.freeall(FALSE);
609     unparsedEntities.freeall(FALSE);
610     
611     pendingNSList.freelast(FALSE);
612     //assert(!pendingNSList.number());
613 }
614
615 void Tree::initDict()
616 {
617     theDictionary.initialize();
618     theDictionary.insert("", stdPhrases[PHRASE_EMPTY]);
619     theDictionary.insert("xsl", stdPhrases[PHRASE_XSL]);
620     theDictionary.insert(theXSLTNamespace, stdPhrases[PHRASE_XSL_NAMESPACE]);
621     theDictionary.insert(theXMLNamespace, stdPhrases[PHRASE_XML_NAMESPACE]);
622     theDictionary.insert(theSabExtNamespace, stdPhrases[PHRASE_SABEXT_NAMESPACE]);
623     theDictionary.insert("*", stdPhrases[PHRASE_STAR]);
624     theDictionary.insert("xmlns", stdPhrases[PHRASE_XMLNS]);
625     theDictionary.insert("lang", stdPhrases[PHRASE_LANG]);
626 }
627
628 void Tree::excludeStdNamespaces()
629 {
630   NZ(getCurrentInfo()) -> 
631     getExcludedNS().addUri(stdPhrase(PHRASE_XML_NAMESPACE));
632   if (XSLTree)
633     {
634       NZ(getCurrentInfo()) -> 
635         getExcludedNS().addUri(stdPhrase(PHRASE_XSL_NAMESPACE));
636     }
637 }
638
639 Element &Tree::dummyElement() const
640 {
641     return *theDummyElement;
642 }
643
644 void Tree::flushPendingText()
645 {
646     if (pendingTextNode)
647         pendingTextNode -> cont = pendingText;
648     pendingText.empty();
649     pendingTextNode = NULL;
650 }
651     
652 eFlag Tree::appendVertex(Sit S, Vertex *v)
653 {
654     assert(stackTop && isDaddy(stackTop));
655     assert(!isText(v) || !pendingTextNode);
656     if (!isText(v))
657         flushPendingText();
658     E( cast(Daddy*,stackTop) -> newChild(S, v) ); //sets parent too
659     if (isDaddy(v))
660         stackTop = v;
661     v -> stamp = vcount++;
662     // set the subtree information for vertex
663     v -> setSubtreeInfo(subtrees.getCurrent());
664     return OK;
665 };
666
667 void Tree::dropCurrentElement(Vertex *v)
668 {
669     assert(stackTop && isElement(stackTop));
670     assert(stackTop == v);
671     assert(!pendingTextNode);
672     stackTop = v -> parent;
673     delete v;
674     toE(stackTop) -> contents.deppend();
675 }
676
677 Vertex* Tree::appendText(Sit S, char *string, int len)
678 {
679     Vertex *txt = NULL;
680     if (!pendingTextNode)
681     {
682         // the initializing text does not matter
683         txt = new(&getArena()) Text(*this, string, len);
684         Processor *proc = S.getProcessor();
685         if ( proc && proc->outputter() ) 
686           {
687             OutputDocument *doc=proc->outputter()->getDocumentForLevel(FALSE);
688             txt -> setOutputDocument(doc);
689           }
690
691         appendVertex(S, txt);
692         pendingTextNode = toText(txt);
693     }
694     pendingText.nadd(string,len);
695     return txt;
696 }
697
698 Vertex* Tree::popVertex()
699 {
700     Vertex *v = NZ( stackTop );
701     stackTop = v -> parent;
702     return v;
703 }
704
705 eFlag Tree::parseFinished(Sit S)
706 {
707     flushPendingText();
708     return OK;
709 }
710
711 HashTable& Tree::dict() 
712 {
713     return theDictionary;
714 }
715
716 SabArena& Tree::getArena()
717 {
718     return theArena;
719 }
720
721 const QName& Tree::getTheEmptyQName() const
722 {
723     return theEmptyQName;
724 }
725
726
727 Bool Tree::cmpQNames(const QName &first, const QName &second) const
728 {
729 /*
730     printf("comparing names (%s,%s,%s) and (%s,%s,%s)\n",
731         (char*)(((Tree*)this)->expand(first.getPrefix())),
732             (char*)(((Tree*)this)->expand(first.getUri())),
733             (char*)(((Tree*)this)->expand(first.getLocal())),
734         (char*)(((Tree*)this)->expand(second.getPrefix())),
735             (char*)(((Tree*)this)->expand(second.getUri())),
736             (char*)(((Tree*)this)->expand(second.getLocal()))
737         );
738 */      
739     if (first.getLocal() == stdPhrase(PHRASE_STAR))
740         return (Bool)(first.getPrefix() == UNDEF_PHRASE || 
741             first.getUri() == second.getUri());
742     else
743         return (Bool) (first.getUri() == second.getUri()
744                 && first.getLocal() == second.getLocal());
745 }
746
747 Bool Tree::cmpQNamesForeign(const QName &q, const HashTable& dictForeign, const QName &qForeign)
748 {
749 /*
750     printf("comparing names (%s,%s,%s) and (%s,%s,%s)\n",
751         (char*)(((Tree*)this)->expand(q.getPrefix())),
752             (char*)(((Tree*)this)->expand(q.getUri())),
753             (char*)(((Tree*)this)->expand(q.getLocal())),
754         (char*)(dictForeign.getKey(qForeign.getPrefix())),
755             (char*)(dictForeign.getKey(qForeign.getUri())),
756             (char*)(dictForeign.getKey(qForeign.getLocal()))
757         );
758 */      
759
760     if (q.getLocal() == stdPhrase(PHRASE_STAR))
761     {
762         return (Bool)(q.getPrefix() == UNDEF_PHRASE || 
763             (dict().getKey(q.getUri()) == dictForeign.getKey(qForeign.getUri())));
764         }
765     else
766     {
767         return (Bool) 
768                 (dict().getKey(q.getUri()) == dictForeign.getKey(qForeign.getUri()) &&
769             dict().getKey(q.getLocal()) == dictForeign.getKey(qForeign.getLocal()));            
770         }
771 }
772
773 Bool Tree::cmpQNameStrings(const QName &q, const Str& uri, const Str& local)
774 {
775     if (q.getLocal() == stdPhrase(PHRASE_STAR))
776         return (Bool)(
777             q.getUri() == UNDEF_PHRASE || dict().getKey(q.getUri()) == uri);
778     else
779     {
780         return (Bool) 
781                 (dict().getKey(q.getUri()) == uri &&
782             dict().getKey(q.getLocal()) == local);              
783         }
784 }
785
786 void Tree::expandQ(const QName& q, EQName& expanded)
787 {
788     expanded.setLocal(expand(q.getLocal()));
789     expanded.setUri(expand(q.getUri()));
790     expanded.setPrefix(expand(q.getPrefix()));
791 }
792
793 void Tree::expandQStr(const QName& q, Str& expName)
794 {
795     EQName expanded;
796     expandQ(q, expanded);
797     expanded.getname(expName);
798 }
799
800 const Str& Tree::expand(Phrase ph)
801 {
802     return dict().getKey(ph);
803 }
804
805 Phrase Tree::unexpand(const Str& strg)
806 {
807     Phrase result;
808     dict().insert(strg, result);
809     return result;
810 }
811
812 eFlag Tree::serialize(Sit S, char *& result)
813 {
814     OutputterObj out;
815     OutputDefinition def;
816     GP( DataLine ) targetLine = new DataLine;
817     // set default options for output
818     EQName xmlMethod;
819     xmlMethod.setLocal((char*)"xml");
820     E( def.setItemEQName(S, XSLA_METHOD, xmlMethod, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
821     E( def.setDefaults(S) ); 
822     E( (*targetLine).open(S, (const char*)"arg:/dummy_", DLMODE_WRITE, NULL) );
823     out.setOptions(S, targetLine, &def);
824     E( getRoot().serialize(S, out) );
825     result = (*targetLine).getOutBuffer() -> compactToBuffer();
826     E( (*targetLine).close(S) );
827     targetLine.del();
828     return OK;
829 }
830
831 eFlag Tree::serializeNode(Sit S, Element *v, char *& result)
832 {
833     OutputterObj out;
834     OutputDefinition def;
835     GP( DataLine ) targetLine = new DataLine;
836     // set default options for output
837     EQName xmlMethod;
838     xmlMethod.setLocal((char*)"xml");
839     E( def.setItemEQName(S, XSLA_METHOD, xmlMethod, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
840     E( def.setDefaults(S) ); 
841     E( (*targetLine).open(S, (const char*)"arg:/dummy_", DLMODE_WRITE, NULL) );
842     out.setOptions(S, targetLine, &def);
843     E( (*v).serializeSubtree(S, out) );
844     result = (*targetLine).getOutBuffer() -> compactToBuffer();
845     E( (*targetLine).close(S) );
846     targetLine.del();
847     return OK;
848 }
849
850 void Tree::makeStamps()
851 {
852     int stamp_ = 0;
853     getRoot().makeStamps(stamp_);
854     vcount = stamp_;
855 }
856
857 void Tree::updateImportStatus() 
858 {
859   if (! subtrees.getCurrent() -> getStructure() -> getTopLevelFound() )
860     {
861       StylesheetStructure * stru = subtrees.getCurrent() -> getStructure();
862       stru -> setTopLevelFound(true);
863       stru -> setImportPrecedence(importUnique);
864       importUnique--;
865     }
866 }
867
868 /*****************************************************************
869 Tree::processVertexAfterParse()
870 Performs any necessary actions on a vertex immediately after it is
871 parsed into the tree. The vertex is still 'current'. Typically, this
872 function calls popVertex.
873 ARGS:
874     v   the vertex to be processed
875 The function operates only on XSL vertices, namely:
876 xsl:include - replaces the vertex by the newly constructed tree
877 xsl:output  - files the information into the tree's structures
878 ...
879 Other vertices are just popped off the stack.
880 *****************************************************************/
881
882 eFlag Tree::processVertexAfterParse(Sit S, Vertex *v, TreeConstructer* tc)
883 {
884   //be careful with this test, it might be moved deeper inside this 
885   //function if needed
886
887   if (v -> vt & VT_TOP_FOREIGN) 
888     {
889       popVertex();
890       return OK;
891     }
892
893   XSL_OP theOp;
894   if (isXSLElement(v))
895     {
896       XSLElement *x = toX(v);
897       theOp = x -> op;
898
899       if (theOp != XSL_IMPORT) updateImportStatus();
900
901       switch(theOp)
902         {
903           //catch xsl:use-attribute-sets
904         case XSL_ELEMENT:
905         case XSL_COPY: 
906           {
907             E( extractUsedSets(S, toE(v)) );
908             popVertex();
909           }; break;
910         case XSL_IMPORT:
911           {
912             if (subtrees.getCurrent() -> getStructure() -> getTopLevelFound())
913               {
914                 Err2(S, E_ELEM_CONTAINS_ELEM, 
915                      xslOpNames[XSL_STYLESHEET], 
916                      xslOpNames[XSL_IMPORT]);
917               }
918           }; // no break
919         case XSL_INCLUDE:
920           {
921             Attribute *a = NZ( x -> atts.find(XSLA_HREF) );
922             GP( Tree ) srcTree; 
923             const Str& base = S.findBaseURI(a -> getSubtreeInfo() ->
924                                             getBaseURI());              
925             
926             Str absolute;
927             makeAbsoluteURI(S, a -> cont, base, absolute);
928             if (S.getProcessor())
929               {
930                 E( S.getProcessor() -> readTreeFromURI(S, srcTree, 
931                                                        a -> cont, base, 
932                                                        FALSE) );
933                 srcTree.keep();
934               }
935             else
936               {
937                 //Str absolute;
938                 //makeAbsoluteURI(a -> cont, base, absolute);
939                 srcTree = new Tree(absolute, FALSE);
940                 DataLine d;
941                 E( d.open(S, absolute, DLMODE_READ, /* argList = */ NULL) );
942                 E( (*srcTree).parse(S, &d) );
943                 E( d.close(S) );
944               }
945             
946             Element *theSheet=(*srcTree).findStylesheet((*srcTree).getRoot());
947             if (!theSheet)
948                 Warn1(S, W_NO_STYLESHEET, (char*)(a -> cont));
949             dropCurrentElement(v);
950             
951             OutputterObj source;
952             // we start a subtree to record where the nodes come from
953             // when including, we use the old structure
954             // when importing, Tree creates a new one
955             E( startSubtree(S, (*srcTree).getURI(), theOp) );
956             //set extension namespaces for subtree
957
958             //(*srcTree).speakDebug();
959
960             //merge it into the current tree
961             E( tc -> parseUsingSAXForAWhile(S, source, absolute, 
962                                             TRUE, 
963                                             (Tree*)srcTree,
964                                             theSheet -> namespaces) );
965
966             //first we have to deal with ext. and excl. namespaces
967             Attribute *attr;
968             QName q;
969             //exclusions
970             q.setLocal((*srcTree).unexpand("exclude-result-prefixes"));
971             attr = theSheet->atts.find(q);
972             if (attr)
973               E(pushNamespacePrefixes(S, attr->cont, XSLA_EXCL_RES_PREFIXES));
974             //extensions
975             q.setLocal((*srcTree).unexpand("extension-element-prefixes"));
976             attr = theSheet->atts.find(q);
977             if (attr)
978               E(pushNamespacePrefixes(S, attr->cont, XSLA_EXT_ELEM_PREFIXES));
979
980             if (theSheet)
981               E( theSheet -> contents.copy(S, source) );
982             E( tc -> parseUsingSAXForAWhileDone(S, source, TRUE) );
983             // end the subtree
984             E( endSubtree(S, theOp) );          
985           }; break;
986         case XSL_OUTPUT:
987           {
988             int i, attsNumber = x -> atts.number();
989             Attribute *theAtt;
990             for (i = 0; i < attsNumber; i++)
991               {
992                 theAtt = toA(x -> atts[i]);
993                 switch(theAtt -> op)
994                   {
995                   case XSLA_METHOD:
996                     {
997                       QName q;
998                       EQName eq;
999                       E( x -> setLogical(S, 
1000                                          q, theAtt -> cont, FALSE) );
1001                       expandQ(q, eq);
1002                       E( outputDef.setItemEQName(S, XSLA_METHOD, 
1003                                                  eq, v, 
1004                                                  v -> getImportPrecedence()) );
1005                     }; break;
1006                   case XSLA_CDATA_SECT_ELEMS:
1007                     {
1008                       QName q;
1009                       Bool someRemains;
1010                       Str listPart;
1011                       char *p = theAtt -> cont;
1012                       do
1013                         {
1014                           someRemains = getWhDelimString(p, listPart);
1015                           if (someRemains)
1016                             {
1017                               E( x -> setLogical(S, 
1018                                                  q, listPart, TRUE) );
1019                               EQName expanded;
1020                               expandQ(q, expanded);
1021                               E( outputDef.setItemEQName(S, 
1022                                                          XSLA_CDATA_SECT_ELEMS,
1023                                                          expanded, v, 
1024                                                          v -> getImportPrecedence()) );
1025                             };
1026                         }
1027                       while (someRemains);
1028                     }; break;
1029                   case XSLA_NONE: //skip other namespaces
1030                     break;
1031                   default:
1032                     {
1033                       E( outputDef.setItemStr(S, theAtt -> op, theAtt -> cont, 
1034                                               theAtt, 
1035                                               theAtt -> getImportPrecedence()) );
1036                       
1037                     };
1038                   };
1039               }
1040             popVertex();
1041           }; break;
1042         case XSL_NAMESPACE_ALIAS:
1043           {
1044             Phrase style, result, sUri, rUri;
1045             Attribute *sp = NZ( x -> atts.find(XSLA_STYLESHEET_PREFIX) );
1046             Attribute *rp = NZ( x -> atts.find(XSLA_RESULT_PREFIX) );
1047             if (sp -> cont == "#default") style = UNDEF_PHRASE;
1048             else dict().insert(sp -> cont, style);
1049             if (rp -> cont == "#default") result = UNDEF_PHRASE;
1050             else dict().insert(rp -> cont, result);
1051
1052             int i;
1053             i = pendingNS().findNdx(style);
1054             if (i != -1)
1055               sUri = toNS(pendingNS().operator[](i)) -> uri;
1056             else
1057               Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) sp -> cont);
1058
1059             i = pendingNS().findNdx(result);
1060             if (i != -1)
1061               rUri = toNS(pendingNS().operator[](i)) -> uri;
1062             else
1063               Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) rp -> cont);
1064
1065             aliases().insertAlias(sUri, rUri, result, 
1066                                   v -> getImportPrecedence(), x);
1067             popVertex();
1068           }; break;
1069         case XSL_TEMPLATE:
1070           {
1071             E( insertRule(S, x) );
1072             popVertex();
1073           }; break;
1074         case XSL_ATTRIBUTE_SET:
1075           {
1076             QName name;
1077             
1078             E( x -> setLogical(S, name,
1079                                NZ( x -> atts.find(XSLA_NAME)) -> cont, 
1080                                FALSE) );
1081             AttSet *ptr = attSets().insert(name);
1082             E( extractUsedSets(S, toE(v)) );
1083             if (x -> attSetNames(FALSE))
1084               {
1085                 for (int i = 0; i < x -> attSetNames(FALSE) -> number(); i++)
1086                  ptr -> insertUses(*(x -> attSetNames(FALSE) -> operator[] (i)));
1087               }
1088             XSLElement *son;
1089             for (int i = 0; i < x -> contents.number(); i++)
1090               {
1091                 assert(isXSLElement(x -> contents[i]) && 
1092                        toX(x -> contents[i]) -> op == XSL_ATTRIBUTE);
1093                 son = toX(x -> contents[i]);
1094                 E( son -> setLogical(S, name, 
1095                                      NZ( son -> atts.find(XSLA_NAME)) -> cont,
1096                                      FALSE) );
1097                 ptr -> insertAttributeDef(son, name);
1098               }
1099             popVertex();
1100           }; break;
1101         case XSL_STYLESHEET:
1102         case XSL_TRANSFORM:
1103           {
1104             popVertex();
1105           }; break;
1106         case XSL_VARIABLE:
1107         case XSL_PARAM:
1108           {
1109             // only look at top-levels
1110             Vertex *par = v -> parent;
1111             if (par && isXSLElement(par) && 
1112                 (toX(par) -> op == XSL_STYLESHEET || 
1113                  toX(par) -> op == XSL_TRANSFORM))
1114               {
1115                 // is top-level -> insert into directory, 
1116                 //with error if there already is an entry 
1117                 // with the same import precedence
1118                 // find name first
1119                 QName name;
1120                 E( x -> setLogical(S, name, 
1121                                    NZ( x -> atts.find(XSLA_NAME)) -> cont, 
1122                                    FALSE) );
1123                 E( toplevelVars.insert(S, name, x) );
1124               }
1125             popVertex();
1126           }; break;
1127         case XSL_STRIP_SPACE:
1128           {
1129             SpaceNameList &foo = 
1130               subtrees.getCurrent() -> getStructure() -> strippedNames();
1131             E( getSpaceNames(S, *x, NZ(x -> atts.find(XSLA_ELEMENTS)) -> cont, 
1132                              foo) );
1133             popVertex();
1134           }; break;
1135         case XSL_PRESERVE_SPACE:
1136           {
1137             SpaceNameList &foo = 
1138               subtrees.getCurrent() -> getStructure() -> preservedNames();
1139             E( getSpaceNames(S, *x, NZ(x -> atts.find(XSLA_ELEMENTS)) -> cont, 
1140                              foo) );
1141             popVertex();
1142           }; break;
1143         default:
1144           popVertex();
1145         }
1146         //the literal output element may have some xsl features
1147     }
1148   else 
1149     { //isXSLElement
1150       updateImportStatus();
1151       if (XSLTree) {
1152         E( extractUsedSets(S, toE(v)) );
1153         popVertex();
1154       }
1155       else {
1156         popVertex();
1157       }
1158     }
1159   return OK;
1160 }
1161
1162 eFlag Tree::getSpaceNames(Sit S, Element &e, Str &str, SpaceNameList &where)
1163 {
1164   char *p, *q;
1165   q = (char*)str;
1166   skipWhite(q);
1167   p = q;
1168   int i = strcspn(q, theWhitespace);
1169   while (*q && i) 
1170     {
1171       q += i;
1172       char save = *q;
1173       *q = 0;
1174       
1175       Str token = p;
1176       QName name;
1177       E( e.setLogical(S, name, token, FALSE) );
1178       GP(EQName) ename = new EQName;
1179       expandQ(name, *ename);
1180       where.append(ename.keep());
1181
1182       *q = save;
1183       skipWhite(q);
1184       p = q;
1185       i = strcspn(q, theWhitespace);
1186     }
1187
1188   return OK;
1189 }
1190
1191 eFlag Tree::markNamespacePrefixes(Sit S)
1192 {
1193   if (XSLTree)
1194     getCurrentInfo() -> pushNamespaceMarks();
1195   return OK;
1196 }
1197
1198 eFlag Tree::pushNamespacePrefixes(Sit S, Str& prefixes, XSL_ATT att)
1199 {
1200   if (!XSLTree) return OK;
1201
1202   PList<Str*> tokens;
1203   char *p, *q;
1204   q = (char*) prefixes;
1205   skipWhite(q);
1206   p = q;
1207   int i = strcspn(q, theWhitespace);
1208   while (*q && i) 
1209     {
1210       q += i;
1211       char save = *q;
1212       *q = 0;
1213       
1214       Str* aux = new Str(p);
1215       tokens.append(aux);
1216
1217       *q = save;
1218       skipWhite(q);
1219       p = q;
1220       i = strcspn(q, theWhitespace);
1221     }
1222   //add to list
1223   SubtreeInfo *info = getCurrentInfo();
1224   for (i = 0; i < tokens.number(); i++)
1225     {
1226       Str tok = *(tokens[i]);
1227       Phrase prefix = 
1228         tok == (const char*) "#default" ? UNDEF_PHRASE : unexpand(tok);
1229       int idx = pendingNS().findNdx(prefix);
1230       if (idx != -1)
1231         {
1232           switch (att) {
1233           case XSLA_EXT_ELEM_PREFIXES:
1234             {
1235               info -> getExtensionNS().append(toNS(pendingNS()[idx]) -> uri);
1236             }; //no break
1237           case XSLA_EXCL_RES_PREFIXES:
1238             {
1239               info -> getExcludedNS().append(toNS(pendingNS()[idx]) -> uri);
1240             }; break;
1241           }
1242         }
1243       else
1244         {
1245           Str aux = *(tokens[i]);
1246           tokens.freeall(FALSE);
1247           Err1(S, E_EX_NAMESPACE_UNKNOWN, (char*) aux);
1248         }
1249     }
1250   tokens.freeall(FALSE);
1251   //printf("----------------------------\n");
1252   return OK;
1253 }
1254
1255 eFlag Tree::popNamespacePrefixes(Sit S)
1256 {
1257   if (XSLTree)
1258     getCurrentInfo() -> popNamespaceMarks();
1259   return OK;
1260 }
1261
1262 eFlag Tree::extractUsedSets(Sit S, Element *e) 
1263 {
1264     Attribute *a = e -> atts.find(XSLA_USE_ATTR_SETS); 
1265     if (a) 
1266     {
1267         QNameList *names = e -> attSetNames(TRUE);
1268         names -> freeall(FALSE);
1269         char *p, *q;
1270
1271         q = (char*) (a -> cont);
1272         skipWhite(q);
1273         p = q;
1274         int i = strcspn(q, theWhitespace);
1275         while (*q && i) {
1276             q += i;
1277             char save = *q;
1278             *q = 0;
1279
1280             Str token = p;
1281             GP( QName ) name = new QName;
1282             E( e -> setLogical(S, *name, token, FALSE) );
1283
1284             names -> append( name.keep() );
1285             *q = save;
1286             skipWhite(q);
1287             p = q;
1288             i = strcspn(q, theWhitespace);
1289         }
1290
1291     }
1292     return OK;
1293 }
1294
1295 /*****************************************************************
1296 findStylesheet()
1297 finds a xsl:stylesheet child of the given daddy. Returns NULL 
1298 if not found.
1299 *****************************************************************/
1300
1301 Element* Tree::findStylesheet(Daddy& d)
1302 {
1303     Vertex *w;
1304     int dContentsNumber = d.contents.number();
1305     for (int i = 0; i < dContentsNumber; i++)
1306     {
1307         if (isElement(w = d.contents[i]))
1308         {
1309             const QName& wName = toE(w) -> name;
1310                 Tree& owner = w -> getOwner();
1311                     Str localStr;
1312 //            if (!strcmp(wName.getUri(), theXSLTNamespace) && /* _PH_ */
1313             if (wName.getUri() == owner.stdPhrase(PHRASE_XSL_NAMESPACE) &&
1314                ((localStr = owner.expand(wName.getLocal()) == 
1315                        xslOpNames[XSL_STYLESHEET]) ||
1316                (localStr == xslOpNames[XSL_TRANSFORM])))
1317             return toE(w);
1318         }
1319     };
1320     return NULL;
1321 }
1322
1323 double Tree::defaultPriorityLP(Expression *lpath)
1324 {
1325     assert(lpath && lpath -> functor == EXF_LOCPATH);
1326     assert(lpath -> args.number());
1327     if ((lpath -> args.number() > 1) || lpath -> args[0] -> step -> preds.number())
1328         return .5;
1329     else
1330     {
1331         switch (lpath -> args[0] -> step -> ntype)
1332         {
1333         case EXNODE_COMMENT:
1334         case EXNODE_TEXT:
1335         case EXNODE_NODE:
1336           return -0.5;
1337           break;
1338         case EXNODE_PI:
1339           return lpath->args[0]->step->piname == "" ? -0.5 : 0;
1340         case EXNODE_NONE:
1341           {
1342             QName &qn = lpath -> args[0] -> step -> ntest;
1343             if (qn.getLocal() != lpath -> getOwnerTree().stdPhrase(PHRASE_STAR))
1344               return 0.0;
1345             else
1346               {   
1347                 if (qn.getPrefix() == UNDEF_PHRASE)
1348                   return -0.5;
1349                 else
1350                   return -0.25;
1351               };
1352           }; break;
1353         default:
1354           return 0.5;
1355         };
1356     };
1357     return 0;   // BCC thinks we don't return enough
1358 }
1359
1360 double Tree::defaultPriority(XSLElement *tmpl)
1361 {
1362     Expression *e = tmpl -> getAttExpr(XSLA_MATCH);
1363     if (!e) 
1364         return PRIORITY_NOMATCH;
1365     switch(e -> functor)
1366     {
1367     case EXF_LOCPATH:
1368         {
1369             return defaultPriorityLP(e);
1370         }; break;
1371     case EXFO_UNION:
1372         {
1373             double max=0, priority;
1374             BOOL first = TRUE;
1375             int eArgsNumber = e -> args.number();
1376             for (int i=0; i < eArgsNumber; i++)
1377             {
1378                 priority = defaultPriorityLP(e -> args[i]);
1379                 if (first || (priority > max)) 
1380                     max = priority;
1381                 first = FALSE;
1382             };
1383             return max;
1384         }; break;
1385     default:
1386         {
1387             assert(!"expression not a union or LP");
1388             return 0;   // dummy
1389         }
1390     };
1391     return 0;       // dummy for BCC
1392 }
1393
1394 eFlag Tree::parse(Sit S, DataLine *d)
1395 {
1396     Log1(S, L1_PARSING, getURI());
1397     double time_was = getMillisecs();
1398     TreeConstructer tc(S);
1399     eFlag retval = tc.parseDataLineUsingExpat(S, this, d);
1400     if (!retval)
1401     {
1402         Log1(S, L1_PARSE_DONE, getMillisecsDiff(time_was));
1403     }
1404     return retval;
1405 }
1406
1407 eFlag Tree::getMatchingList(Sit S, Expression& match, Context& result)
1408 {
1409     E( getRoot().getMatchingList(S, match, result) );
1410     return OK;
1411 }
1412
1413 Bool Tree::isExtensionUri(Phrase uri) 
1414 {
1415   return getCurrentInfo() -> getExtensionNS().findNdx(uri) != -1;
1416 }
1417
1418 eFlag Tree::insertRule(Sit S, XSLElement *tmpl)
1419 {
1420     double prio;
1421     Attribute *a = tmpl -> atts.find(XSLA_PRIORITY);
1422     if (!a)
1423         prio = defaultPriority(tmpl);
1424     else
1425     {
1426         if (a -> cont.toDouble(prio))
1427             Err(S, ET_BAD_NUMBER);
1428     };
1429     QName q; 
1430     GP( QName ) mode = NULL;
1431     if (!!(a = tmpl -> atts.find(XSLA_NAME)))
1432         E( tmpl -> setLogical(S, q, a -> cont, FALSE) );
1433     if (q.getLocal() != UNDEF_PHRASE && 
1434         subtrees.getCurrent() -> getStructure() -> rules().findByName(
1435             *this, q))
1436     {
1437         Str fullName;
1438         expandQStr(q, fullName);
1439
1440         Err1(S, ET_DUPLICATE_RULE_NAME, fullName);
1441     };
1442     if (!!(a = tmpl -> atts.find(XSLA_MODE)))
1443         E( tmpl -> setLogical(S, *(mode = new QName), 
1444                               a -> cont, FALSE) );
1445     
1446     subtrees.getCurrent() -> getStructure() -> rules().insert(
1447         new RuleItem(tmpl,prio,q,mode.keep()));
1448     return OK;
1449 }
1450
1451 eFlag Tree::insertAttSet(Sit S, XSLElement *tmpl)
1452 {
1453     QName q; 
1454     Attribute *a;
1455     GP( QName ) sets = NULL;
1456     if (!!(a = tmpl -> atts.find(XSLA_NAME))) 
1457         E( tmpl -> setLogical(S, q, a -> cont, FALSE) );
1458     if (q.getLocal() != UNDEF_PHRASE && 
1459         attSets().findByName(q))
1460     {
1461         Str fullName;
1462         expandQStr(q, fullName);
1463         Err1(S, ET_DUPLICATE_ASET_NAME, fullName);
1464     };    
1465     attSets().append(new AttSet(q));
1466     return OK;
1467 }
1468
1469
1470
1471 eFlag Tree::startSubtree(Sit S, const Str& baseURI, XSL_OP dependency,
1472                          Bool isInline /* = FALSE */)
1473 {
1474     // look if the URI is on the way to root of the include tree
1475     if (subtrees.findAmongPredecessors(baseURI))
1476         Err1(S, E1_CIRCULAR_INCLUSION, baseURI);
1477     StylesheetStructure *structure;
1478     if (dependency == XSL_IMPORT)
1479         structure = createStylesheetStructure(S);
1480     else
1481         // find structure of current subtree (always defined since Tree::Tree)
1482         structure = NZ(subtrees.getCurrent()) -> getStructure();
1483
1484     subtrees.push(
1485         new SubtreeInfo(
1486             baseURI, 
1487             dependency,
1488             structure,
1489             isInline));
1490
1491     excludeStdNamespaces();
1492     //set parent tree (closest non-inline)
1493     if (isInline)
1494       for (SubtreeInfo *nfo = subtrees.getCurrent();
1495            nfo;
1496            nfo = nfo -> getParentSubtree())
1497         {
1498           if (!nfo -> isInline())
1499             {
1500               subtrees.getCurrent() -> setMasterSubtree(nfo);
1501               break;
1502             }
1503         }
1504
1505     return OK;
1506 }
1507
1508 eFlag Tree::endSubtree(Sit S, XSL_OP dependency)
1509 {
1510   /*
1511   subtrees.getCurrent()->getStructure()->setImportPrecedence(importUnique);
1512   if (dependency == XSL_IMPORT)
1513     {
1514       importUnique--;
1515     }
1516   */
1517
1518   // move current subtree
1519   subtrees.pop();
1520   return OK;
1521 }
1522
1523 StylesheetStructure* Tree::createStylesheetStructure(Sit S)
1524 {
1525     // current subtree is created in Tree::Tree() so must be NZ
1526     SubtreeInfo *currSubtree = NZ( subtrees.getCurrent() );
1527     // there is always a structure for an existing subtree
1528     StylesheetStructure *currStruct  = NZ( currSubtree -> getStructure() );
1529     // create new structure with precedence one higher
1530     //StylesheetStructure *newStruct = new StylesheetStructure(
1531     //currStruct -> getImportPrecedence() + 1);
1532     StylesheetStructure *newStruct = new StylesheetStructure(0);
1533
1534     // file newStruct into existing tree if stylesheet structures
1535     currStruct -> addImportStructure(S, newStruct);
1536     return newStruct;    
1537 }
1538
1539 eFlag Tree::findBestRule(
1540     Sit S, 
1541     XSLElement *&ret, 
1542     Context *c,
1543     QName *currMode,
1544     Bool importsOnly,
1545     SubtreeInfo *subtree /* NULL */)
1546 {
1547   SubtreeInfo *start = (importsOnly && subtree) ? subtree : subtrees[0];
1548     return NZ(start) -> getStructure() -> findBestRule(
1549         S, ret, c, currMode, importsOnly);
1550 }
1551
1552 Bool Tree::hasAnyStrippedName() {
1553   if (hasAnyStripped == -1)
1554     hasAnyStripped = subtrees[0] -> getStructure() -> hasAnyStripped();
1555   return hasAnyStripped;
1556 }
1557
1558 Bool Tree::hasAnyPreservedName() {
1559   if (hasAnyPreserved == -1)
1560     hasAnyPreserved = subtrees[0] -> getStructure() -> hasAnyPreserved();
1561   return hasAnyPreserved;
1562 }
1563
1564 Bool Tree::findStrippedName(EQName &name, int &prec, double &prio)
1565 {
1566   return 
1567     NZ(subtrees[0]) -> getStructure() -> 
1568         findStrippedName(name, prec, prio);
1569 }
1570
1571 Bool Tree::findPreservedName(EQName &name, int &prec, double &prio)
1572 {
1573   return 
1574     NZ(subtrees[0]) -> getStructure() -> 
1575         findPreservedName(name, prec, prio);
1576 }
1577
1578 XSLElement* Tree::findRuleByName(QName &q)
1579 {
1580     return NZ( subtrees[0] ) -> getStructure() -> findRuleByName(*this, q);
1581 }
1582
1583 /*
1584 eFlag Tree::resolveGlobals(Sit S, Context *c, Processor *proc)
1585 {
1586     assert(proc);
1587     QName temp;
1588     for (int i = 0; i < toplevelVars.number(); i++)
1589     {
1590         // resolve the global identified by pointer
1591         // the name does not matter
1592         temp.empty();
1593         E( proc -> resolveGlobal(S, c, temp, toplevelVars[i] -> getElement()) );
1594     }
1595     return OK;
1596 }
1597 */
1598
1599 void Tree::setUnparsedEntityUri(Str &name, Str &uri)
1600 {
1601   unparsedEntities.appendConstruct(name, uri);
1602 }
1603
1604 Str* Tree::getUnparsedEntityUri(Str &name)
1605 {
1606   return unparsedEntities.find(name);
1607 }
1608
1609 eFlag Tree::pushPendingNS(Sit S, Tree* srcTree, NSList &other) 
1610 {
1611   NSList *lst = new(&theArena) NSList();
1612   lst -> swallow(S, other, srcTree, this);
1613   pendingNSList.append(lst);
1614   return OK;
1615 }
1616     
1617 eFlag Tree::popPendingNS(Sit S)
1618 {
1619   pendingNSList.freelast(FALSE);
1620   return OK;
1621 }
1622
1623 /*
1624 void Tree::speakDebug()
1625 {
1626   DStr foo;
1627   getRoot().speak(foo, (SpeakMode)(SM_OFFICIAL | SM_INS_SPACES));
1628   printf("--------------------\n%s\n--------------------\n", (char*)foo);
1629 }
1630 */
1631
1632 //_TH_ v
1633 /****************************************
1634 T m p L i s t   methods
1635 ****************************************/
1636
1637 TmpList::TmpList():PList<Vertex *>()
1638 {
1639 #ifdef _TH_DEBUG
1640   puts("TmpList constructor");
1641 #endif
1642   //printf("TmpList constructor >%x<\n",this);
1643 }
1644
1645 TmpList::~TmpList()
1646 {
1647 #ifdef _TH_DEBUG
1648   puts("TmpList destructor");
1649 #endif
1650   //  dump();
1651   freeall(FALSE);
1652 }
1653 void TmpList::append(void *what)
1654 {
1655   //     printf("TmpList append\n");
1656   ((Vertex *)what)->ordinal=number();
1657   PList<Vertex *>::append((Vertex *)what);
1658 }
1659
1660 void TmpList::rm(int n)
1661 {
1662   //     printf("TmpList rm >%d<\n",n);
1663   PList<Vertex *>::rm(n);
1664   for(int i=n;i<number();i++)
1665     (*this)[i]->ordinal=i;
1666 }
1667
1668 void TmpList::freeall(Bool a)
1669 {
1670 #ifdef _TH_DEBUG
1671   printf("TmpList freeall(Bool)\n");
1672 #endif
1673   PList<Vertex *>::freeall(a);
1674 }
1675
1676 void TmpList::dump(int p)
1677
1678   /*
1679   Str vname;
1680   if(p==0) printf("TmpList.dump (%d item(s))\n", nItems);
1681   else printf("TmpList.dump %d (%d item(s))\n", p, nItems);
1682   for(int i=0; i<nItems; i++){
1683     ((*this)[i])->getOwner().expandQStr(toE((*this)[i]) -> getName(),vname);
1684     printf("%d:>%d< >%x< (%s)\n",i,((*this)[i])->ordinal,((*this)[i]),(char*)vname);
1685   }
1686   */
1687 };
1688
1689 int TmpList::findNum(void *p) const
1690 {
1691   int i;
1692   for (i = number()-1; (i >= 0) && !((Vertex *)p == (*this)[i]); i--) {};
1693   return i;
1694 }
1695
1696 void TmpList::rmP(void *p)
1697 {
1698   rm(((Vertex *)p)->ordinal);
1699 }
1700 //_TH_ ^
1701
1702 Attribute* AttsCache::find(XSL_ATT what)
1703 {
1704     int i;
1705     Attribute *a;
1706     int num = number();
1707     for (i = 0; i < num; i++)
1708     {
1709         // need to use a temporary variable
1710         // to get around Solaris template problem
1711         Vertex * pTemp = (*this)[i];
1712         a = cast(Attribute *, pTemp);
1713         if (a -> op == what)
1714             return a;
1715     };
1716     return NULL;
1717 }
1718
1719 int AttsCache::findNdx(const QName& attName)
1720 {
1721     int i;
1722     Attribute *a;
1723     int num = number();
1724     for (i = 0; i < num; i++)
1725     {
1726         // need to use a temporary variable
1727         // to get around Solaris template problem
1728         Vertex * pTemp = (*this)[i];
1729         a = toA(pTemp);
1730         if (attName == a -> getName())
1731             return i;
1732     };
1733     return -1;
1734 }
1735
1736 Attribute* AttsCache::find(const QName& attName)
1737 {
1738     int ndx = findNdx(attName);
1739     // need to use a temporary variable
1740     // to get around Solaris template problem
1741     if (ndx != -1)
1742       {
1743         Vertex * pTemp = (*this)[ndx];
1744         return toA(pTemp);
1745       } 
1746     else
1747       {
1748         return NULL;
1749       }
1750 }