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