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