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 "base.h"
34 #include "proc.h"
35 #include "expr.h"
36 #include "tree.h"
37 #include "context.h"
38 #include "vars.h"
39 // #include "xmlparse.h" - moved to parser.h
40 #include "parser.h"
41 #include "guard.h"
42 #include "key.h"
43 #include "domprovider.h"
44 
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48 
49 #ifdef SABLOT_DEBUGGER
50 #include "debugger.h"
51 #endif
52 
53 // GP: clean
54 
55 /*****************************************************************
56 R u l e I t e m   methods
57 *****************************************************************/
58 
RuleItem(XSLElement * arule,double aprio,QName & _name,QName * _mode)59 RuleItem::RuleItem(XSLElement *arule,double aprio, QName &_name,
60                    QName *_mode)
61 :
62 rule(arule), priority(aprio), name(_name), mode(_mode)
63 {
64   match = rule -> atts.find(XSLA_MATCH);
65 };
66 
67 
68 //
69 //  ~RuleItem
70 //  has to dispose of the mode
71 //
~RuleItem()72 RuleItem::~RuleItem()
73 {
74     cdelete(mode);
75 }
76 
77 
78 /*****************************************************************
79 R u l e S L i s t   methods
80 *****************************************************************/
81 
RuleSList()82 RuleSList::RuleSList()
83 :
84 SList<RuleItem*>(LIST_SIZE_LARGE)
85 {};
86 
~RuleSList()87 RuleSList::~RuleSList()
88 {
89     freeall(FALSE);
90 }
91 
compare(int first,int second,void * data)92 int RuleSList::compare(int first, int second, void *data)
93 {
94     return fcomp((*this)[first] -> priority, (*this)[second] -> priority);
95 };
96 
97 
findByName(const Tree & t,const QName & what) const98 XSLElement* RuleSList::findByName(const Tree& t, const QName &what) const
99 {
100     int theNumber = number();
101     for (int i=0; i < theNumber; i++)
102         if (t.cmpQNames((*this)[i] -> name, what))
103             return (*this)[i] -> rule;
104     return NULL;
105 }
106 
107 /*****************************************************************
108 
109   DataLineItem
110 
111 *****************************************************************/
112 
DataLineItem(Sit S_)113 DataLineItem::DataLineItem(Sit S_)
114 : situation(S_)
115 {
116 }
117 
~DataLineItem()118 DataLineItem::~DataLineItem()
119 {
120     // the following close should be checked for error!!
121     if (_dataline && _dataline -> mode != DLMODE_CLOSED)
122         _dataline -> close(situation);
123     cdelete(_dataline);
124     if (!_preparsedTree)
125         cdelete(_tree);
126 }
127 
128 /*****************************************************************
129 
130   DataLinesList
131 
132 *****************************************************************/
133 
findNum(Str & absoluteURI,Bool _isXSL,DLAccessMode _mode)134 int DataLinesList::findNum(Str &absoluteURI, Bool _isXSL,
135     DLAccessMode _mode)
136 {
137     int theNumber = number();
138     for (int i = 0; i < theNumber; i++)
139     {
140         DataLineItem* item = (*this)[i];
141         if ((item->_dataline -> fullUri == absoluteURI) &&
142             (item->_isXSL == _isXSL) &&
143             (item-> _dataline -> mode == _mode ||
144 	         item-> _dataline -> mode == DLMODE_CLOSED))
145         return i;
146     }
147     return -1;
148 }
149 
getTree(Str & absoluteURI,Bool _isXSL,DLAccessMode _mode)150 Tree* DataLinesList::getTree(Str &absoluteURI, Bool _isXSL,
151     DLAccessMode _mode)
152 {
153     int n;
154     if ((n = findNum(absoluteURI, _isXSL, _mode)) != -1)
155         return (*this)[n] -> _tree;
156     else
157         return NULL;
158 }
159 
addLine(Sit S,DataLine * d,Tree * t,Bool isXSL,Bool preparsedTree)160 eFlag DataLinesList::addLine(Sit S, DataLine *d, Tree *t, Bool isXSL,
161     Bool preparsedTree /* = FALSE */)
162 {
163     DataLineItem *item = new DataLineItem(S);
164     item -> _dataline = d;
165     item -> _tree = t;
166     item -> _isXSL = isXSL;
167     item -> _preparsedTree = preparsedTree;
168     append(item);
169     return OK;
170 }
171 
172 /*****************************************************************
173 *                                                                *
174 *   P r o c e s s o r   methods                                  *
175 *                                                                *
176 *****************************************************************/
177 
178 // disable the MSVC warning "'this' used in the initializer list"
179 
180 #ifdef WIN32
181 #pragma warning( disable : 4355 )
182 #endif
183 
Processor()184 Processor::Processor()
185 :
186   theArena(PROC_ARENA_SIZE)
187 #ifdef ENABLE_JS
188   , jscontexts(this)
189 #endif
190 
191 #ifdef WIN32
192 #pragma warning( default : 4355 )
193 #endif
194 
195 {
196 //    pushNewHandler();
197     theSchemeHandler = NULL;
198     theMessageHandler = NULL;
199     theSAXHandler = NULL;
200     theMiscHandler = NULL;
201     theEncHandler = NULL;
202     theSchemeUserData = theMessageUserData =
203         theSAXUserData = theMiscUserData = theEncUserData = NULL;
204     instanceData = NULL;
205     instanceSituation = NULL;
206     addedFlag = FALSE;
207     vars = NULL;
208     input = styleSheet = NULL;
209     keys = NULL;
210     nsUnique = 1;
211     hasMasterSituation = FALSE;
212     runsOnExternal = FALSE;
213 };
214 
prepareForRun()215 void Processor::prepareForRun()
216 {
217     // do this in open():
218     // vars = new VarsList();
219     input = styleSheet = NULL;
220     decimals().initialize();
221 }
222 
freeNonArgDatalines()223 void Processor::freeNonArgDatalines()
224 {
225     int i = 0;
226     while(i < datalines.number())
227     {
228         if (datalines[i] -> _dataline -> scheme != URI_ARG)
229 	    {
230             datalines.freerm(i, FALSE);
231 	    }
232         else
233         {
234             // removing the tree here because the arena gets disposed
235             // in cleanupAfterRun(). So only the arg buffers remain.
236 	        // only remove the tree if not preparsed
237 		    if (!datalines[i] -> _preparsedTree)
238                 cdelete(datalines[i] -> _tree);
239 	        // don't move the following line out of the else!
240             i++;
241         };
242     }
243     addedFlag = FALSE;
244 }
245 
cleanupAfterRun(Situation * Sp)246 void Processor::cleanupAfterRun(Situation *Sp)
247 {
248 /*
249 These deletes are now subsumed in "datalines.freeall()":
250     cdelete(input);
251     cdelete(result);
252     cdelete(styleSheet);
253 */
254 
255   styleSheet = input = NULL;
256     cdelete(vars);
257     cdelete(keys);
258     decimals().freeall(FALSE);
259 #ifdef ENABLE_JS
260     jscontexts.freeall(FALSE);
261 #endif
262 
263     outputDocuments.freeall(FALSE);
264     outputDocumentURIs.freeall(FALSE);
265 
266     freeNonArgDatalines();
267     if (Sp && !Sp -> isError())
268       {
269         sabassert(modes.isEmpty());
270         sabassert(outputters_.isEmpty());
271       }
272     else
273       {
274         modes.freeall(FALSE);
275         outputters_.freeall(FALSE);
276       };
277     if (Sp)
278 	Sp -> clear();
279     // hope this works:
280     //DETACH: move to Tree
281     // dictionary.destroy();
282     theArena.dispose();
283     runsOnExternal = FALSE;
284 }
285 
~Processor()286 Processor::~Processor()
287 {
288 //    popNewHandler();
289     baseURIMappings.freeall(FALSE);
290     // FIXME: MUST clear theRecoder but got no situation
291 //    theRecoder.clear();
292 };
293 
open(Sit S,const char * sheetURI,const char * inputURI)294 eFlag Processor::open(Sit S, const char *sheetURI, const char *inputURI)
295 {
296     Str temp;
297     DStr theBase;
298 
299     my_getcwd(theBase);
300     theBase = findBaseURI(S, Str("file://") + theBase);
301 
302     E( readTreeFromURI(S, styleSheet, temp = sheetURI, theBase, TRUE) );
303     //styleSheet -> speakDebug();
304     if ( S.hasFlag(SAB_DUMP_SHEET_STRUCTURE) )
305       styleSheet -> dumpStructure(S);
306 
307 #ifdef SABLOT_DEBUGGER
308     if (debugger) debugger -> setBreakpoints(S, styleSheet);
309 #endif
310 
311     runsOnExternal = !inputURI;
312     if (inputURI)
313       E( readTreeFromURI(S, input, temp = inputURI, theBase, FALSE) );
314     vars = new VarsList (*styleSheet);
315     keys = new KeySet;
316     return OK;
317 }
318 
run(Sit S,const char * resultURI,NodeHandle doc)319 eFlag Processor::run(Sit S, const char* resultURI, NodeHandle doc /*= NULL */)
320 {
321     Str temp;
322     DStr theBase;
323     my_getcwd(theBase);
324     theBase = findBaseURI(S, Str("file://") + theBase);
325 
326     //strip spaces from the document
327     if (input) E( stripTree(S, *input) )
328 
329     Log1(S, L1_EXECUTING, styleSheet -> getURI());
330     double time_was = getMillisecs();
331     E( pushOutputterForURI(S, temp = resultURI, theBase) );
332     E( outputter() -> eventBeginOutput(S) );
333 
334     inputRoot = !nhNull(doc) ? doc : (NodeHandle)&(NZ(input) -> getRoot());
335     GP( Context ) c = new Context(inputRoot);
336     (*c).set(inputRoot);
337 
338     /*
339         in vars, global prebindings go to call level 0,
340         global bindings to call level 1
341     */
342     vars -> startCall();
343     // start by resolving all globals
344     //E( resolveGlobals(S, c) ); It has been done twice (XSLElement::execute)
345     E( styleSheet -> getRoot().execute(S, c, FALSE) );
346     vars -> endCall();
347     c.del();
348 
349     E( outputter() -> eventTrailingNewline(S) );
350     E( outputter() -> eventEndOutput(S) );
351 
352     //done all outputetrs
353     //E( outputDocuments.finish(S) );
354 
355     // report info about the output document to the MiscHandler
356     void *miscUserData;
357     OutputDefinition *outDef = &(styleSheet -> outputDef);
358     MiscHandler *miscHlr = getMiscHandler(&miscUserData);
359     if (miscHlr)
360         miscHlr -> documentInfo(
361             miscUserData,
362             this,   // processor
363             outDef -> getValueStr(XSLA_MEDIA_TYPE),
364             outDef -> getValueStr(XSLA_ENCODING));
365 
366     E( popOutputter(S) );
367 
368     //check statuses
369     //this is not needed,
370     //cleanupAfterRun takes care in the case of error
371     //sabassert(!outputters_.number());
372 
373     Log1(S, L1_EXECUTION_DONE, getMillisecsDiff(time_was));
374     return OK;
375 }
376 
377 
378 
379 /*================================================================
380 getVarBinding
381     finds the current binding for the variable with the given name.
382     The binding is an expression. If none is present, returns NULL.
383 ================================================================*/
384 
getVarBinding(QName & which)385 Expression* Processor::getVarBinding(QName &which)
386 {
387     return vars -> getBinding(which);
388 }
389 
390 /*================================================================
391 execute
392 both flavours DEALLOCATE the context and set the pointer to NULL
393 ================================================================*/
394 
execute(Sit S,Vertex * IP,Context * & c,Bool resolvingGlobals)395 eFlag Processor::execute(Sit S, Vertex *IP, Context *&c, Bool resolvingGlobals)
396 {
397     while (!c -> isFinished())
398     {
399       c -> setCurrentNode(c -> current());
400         if (IP)
401 	  {
402             E( IP -> execute(S, c, resolvingGlobals) );
403 	  }
404         else
405 	  {
406             E( execApplyTemplates(S, c, resolvingGlobals) );
407 	  }
408         c -> shift();
409     };
410     cdelete(c);
411     return OK;
412 }
413 
execute(Sit S,VertexList & IPlist,Context * & c,Bool resolvingGlobals)414 eFlag Processor::execute(Sit S, VertexList &IPlist, Context *&c, Bool resolvingGlobals)
415 {
416     // we may need to remove some variable bindings on each pass
417     // through a for loop
418     Vertex *theParent = IPlist.number()? IPlist[0] -> parent : NULL;
419     XSLElement *theForParent;
420     if (theParent && isXSLElement(theParent) && toX(theParent) -> op == XSL_FOR_EACH)
421         theForParent = toX(theParent);
422     else
423         theForParent = NULL;
424 
425     while (c -> current())
426     {
427         c -> setCurrentNode(c -> current());
428         E( IPlist.execute(S, c, resolvingGlobals) );
429         c -> shift();
430         if (theForParent)
431             theForParent -> removeBindings(S);
432     };
433     cdelete(c);
434     return OK;
435 }
436 
execApplyTemplates(Sit S,Context * c,Bool resolvingGlobals)437 eFlag Processor::execApplyTemplates(Sit S, Context *c, Bool resolvingGlobals)
438 {
439     XSLElement *rule;
440     E( NZ(styleSheet) -> findBestRule(S, rule, c, getCurrentMode(), FALSE) );
441     if (!rule)
442         E( builtinRule(S, c, resolvingGlobals) )
443     else
444         E( rule -> execute(S, c, resolvingGlobals) );
445     return OK;
446 }
447 
execApplyImports(Sit S,Context * c,SubtreeInfo * subtree,Bool resolvingGlobals)448 eFlag Processor::execApplyImports(Sit S, Context *c, SubtreeInfo *subtree,
449 				  Bool resolvingGlobals)
450 {
451     XSLElement *rule;
452     E( NZ(styleSheet) ->
453        findBestRule(S, rule, c, getCurrentMode(), TRUE, subtree) );
454     if (rule)
455         E( rule -> execute(S, c, FALSE) );
456     return OK;
457 }
458 
builtinRule(Sit S,Context * c,Bool resolvingGlobals)459 eFlag Processor::builtinRule(Sit S, Context *c, Bool resolvingGlobals)
460 {
461   // may assume v to be a physical vertex
462   //Vertex *v = toPhysical(c -> current());
463   NodeHandle v = c -> current();
464 
465   switch (S.dom().getNodeType(v)) {
466   case DOCUMENT_NODE:
467   case ELEMENT_NODE:
468     //apply-templates
469     {
470       GP( Expression ) e = new Expression(styleSheet->getRoot(), EXF_LOCPATH);
471       (*e).setLS(AXIS_CHILD, EXNODE_NODE);
472       GP( Context ) newc;
473       newc.assign(c);
474       E( (*e).createContext(S, newc) );
475       newc.unkeep();
476       E( execute(S, NULL, newc, resolvingGlobals) );
477       newc.keep(); // GP: it's NULL by this time anyway
478       e.del();
479     }; break;
480   case TEXT_NODE:
481   case ATTRIBUTE_NODE:
482     //copy contents to output
483     {
484       const char *val = S.dom().getNodeValue(v);
485       E( outputter() -> eventData(S, Str(val)) );
486       S.dom().freeValue(v, (char*)val);
487     }; break;
488   case PROCESSING_INSTRUCTION_NODE:
489   case COMMENT_NODE:
490     {};
491   };
492 
493   /*
494   switch(v -> vt & VT_BASE)
495   {
496   case VT_ROOT:
497   case VT_ELEMENT:
498     //apply-templates
499     {
500       GP( Expression ) e = new Expression(*toE(v), EXF_LOCPATH);
501       (*e).setLS(AXIS_CHILD, EXNODE_NODE);
502       GP( Context ) newc;
503       newc.assign(c);
504       E( (*e).createContext(S, newc) );
505       newc.unkeep();
506       E( execute(S, NULL, newc, resolvingGlobals) );
507       newc.keep(); // GP: it's NULL by this time anyway
508       e.del();
509     }; break;
510     case VT_TEXT:
511   case VT_ATTRIBUTE:
512     //copy contents to output
513     {
514       DStr temp;
515       E( v -> value(S, temp, c) );
516       E( outputter() -> eventData(S, temp) );
517     }; break;
518   case VT_PI:
519   case VT_COMMENT:
520     {};
521   };
522   */
523   return OK;
524 };
525 
526 
527 /*................................................................
528 getCurrentMode()
529 RETURN: pointer to the current mode which is a QName
530 ................................................................*/
531 
getCurrentMode()532 QName* Processor::getCurrentMode()
533 {
534     return (modes.number() ? modes.last() : NULL);
535 }
536 
537 /*................................................................
538 pushMode()
539 called before every mode-changing apply-templates
540 ARGS:
541 m       the mode to be placed on top of the mode stack
542 ................................................................*/
543 
pushMode(QName * m)544 void Processor::pushMode(QName *m)
545 {
546     modes.append(m);
547 }
548 
549 /*................................................................
550 popMode()
551 called after every mode-changing apply-templates
552 removes the current mode from the mode stack FREEING it
553 ................................................................*/
554 
popMode()555 void Processor::popMode()
556 {
557     modes.freelast(FALSE);
558 }
559 
addLineNoTree(Sit S,DataLine * & d,Str & absolute,Bool isXSL)560 eFlag Processor::addLineNoTree(Sit S, DataLine *&d, Str &absolute, Bool isXSL)
561 {
562     GP( DataLine ) d_;
563     M( S, d_ = new DataLine );
564     E( (*d_).open(S, absolute, DLMODE_READ, &argList) );
565     E( datalines.addLine(S, d_, NULL, isXSL) );
566     d = d_.keep();
567     return OK;
568 }
569 
addLineTreeOnly(Sit S,DataLine * & d,Str & absolute,Bool isXSL,Tree * t)570 eFlag Processor::addLineTreeOnly(Sit S, DataLine *&d, Str &absolute, Bool isXSL,
571     Tree *t)
572 {
573     GP( DataLine ) d_;
574     M( S, d_ = new DataLine );
575     E( (*d_).setURIAndClose(S, absolute) );
576     E( datalines.addLine(S, d_, t, isXSL, /* preparsedTree = */ TRUE) );
577     d = d_.keep();
578     return OK;
579 }
580 
addLineParse(Sit S,Tree * & newTree,Str & absolute,Bool isXSL,Bool ignoreErr)581 eFlag Processor::addLineParse(Sit S, Tree *& newTree, Str &absolute,
582 			      Bool isXSL, Bool ignoreErr /* = FALSE */)
583 {
584     GP( DataLine ) d = new DataLine;
585     E( (*d).open(S, absolute, DLMODE_READ, &argList, ignoreErr) );
586     GP( Tree ) newTree_ = new Tree(absolute, isXSL );
587     //E( (*newTree_).parse(S, d) );
588     eFlag status = (*newTree_).parse(S, d);
589     E( (*d).close(S) );
590     //hold parse errors after dataline is closed
591     E( status );
592     E( datalines.addLine(S, d.keep(), newTree = newTree_.keep(), isXSL) );
593     return OK;
594 }
595 
findBaseURI(Sit S,const Str & unmappedBase)596 const Str& Processor::findBaseURI(Sit S, const Str& unmappedBase)
597 {
598     Str scheme, rest;
599     uri2SchemePath(S, unmappedBase, scheme, rest);
600     Str *mapping = baseURIMappings.find(scheme);
601     if (mapping) return *mapping;
602     mapping = baseURIMappings.find(""/**theEmptyString*/);
603     if (mapping) return *mapping;
604     return unmappedBase;
605 }
606 
607 //
608 //          Processor::baseForVertex
609 //
610 //  returns the *translated* base URI in effect for a given vertex
611 //
612 
baseForVertex(Sit S,Element * v)613 const Str& Processor::baseForVertex(Sit S, Element *v)
614 {
615     return findBaseURI(S, NZ(v) -> getSubtreeInfo() -> getBaseURI());
616 }
617 
618 
619 //
620 //          Processor::readTreeFromURI
621 //
622 //  reads in a tree from URI 'location' resolved against 'base' which is
623 //  a *translated* base (one for which the 'hard base URIs' have been taken
624 //  into account)
625 //
626 
readTreeFromURI(Sit S,Tree * & newTree,const Str & location,const Str & base,Bool isXSL,Bool ignoreErr)627 eFlag Processor::readTreeFromURI(Sit S, Tree*& newTree, const Str& location,
628 				 const Str& base, Bool isXSL,
629 				 Bool ignoreErr /* = FALSE */)
630 {
631     Str
632         absolute;
633     makeAbsoluteURI(S, location, base, absolute);
634     newTree = datalines.getTree(absolute, isXSL, DLMODE_READ);
635     if (!newTree)
636         E( addLineParse(S, newTree, absolute, isXSL, ignoreErr) );
637     return OK;
638 }
639 
createOutputterForURI(Sit S,Str & absolute,OutputterObj * & result,OutputDefinition * outDef)640 eFlag Processor::createOutputterForURI(Sit S, //Str& location, Str& base,
641 				       Str& absolute,
642 				       OutputterObj*& result,
643 				       OutputDefinition *outDef /*=null*/)
644 {
645   //Str absolute;
646   //makeAbsoluteURI(S, location, base, absolute);
647   if (datalines.getTree(absolute, FALSE, DLMODE_WRITE))
648     Err1(S, E1_URI_WRITE, absolute);
649   GP( DataLine ) d;
650   if ( !(absolute == "arg:/null") )
651     {
652       M( S, d = new DataLine );
653       E( (*d).open(S, absolute, DLMODE_WRITE, &argList) );
654       // FIXME: the NULL tree in the following
655       E( datalines.addLine(S, d.keep(), NULL, FALSE) );
656     } else { //physical output not required
657       d = NULL;
658     };
659   GP( OutputterObj ) newOut;
660   M( S, newOut = new OutputterObj );
661 
662   if (!outDef) outDef = &(styleSheet -> outputDef);
663   E( (*newOut).setOptions(S, d, outDef) );
664   if (theSAXHandler)
665     E( (*newOut).setOptionsSAX(S, theSAXHandler, theSAXUserData,
666 			       SAXOUTPUT_AS_PHYSICAL) );
667 
668   result = newOut.keep();
669 
670   return OK;
671 }
672 
getOutputDocument(Sit S,Str & href,OutputDocument * & resultDoc,OutputDefinition * def)673 eFlag Processor::getOutputDocument(Sit S, Str& href,
674 				      OutputDocument *&resultDoc,
675 				      OutputDefinition *def)
676 {
677   //OutputDocument * aux = outputDocuments.find(def ->
678 
679   //GP(OutputDocument) doc = new OutputDocument(newOut, def);
680   GP(OutputDocument) doc = new OutputDocument(href, def);
681 
682   resultDoc = doc.keep();
683   outputDocuments.append(resultDoc);
684 
685   return OK;
686 }
687 
startDocument(Sit S,OutputDocument * doc)688 eFlag Processor::startDocument(Sit S, OutputDocument *doc)
689 {
690   switch (doc -> getState()) {
691   case OUTDOC_ACTIVE:
692     {
693       sabassert(!"rewrite document");
694       //printf("---> aaa\n");
695       //OutputterObj *out = NZ( doc -> getOutputter());
696       //E( pushOutputter(S, out) );
697     }; break;
698   case OUTDOC_NEW:
699     {
700       ////////////////////////////////////////
701       //create the outputter
702       Str &href = doc -> getHref();
703       DStr base = "";
704       OutputterObj *current = outputter();
705       PhysicalOutputLayerObj *phys;
706       if (current && (phys = current->getPhysical()) && phys->getDataLine())
707 	{
708 	  base = phys -> getDataLine() -> fullUri;
709 	}
710       if (base == "" || base == "file:///__stdout" || base == "file:///__stderr")
711 	{
712 	  DStr cwd;
713 	  my_getcwd(cwd);
714 	  base = "file://";
715 	  base += cwd;
716 	  S.message(MT_LOG, L2_SUBDOC_BASE, href, base);
717 	}
718       S.message(MT_LOG, L2_SUBDOC, href, base);
719 
720       OutputterObj *newOut;
721       Str absolute;
722       makeAbsoluteURI(S, href, base, absolute);
723 
724       //test if the document was not output recently
725       if ( outputDocumentURIs.findIdx(absolute) != -1 ) {
726 	Err1( S, E_DUPLICIT_OUTDOC, absolute );
727       } else {
728 	doc -> setURI(absolute);
729 	outputDocumentURIs.insert(new Str(absolute));
730       }
731 
732       E( createOutputterForURI(S, absolute, newOut, doc->getDefinition()) );
733       E( pushOutputter(S, doc -> setOutputter(newOut)) );
734       E( outputter() -> eventBeginOutput(S) );
735 
736       doc -> setState(OUTDOC_ACTIVE);
737     }; break;
738   case OUTDOC_FINISHED:
739     sabassert(! "Couldn't write the document twice"); break;
740   }
741   return OK;
742 }
743 
finishDocument(Sit S,OutputDocument * doc,Bool canClose)744 eFlag Processor::finishDocument(Sit S, OutputDocument *doc, Bool canClose)
745 {
746   switch (doc -> getState()) {
747   case OUTDOC_NEW:
748   case OUTDOC_FINISHED:
749     sabassert(!"Could not finish unopened/finished document"); break;
750   case OUTDOC_ACTIVE:
751     {
752       E( doc -> finish(S) );
753       E( popOutputter(S) );
754     }; break;
755   }
756   return OK;
757 }
758 
pushOutputterForURI(Sit S,Str & location,Str & base,OutputDefinition * outDef)759 eFlag Processor::pushOutputterForURI(Sit S, Str& location, Str& base,
760 				     OutputDefinition *outDef /*=NULL*/)
761 {
762   OutputterObj *newOut;
763 
764   Str absolute;
765   makeAbsoluteURI(S, location, base, absolute);
766   E( createOutputterForURI(S, absolute, newOut, outDef) );
767 
768   outputters_.append(newOut);
769   return OK;
770 }
771 
pushTreeConstructer(Sit S,TreeConstructer * & newTC,Tree * t,SAXOutputType ot)772 eFlag Processor::pushTreeConstructer(Sit S, TreeConstructer *& newTC, Tree *t,
773 				     SAXOutputType ot)
774 {
775     newTC = NULL;
776     GP( TreeConstructer ) newTC_ = new TreeConstructer(S);
777     GP( OutputterObj ) newTCSource = new OutputterObj;
778     //E( (*newTCSource).setOptions(S, NULL, &(styleSheet -> outputDef)) ); //_PH_
779     M( S, newTC_+0 );
780     outputters_.append(newTCSource);
781     E( (*newTC_).parseUsingSAX(S, t, *newTCSource, ot) );
782     newTCSource.keep();
783     newTC = newTC_.keep();
784     return OK;
785 }
786 
pushOutputter(Sit S,OutputterObj * out_)787 eFlag Processor::pushOutputter(Sit S, OutputterObj* out_)
788 {
789     outputters_.append(out_);
790     return OK;
791 }
792 
popOutputter(Sit S)793 eFlag Processor::popOutputter(Sit S)
794 {
795     outputters_.freelast(FALSE);
796     return OK;
797 }
798 
popOutputterNoFree(Sit S)799 eFlag Processor::popOutputterNoFree(Sit S)
800 {
801     outputters_.deppend();
802     return OK;
803 }
804 
popTreeConstructer(Sit S,TreeConstructer * theTC)805 eFlag Processor::popTreeConstructer(Sit S, TreeConstructer *theTC)
806 {
807     popOutputter(S);
808     delete theTC;
809     return OK;
810 }
811 
812 /*
813 eFlag Processor::parse(Sit S, Tree *t, DataLine *d)
814 {
815     Log1(S, L1_PARSING, t -> name);
816     double time_was = getMillisecs();
817     TreeConstructer tc(S);
818     eFlag retval = tc.parseDataLineUsingExpat(S, t, d);
819     if (!retval)
820     {
821         Log1(S, L1_PARSE_DONE, getMillisecsDiff(time_was));
822     }
823     return retval;
824 }
825 */
826 
getArg(Sit S,const char * name,char * & buffer,Bool isUTF16)827 eFlag Processor::getArg(Sit S, const char* name, char*& buffer, Bool isUTF16)
828 {
829     Str temp, *value = argList.find(temp = (char*)name);
830     if (!value)
831         Err1(S, E1_ARG_NOT_FOUND,(char*) name);
832     buffer = (char*) *value;
833     return OK;
834 }
835 
836 //
837 //
838 //
839 //      plugin handler stuff
840 //
841 //
842 //
843 
setHandler(Sit S,HandlerType type,void * handler,void * userData)844 eFlag Processor::setHandler(Sit S, HandlerType type, void *handler, void *userData)
845 {
846     void **whereHandler, **whereUserData;
847     switch(type)
848     {
849     case HLR_SCHEME:
850         {
851             whereHandler = (void **)&theSchemeHandler;
852             whereUserData = &theSchemeUserData;
853         }; break;
854     case HLR_MESSAGE:
855         {
856             whereHandler = (void **)&theMessageHandler;
857             whereUserData = &theMessageUserData;
858         }; break;
859     case HLR_SAX:
860         {
861             whereHandler = (void **)&theSAXHandler;
862             whereUserData = &theSAXUserData;
863         }; break;
864     case HLR_MISC:
865         {
866             whereHandler = (void **)&theMiscHandler;
867             whereUserData = &theMiscUserData;
868         }; break;
869     case HLR_ENC:
870         {
871             whereHandler = (void **)&theEncHandler;
872             whereUserData = &theEncUserData;
873         }; break;
874     default:
875         Err1(S, E1_INVALID_HLR_TYPE, (int) type);
876     }
877     if (*whereHandler)
878     {
879         if (handler)
880             Warn1(S, W1_HLR_REGISTERED, hlrTypeNames[type])
881         else
882         {
883             *whereHandler = NULL;
884             *whereUserData = NULL;
885         }
886     }
887     else
888     {
889         if (handler)
890         {
891             *whereHandler = handler;
892             *whereUserData = userData;
893         }
894         else
895             Warn1(S, W1_HLR_NOT_REGISTERED, hlrTypeNames[type])
896     }
897     return OK;
898 }
899 
900 
getSchemeHandler(void ** udata)901 SchemeHandler* Processor::getSchemeHandler(void **udata)
902 {
903     if (udata)
904         *udata = theSchemeUserData;
905     return theSchemeHandler;
906 }
907 
getMessageHandler(void ** udata)908 MessageHandler* Processor::getMessageHandler(void **udata)
909 {
910     if (udata)
911         *udata = theMessageUserData;
912     return theMessageHandler;
913 }
914 
getSAXHandler(void ** udata)915 SAXHandler* Processor::getSAXHandler(void **udata)
916 {
917     if (udata)
918         *udata = theSAXUserData;
919     return theSAXHandler;
920 }
921 
getMiscHandler(void ** udata)922 MiscHandler* Processor::getMiscHandler(void **udata)
923 {
924     if (udata)
925         *udata = theMiscUserData;
926     return theMiscHandler;
927 }
928 
getEncHandler(void ** udata)929 EncHandler* Processor::getEncHandler(void **udata)
930 {
931     if (udata)
932         *udata = theEncUserData;
933     return theEncHandler;
934 }
935 
getHandlerUserData(HandlerType type,void * handler)936 void* Processor::getHandlerUserData(HandlerType type, void *handler)
937 {
938     switch(type)
939     {
940     case HLR_SCHEME: return theSchemeUserData;
941     case HLR_MESSAGE: return theMessageUserData;
942     case HLR_MISC: return theMiscUserData;
943     default: return theSAXUserData;
944     }
945 }
946 
setHardEncoding(const Str & hardEncoding_)947 void Processor::setHardEncoding(const Str& hardEncoding_)
948 {
949     hardEncoding = hardEncoding_;
950 }
951 
getHardEncoding() const952 const Str& Processor::getHardEncoding() const
953 {
954     return hardEncoding;
955 };
956 
957 /*****************************************************************
958 copyArg
959   called if the result document's location uses the arg:
960   scheme. Returns information about the associated named buffer.
961   if not found, returns -1 in argOrdinal and NULL in newCopy.
962 ARGS
963   argName       the name of the arg
964 RETURNS
965   *argOrdinal    the ordinal number of this arg. This is the number
966                 of the call to useArg() which defined the arg.
967   newCopy       pointer to a new copy of the arg (allocated via
968                 malloc())
969 *****************************************************************/
970 
copyArg(Sit S,const Str & argName,int * argOrdinal,char * & newCopy)971 void Processor::copyArg(Sit S, const Str& argName, int* argOrdinal,
972     char*& newCopy)
973 {
974     Str absolute;
975     int lineNo;
976     if ((makeAbsoluteURI(S, (Str&)argName, "arg:/", absolute) != URI_ARG)
977         || (lineNo = datalines.findNum(absolute, FALSE, DLMODE_WRITE)) == -1)
978     {
979         newCopy = NULL;
980         *argOrdinal = -1;
981         return;
982     }
983     DynBlock *block = NZ( datalines[lineNo] -> _dataline -> getOutBuffer() );
984     newCopy = block -> compactToBuffer(); // GP: OK (no exit route)
985 
986     //  set *argOrdinal
987     *argOrdinal = argList.findNum((char *)absolute + 4);    // skip 'arg:'
988 
989 }
990 
useArg(Sit S,const char * name,const char * val)991 eFlag Processor::useArg(Sit S, const char *name, const char *val)
992 {
993     sabassert(name);
994     DStr nameStr;
995     if (*name != '/')
996         nameStr = "/";
997     nameStr += name;
998     if (argList.find(nameStr))
999         Err1(S, E1_DUPLICATE_ARG, nameStr);
1000     StrStr *p = new StrStr;
1001     p -> key = nameStr;
1002     if (val)
1003         p -> value = val;
1004     else
1005         p -> value.empty();
1006     argList.append(p);
1007     addedFlag = TRUE;
1008 
1009     return OK;
1010 }
1011 
useTree(Sit S,const char * name,Tree * t)1012 eFlag Processor::useTree(Sit S, const char *name, Tree *t)
1013 {
1014   sabassert(name);
1015   DStr nameStr;
1016   if (*name != '/')
1017     nameStr = "/";
1018   nameStr += name;
1019   // to check for duplicate trees
1020   E( useArg(S, name, NULL) );
1021 
1022   Str absolute;
1023   DataLine *d;
1024   makeAbsoluteURI(S, nameStr, "arg:/", absolute);
1025   E( addLineTreeOnly(S, d, absolute, t -> XSLTree, t) );
1026   addedFlag = TRUE;
1027   return OK;
1028 }
1029 
addGlobalParam(Sit S,const char * name,const char * val)1030 eFlag Processor::addGlobalParam(Sit S, const char *name, const char *val)
1031 {
1032     sabassert(name);
1033     if (!val) val = (char*)"";
1034     globalParamsList.appendConstruct(name, val);
1035     return OK;
1036 }
1037 
useGlobalParam(Sit S,const char * name,const char * val)1038 eFlag Processor::useGlobalParam(Sit S, const char *name, const char *val)
1039 {
1040     sabassert(name);
1041     QName q;
1042     q.setLocal(NZ(styleSheet) -> unexpand(name));
1043     Expression *expr = new Expression(styleSheet -> getRoot(), EXF_ATOM);
1044     Str aux = val;
1045     expr -> setAtom(aux);
1046     vars -> addPrebinding(S, q, expr);
1047     return OK;
1048 }
1049 
useGlobalParams(Sit S)1050 eFlag Processor::useGlobalParams(Sit S)
1051 {
1052     while (globalParamsList.number())
1053     {
1054         StrStr& item = *(globalParamsList.last());
1055         E( useGlobalParam(S, item.key, item.value) );
1056 	    globalParamsList.freelast(FALSE);
1057     }
1058     return OK;
1059 }
1060 
setHardBaseURI(const char * hardBase)1061 void Processor::setHardBaseURI(const char* hardBase)
1062 {
1063   addBaseURIMapping(""/**theEmptyString*/, (const Str) hardBase);
1064 }
1065 
addBaseURIMapping(const Str & scheme,const Str & mapping)1066 void Processor::addBaseURIMapping(const Str& scheme, const Str& mapping)
1067 {
1068     int ndx = baseURIMappings.findNum(scheme);
1069     if (ndx != -1)
1070         baseURIMappings.freerm(ndx, FALSE);
1071     if (!mapping.isEmpty())
1072         baseURIMappings.appendConstruct(scheme, mapping);
1073 }
1074 
freeResultArgs(Sit S)1075 eFlag Processor::freeResultArgs(Sit S)
1076 {
1077     datalines.freeall(FALSE);
1078     argList.freeall(FALSE);
1079     addedFlag = FALSE;
1080     return OK;
1081 }
1082 
getArena()1083 SabArena* Processor::getArena()
1084 {
1085     return &theArena;
1086 }
1087 
prefixIsAliasTarget(Sit S,const Str & prefix,Bool & result)1088 eFlag Processor::prefixIsAliasTarget(Sit S, const Str& prefix, Bool& result)
1089 {
1090   result = FALSE;
1091   //we may enter during the tree copy as well
1092   if (styleSheet)
1093     {
1094       Phrase p = NZ(styleSheet) -> unexpand(prefix);
1095       for (int i = 0; i < styleSheet -> aliases().number(); i++)
1096 	{
1097 	  if (styleSheet -> aliases()[i] -> getValue() == p)
1098 	    {
1099 	      result = TRUE;
1100 	      break;
1101 	    }
1102 	}
1103     }
1104   return OK;
1105 }
1106 
getAliasedName(EQName & name,Bool & aliased)1107 void Processor::getAliasedName(EQName & name, Bool & aliased)
1108 {
1109   Str myUri = name.getUri();
1110   for (int i = 0; i < styleSheet -> aliases().number(); i++)
1111     {
1112       const Str & aliasUri =
1113 	styleSheet -> expand(styleSheet -> aliases()[i]->getKey());
1114       if (aliasUri && aliasUri == myUri)
1115 	{
1116 	  Phrase newUri = styleSheet -> aliases()[i] -> getValue();
1117 	  Phrase newPrefix = styleSheet -> aliases()[i] -> getPrefix();
1118 	  name.setUri(styleSheet -> expand(newUri));
1119 	  //name.setPrefix(styleSheet -> expand(newPrefix));
1120 	  aliased = true;
1121 	  break;
1122 	};
1123     }
1124 }
1125 
1126 /*
1127 Str Processor::getAliasedName(const EQName& name,
1128 			      NamespaceStack& currNamespaces,
1129 			      Bool expatLike)
1130 {
1131    DStr s;
1132    Str newPrefixStr;
1133    Str newUri;
1134    //Bool defaultNS = !name.hasPrefix();
1135 
1136    if (1 || name.hasPrefix())
1137    {
1138       Phrase newPrefix = UNDEF_PHRASE;
1139       Str myUri = name.getUri();
1140       int i;
1141       Bool aliasFound = FALSE;
1142       if (styleSheet)
1143       {
1144           for (i = 0; i < styleSheet -> aliases().number(); i++)
1145           {
1146 	    const Str* aliasUri =
1147 	      currNamespaces.getUri(styleSheet -> expand(
1148 	                         styleSheet -> aliases()[i]->getKey()));
1149 	    if (aliasUri && *aliasUri == myUri)
1150               {
1151 		newPrefix = styleSheet -> aliases()[i] -> getValue();
1152 		aliasFound = TRUE;
1153               };
1154 	  }
1155       };
1156 
1157       if (newPrefix == UNDEF_PHRASE)
1158 	{
1159 	  if (! aliasFound && name.hasPrefix())
1160 	    newPrefixStr = name.getPrefix();
1161 	}
1162       else
1163 	{
1164 	  newPrefixStr = styleSheet -> expand(newPrefix);
1165 	  //s += newPrefixStr;
1166 	  //we should proceed w/o this
1167 	  //currNamespaces.appendConstruct(name.getPrefix(),name.getUri(),TRUE);
1168 	  //currNamespaces.appendConstruct(newPrefixStr,
1169 	  // *currNamespaces.getUri(newPrefixStr));
1170 	};
1171 	//if (!s.isEmpty()) //could be empty e.g. for the default namespace
1172       //  s += ":";
1173    };
1174    if (expatLike)
1175      {
1176        s  = name.getUri();
1177        s += THE_NAMESPACE_SEPARATOR;
1178        s += name.getLocal();
1179        s += THE_NAMESPACE_SEPARATOR;
1180        s += newPrefixStr;
1181      }
1182    else
1183      {
1184        s = newPrefixStr;
1185        if (! s.isEmpty()) s += ":";
1186        s += name.getLocal();
1187      }
1188    return s;
1189 }
1190 */
1191 
addKey(Sit S,const EQName & ename,Expression & match,Expression & use)1192 eFlag Processor::addKey(Sit S, const EQName& ename,
1193 			Expression& match, Expression &use)
1194 {
1195 
1196   //E( keys -> addKey(S, ename, toSXP_Document(*input), match, use) );
1197   E( NZ(keys) -> addKey(S, ename, inputRoot, match, use) );
1198   return OK;
1199 }
1200 
getKeyNodes(Sit S,const EQName & ename,const Str & value,Context & result,SXP_Document doc) const1201 eFlag Processor::getKeyNodes(Sit S, const EQName& ename,
1202 			     const Str& value, Context& result,
1203 			     SXP_Document doc) const
1204 {
1205     E( NZ(keys) -> getNodes(S, ename, doc, value, result) );
1206     return OK;
1207 }
1208 
makeKeysForDoc(Sit S,SXP_Document doc)1209 eFlag Processor::makeKeysForDoc(Sit S, SXP_Document doc)
1210 {
1211     E( NZ(keys) -> makeKeysForDoc(S, doc) );
1212     return OK;
1213 }
1214 
1215 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2) const1216 void Processor::report(Sit S, MsgType type, MsgCode code,
1217     const Str &arg1, const Str &arg2) const
1218 {
1219     S.message(type, code, arg1, arg2);
1220 }
1221 
initForSXP(Tree * baseTree)1222 void Processor::initForSXP(Tree *baseTree)
1223 {
1224   input = NULL;
1225   styleSheet = baseTree;
1226   runsOnExternal = TRUE;
1227   if (!vars)
1228     vars = new VarsList(*styleSheet);
1229 }
1230 
cleanupAfterSXP()1231 void Processor::cleanupAfterSXP()
1232 {
1233   vars -> freeall(FALSE);
1234   styleSheet = NULL;
1235   runsOnExternal = FALSE;
1236 }
1237 
supportsFunction(Str & uri,Str & name)1238 Bool Processor::supportsFunction(Str &uri, Str &name)
1239 {
1240 #ifdef ENABLE_JS
1241   JSContextItem *item = jscontexts.find(uri, FALSE);
1242   if (item) {
1243     for (int i = 0; i < item -> names.number(); i++) {
1244       if (*(item -> names[i]) == name) return TRUE;
1245     }
1246   }
1247   return FALSE;
1248 #else
1249   return FALSE;
1250 #endif
1251 }
1252 
1253 #ifdef ENABLE_JS
evaluateJavaScript(Sit S,Str & uri,DStr & script)1254 eFlag Processor::evaluateJavaScript(Sit S, Str &uri, DStr &script)
1255 {
1256   //printf("===> evaluating uri %s: %s\n", (char*)uri, (char*)script);
1257 
1258   JSContextItem *item = jscontexts.find(uri, TRUE);
1259   sabassert(item);
1260   if (item && item -> cx) {
1261     if (! SJSEvaluate(*item, script ) )
1262       {
1263 	Str msg = "'";
1264 	msg = msg + (item -> errInfo.message ? item -> errInfo.message : "");
1265 	if (item -> errInfo.token) {
1266 	  msg = msg + "' token: '";
1267 	  msg = msg + (item -> errInfo.token ? item -> errInfo.token : "");
1268 	}
1269 	msg = msg + "'";
1270 	Err2( S, E_JS_EVAL_ERROR,
1271 	      Str(item -> errInfo.line), msg );
1272       }
1273   }
1274 
1275   return OK;
1276 }
1277 
callJSFunction(Sit S,Context * c,Str & uri,Str & name,ExprList & atoms,Expression & retxpr)1278 eFlag Processor::callJSFunction(Sit S, Context *c, Str &uri, Str &name,
1279 				  ExprList &atoms, Expression &retxpr)
1280 {
1281   if (supportsFunction(uri, name)) {
1282     JSContextItem *item = jscontexts.find(uri, FALSE);
1283     if (item) {
1284       if (! SJSCallFunction(S, c, *item, name, atoms, retxpr) )
1285 	{
1286 	  Str msg = "'";
1287 	  msg = msg + (item -> errInfo.message ? item -> errInfo.message : "");
1288 	  if (item -> errInfo.token) {
1289 	    msg = msg + "' token: '";
1290 	    msg = msg + (item -> errInfo.token ? item -> errInfo.token : "");
1291 	  }
1292 	  msg = msg + "'";
1293 	  Err2( S, E_JS_EVAL_ERROR,
1294 		Str(item -> errInfo.line), msg );
1295 	};
1296     }
1297   }
1298 
1299   return OK;
1300 }
1301 #endif
1302 
getNextNSPrefix()1303 Str Processor::getNextNSPrefix()
1304 {
1305   char ret[10];
1306   sprintf(ret, "ns_%d", nsUnique++);
1307   return Str(ret);
1308 }
1309 
resolveGlobal(Sit S,Context * c,QName & name,XSLElement * varElem)1310 eFlag Processor::resolveGlobal(Sit S, Context *c, QName &name, XSLElement *varElem /* = NULL */)
1311 {
1312   // if !varElem, we need to ask styleSheet's toplevel var directory
1313   /*
1314   if (!varElem)
1315     varElem = styleSheet -> findVarInDirectory(name);
1316   else
1317     {
1318       // set the variable name from the element
1319       E( varElem -> setLogical(S, name, NZ(varElem -> atts.find(XSLA_NAME)) -> cont, FALSE) );
1320     }
1321   */
1322 
1323   //we have either the name or the element, if both, the element wins
1324   if (varElem)
1325       E( varElem->setLogical(S, name,
1326 			     NZ(varElem->atts.find(XSLA_NAME))->cont, FALSE) );
1327   //this element must be the same as the varElem if available
1328   XSLElement *aux = styleSheet -> findVarInDirectory(name);
1329   if (varElem)
1330     {
1331       //it should happen only if the caller is XSLElement::execute
1332       //and we have some overriden (import) declaration
1333       //in such a case we simply skip the processing
1334       if (varElem != aux) return OK;
1335     }
1336   else
1337     {
1338       varElem = aux;
1339     }
1340 
1341   if (varElem)
1342     {
1343       // find the var record for several references
1344       VarBindings* record = vars -> find(name);
1345       // maybe it has a binding defined from a forward reference?
1346       //but it shouldn't happen now, due the ** condition
1347       if (record && vars -> getBinding(record))
1348 	return OK;
1349       else
1350 	{
1351 	  // maybe it is an "open toplevel" (currently processed)
1352 	  if (record && vars -> isOpenGlobal(record))
1353 	    {
1354 	      Str fullName;
1355 	      styleSheet -> expandQStr(name, fullName);
1356 	      Err1(S, E1_VAR_CIRCULAR_REF, fullName);
1357 	    }
1358 	  else
1359 	    {
1360 	      // process it normally
1361 	      E( vars -> openGlobal(S, name, record) );
1362 	      // varElem's expression will automatically evaluate with "resolvingGlobal"
1363 	      E( varElem -> execute(S, c, /* resolvingGlobals = */ TRUE) );
1364 	      E( vars -> closeGlobal(S, record) );
1365 	    }
1366 	}
1367     }
1368   else
1369     {
1370       // this is not a global
1371       Str fullName;
1372       styleSheet -> expandQStr(name, fullName);
1373       Err1(S, E1_VAR_NOT_FOUND, fullName);
1374     }
1375   return OK;
1376 }
1377 
1378 /*
1379 eFlag Processor::resolveGlobals(Sit S, Context *c)
1380 {
1381      return styleSheet -> resolveGlobals(S, c, this);
1382 }
1383 */
1384 
stripElement(Sit S,Daddy * e)1385 eFlag Processor::stripElement(Sit S, Daddy *e)
1386 {
1387   if (isElement(e) && ! toE(e) -> preserveSpace)
1388     {
1389       EQName ename;
1390       e -> getOwner().expandQ(e -> getName(), ename);
1391       int sprec, pprec;
1392       double sprio, pprio;
1393       Bool s = styleSheet -> findStrippedName(ename, sprec, sprio);
1394       Bool p = styleSheet -> findPreservedName(ename, pprec, pprio);
1395 
1396       if (s && (!p || sprec < pprec || sprio > pprio))
1397 	{
1398 	  e -> contents.strip();
1399 	}
1400     }
1401 
1402   //process recursively
1403   for (int i = 0; i < e -> contents.number(); i++)
1404     {
1405       if (isElement(e -> contents[i]))
1406 	E( stripElement(S, toE(e -> contents[i])) );
1407     }
1408   return OK;
1409 }
1410 
stripTree(Sit S,Tree & tree)1411 eFlag Processor::stripTree(Sit S, Tree &tree)
1412 {
1413   //strip is forbidden
1414   if (S.hasFlag(SAB_DISABLE_STRIPPING)) return OK;
1415 
1416   //never strip the tree twice
1417   if (tree.stripped) return OK;
1418 
1419   //skip if no definition in the stylesheet
1420   if (!styleSheet -> hasAnyStrippedName() &&
1421       ! styleSheet -> hasAnyPreservedName())
1422     return OK;
1423 
1424   //do it
1425   Daddy &d = tree.getRoot();
1426   E( stripElement(S, &d) );
1427 
1428   tree.stripped = TRUE;
1429 
1430   return OK;
1431 }
1432 
pushInBinding(Bool val)1433 void Processor::pushInBinding(Bool val)
1434 {
1435   inBinding.append(val);
1436 }
1437 
popInBinding()1438 void Processor::popInBinding()
1439 {
1440   inBinding.deppend();
1441 }
1442 
isInBinding()1443 Bool Processor::isInBinding()
1444 {
1445   return inBinding.number() && inBinding.last();
1446 }
1447 
1448 /*
1449 eFlag Processor::pushDocumentDefinition(Sit S, OutputDefinition *def,
1450 					OutputterObj*& out)
1451 {
1452   sabassert(def);
1453   Bool change = !documentDefinitions.number() ||
1454     documentDefinitions.last() != def;
1455 
1456   documentDefinitions.append(def);
1457 
1458   if (change)
1459     {
1460       Str href = "file:///home/pavel/ga/sablot-ext/bin/inner.xml";
1461       Str base = "";
1462       E( pushOutputterForURI(S, href, base, def) );
1463       E( outputter() -> eventBeginOutput(S) );
1464     }
1465 
1466   out = outputter();
1467   return OK;
1468 }
1469 
1470 eFlag Processor::popDocumentDefinition(Sit S)
1471 {
1472   sabassert(documentDefinitions.number());
1473   OutputDefinition *last = documentDefinitions.last();
1474   documentDefinitions.deppend();
1475   //
1476   if (!documentDefinitions.number() || documentDefinitions.last() != last)
1477     {
1478       E( outputter() -> eventTrailingNewline(S) );
1479       E( outputter() -> eventEndOutput(S) );
1480       E( popOutputter(S) );
1481     }
1482   return OK;
1483 }
1484 
1485 */
1486