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): Marc Lehmann <pcg@goof.com>
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 "expr.h"
34 #include "verts.h"
35 #include <float.h>
36 #include <math.h>
37 #include "context.h"
38 #include "tree.h"
39 #include "utf8.h"
40 #include "domprovider.h"
41 #include "guard.h"
42 
43 // GP: clean.....
44 
45 // period is not here as it can also start a number
46 char tokenShort[]=
47 ".. :: // != <= >= "
48 "(  )  [  ]  @  ,  "
49 "|  +  -  =  <  >  "
50 "/  *  "
51 "\x0\x0\x0";
52 
53 ExToken tokenShortX[]=
54 {
55     TOK_DPERIOD, TOK_DCOLON, TOK_DSLASH, TOK_NEQ, TOK_LE, TOK_GE,
56         TOK_LPAREN, TOK_RPAREN, TOK_LBRACKET, TOK_RBRACKET, TOK_ATSIGN, TOK_COMMA,
57         TOK_VERT, TOK_PLUS, TOK_MINUS, TOK_EQ, TOK_LT, TOK_GT,
58         TOK_SLASH, TOK_STAR
59 };
60 
61 /*================================================================
62     function info table
63 ================================================================*/
64 
65 struct FuncInfoItem
66 {
67     const char *name;
68     ExFunctor func;
69     ExType type;
70 }
71 funcInfoTable[] =
72 {
73     // XPath functions - NODESET category
74     {"last",EXFF_LAST,EX_NUMBER},
75     {"position",EXFF_POSITION,EX_NUMBER},
76     {"count",EXFF_COUNT,EX_NUMBER},
77     {"id",EXFF_ID,EX_NODESET},
78     {"local-name",EXFF_LOCAL_NAME,EX_STRING},
79     {"namespace-uri",EXFF_NAMESPACE_URI,EX_STRING},
80     {"name",EXFF_NAME,EX_STRING},
81 
82     // XPath - STRING category
83     {"string",EXFF_STRING,EX_STRING},
84     {"concat",EXFF_CONCAT,EX_STRING},
85     {"starts-with",EXFF_STARTS_WITH,EX_BOOLEAN},
86     {"contains",EXFF_CONTAINS,EX_BOOLEAN},
87     {"substring-before",EXFF_SUBSTRING_BEFORE,EX_STRING},
88     {"substring-after",EXFF_SUBSTRING_AFTER,EX_STRING},
89     {"substring",EXFF_SUBSTRING,EX_STRING},
90     {"string-length",EXFF_STRING_LENGTH,EX_NUMBER},
91     {"normalize-space",EXFF_NORMALIZE_SPACE,EX_STRING},
92     {"translate",EXFF_TRANSLATE,EX_STRING},
93 
94     // XPath - BOOLEAN category
95     {"boolean",EXFF_BOOLEAN,EX_BOOLEAN},
96     {"not",EXFF_NOT,EX_BOOLEAN},
97     {"true",EXFF_TRUE,EX_BOOLEAN},
98     {"false",EXFF_FALSE,EX_BOOLEAN},
99     {"lang",EXFF_LANG,EX_BOOLEAN},
100 
101     // XPath - NUMBER category
102     {"number", EXFF_NUMBER, EX_NUMBER},
103     {"sum", EXFF_SUM, EX_NUMBER},
104     {"floor", EXFF_FLOOR, EX_NUMBER},
105     {"ceiling", EXFF_CEILING, EX_NUMBER},
106     {"round", EXFF_ROUND, EX_NUMBER},
107 
108     // XSLT core
109     {"document",EXFF_DOCUMENT,EX_NODESET},
110     {"key",EXFF_KEY,EX_NODESET},
111     {"format-number",EXFF_FORMAT_NUMBER, EX_STRING},
112     {"current",EXFF_CURRENT, EX_NODESET},
113     {"unparsed-entity-uri",EXFF_UNPARSED_ENTITY_URI, EX_STRING},
114     {"generate-id",EXFF_GENERATE_ID,EX_STRING},
115     {"system-property",EXFF_SYSTEM_PROPERTY, EX_STRING},
116 
117     // XSLT extensions
118     {"function-available",EXFF_FUNCTION_AVAILABLE,EX_BOOLEAN},
119     {"element-available",EXFF_ELEMENT_AVAILABLE,EX_BOOLEAN},
120     {NULL, EXFF_NONE, EX_UNKNOWN}
121 };
122 
123 struct ExtFuncInfoItem
124 {
125     const char *name;
126     ExFunctor func;
127     ExType type;
128 }
129 extFuncInfoTable[] =
130 {
131     {"evaluate",EXFF_EVAL,EX_NODESET},
132     {NULL, EXFF_NONE, EX_UNKNOWN}
133 };
134 
getFuncName(ExFunctor functor)135 Str getFuncName(ExFunctor functor)
136 {
137     return funcInfoTable[functor - EXF_FUNCTION - 1].name;
138 };
139 
140 
141 
142 /**********************************************************
143 TokenItem
144 **********************************************************/
145 
speak(DStr & s,SpeakMode mode)146 void TokenItem::speak(DStr &s, SpeakMode mode)
147 {
148     switch(tok)
149     {
150     case TOK_VAR:   // remove leading $
151         s.nadd(firstc + 1, len - 1);
152         break;
153     case TOK_LITERAL:// remove enclosing quotes or dquotes
154         s.nadd(firstc + 1, len - 2);
155         break;
156     default:
157         s.nadd(firstc,len);
158     };
159 //    s += '\0'; - thrown out
160 };
161 
162 /**********************************************************
163 
164   Tokenizer
165 
166 **********************************************************/
167 
Tokenizer(Expression & owner_)168 Tokenizer::Tokenizer(Expression &owner_)
169 :
170 items(LIST_SIZE_EXPR_TOKENS), owner(owner_)
171 {
172 };
173 
~Tokenizer()174 Tokenizer::~Tokenizer()
175 {
176     items.freeall(FALSE);
177 }
178 
tokenize(Sit S,const Str & astring)179 eFlag Tokenizer::tokenize(Sit S, const Str &astring)
180 {
181     char *p;
182     TokenItem item;
183     string = astring;
184     p = (char *) string;
185 
186     E( getToken(S, p, item, TOK_NONE) );
187     ExToken prevToken = item.tok;
188     while ((item.tok != TOK_END) && (item.tok != TOK_NONE))
189     {
190         items.append(new TokenItem(item));
191         E( getToken(S, p, item, prevToken) );
192         prevToken = item.tok;
193     };
194 
195     if (item.tok == TOK_NONE)
196     {
197         DStr itemStr;
198         item.speak(itemStr, SM_OFFICIAL);
199         Err1(S, ET_BAD_TOKEN, itemStr);
200     }
201     else
202         items.append(new TokenItem(item));
203 
204     return OK;
205 }
206 
207 /*================================================================
208 namerTable
209 a table of tokens which have the effect that the following
210 name is recognized as a NCName (rather than operator name) and * is
211 recognized as a wildcard (rather than multiplication operator).
212     The table should end with TOK_NONE (which is of this type too).
213 ================================================================*/
214 
215 static ExToken namerTable[] = {
216     TOK_ATSIGN, TOK_DCOLON, TOK_LPAREN, TOK_LBRACKET,
217         // operators:
218     TOK_OR, TOK_AND, TOK_EQ, TOK_NEQ, TOK_LT, TOK_GT, TOK_LE, TOK_GE,
219     TOK_PLUS, TOK_MINUS, TOK_MINUS1, TOK_MULT, TOK_DIV, TOK_MOD, TOK_VERT,
220         // slashes are operators too but not for us
221     TOK_SLASH, TOK_DSLASH, TOK_COMMA,
222         // TOK_NONE (terminator)
223     TOK_NONE};
224 
225 /*================================================================
226 Bool isNamer()
227 returns True iff the token is contained in the namerTable table.
228 ================================================================*/
229 
isNamer(ExToken tok)230 static Bool isNamer(ExToken tok)
231 {
232     int i;
233     if (tok == TOK_NONE) return TRUE;
234     for (i = 0; (namerTable[i] != tok) &&
235         (namerTable[i] != TOK_NONE); i++);
236     return (Bool) (namerTable[i] == tok);
237 }
238 
239 /*================================================================
240 ExToken tryShort()
241 looks up a few characters at p in the tokenShort table containing
242 the (up-to-3-char) symbols
243 RETURNS the token identified, or TOK_NONE if no match is found
244 ================================================================*/
245 
tryShort(char * & p,ExToken prevToken)246 ExToken Tokenizer::tryShort(char*& p, ExToken prevToken)
247 {
248     int i;
249     char* t;
250     ExToken result;
251 
252     for (i=0, t=tokenShort; *t; i++,t+=3)
253         if (*p==*t)
254         if ((t[1] == ' ') || (t[1] == p[1])) break;
255     if (*t)
256     {
257         p += ((t[1] == ' ')? 1 : 2);
258         result = tokenShortX[i];
259         if (result == TOK_STAR)
260             result = (isNamer(prevToken)? TOK_NAME : TOK_MULT);
261         if ((result == TOK_MINUS) && isNamer(prevToken))
262             result = TOK_MINUS1;
263     }
264     else result = TOK_NONE;
265     return result;
266 }
267 
268 /*================================================================
269 eFlag lookToken()
270 sets 'ret' to the following token, but does not change the pointer p
271 ================================================================*/
272 
lookToken(Sit S,ExToken & ret,char * p,ExToken prevToken)273 eFlag Tokenizer::lookToken(Sit S, ExToken &ret, char* p, ExToken prevToken)
274 {
275     // getToken_() changes p but this is passed by value so
276     // remains unchanged
277 
278     E( getToken_(S, ret, p, prevToken) );
279     return OK;
280 }
281 
282 /*================================================================
283 Bool findChar
284 sets p to address FOLLOWING the next occurence of c in p
285 (to skip a character reference, use findChar(p,';'))
286 RETURNS false iff the next occurence was not found
287 ================================================================*/
288 
findChar(char * & p,char c)289 static Bool findChar(char*& p, char c)
290 {
291     while (*p && (*p != c)) p++;
292     if (*p)
293     {
294         p++;
295         return TRUE;
296     }
297     else
298         return FALSE;
299 }
300 
301 /*================================================================
302 findSame
303 sets p to address FOLLOWING the next occurence of *p in p
304 RETURNS false iff another occurence was not found
305 ================================================================*/
306 
findSame(char * & p)307 static Bool findSame(char*& p)
308 {
309     char first = *p++;
310     return findChar(p, first);
311 };
312 
getToken_(Sit S,ExToken & ret,char * & p,ExToken prevToken)313 eFlag Tokenizer::getToken_(Sit S, ExToken &ret, char*& p, ExToken prevToken)
314 {
315     ExToken tok;
316     char c;
317 
318     skipWhite(p);
319     if (!*p)
320     {
321         ret = TOK_END;
322         return OK;
323     }
324     else
325     {
326         // the following may also translate * into TOK_NAME
327         if ((tok = tryShort(p, prevToken)) != TOK_NONE)
328         {
329             ret = tok;
330             return OK;
331         };
332         switch (c = *p)
333         {
334         case '$':
335             {
336                 // call getName with prevToken=TOK_NONE
337                 // to ensure that e.g. 'and' in '$and' is treated as a name
338                 E( getName(S, ret, ++p, TOK_NONE) );
339                 if (ret != TOK_NONE)
340                     ret = TOK_VAR;
341                 else
342                     Err(S, ET_BAD_VAR);
343             };
344             break;
345         case '\"':
346         case '\'':
347             if(!findSame(p))
348                 Err(S, ET_INFINITE_LITERAL)
349             else
350                 ret = TOK_LITERAL;
351             break;
352         case '&': sabassert(0);  //DBG: do not process entity references so far
353             break;
354         case '.':
355             if (utf8IsDigit(utf8CharCode(p+1)))
356             {
357                 E( getNumber(S, p) );
358                 ret = TOK_NUMBER;
359             }
360             else {
361                 p++;
362                 ret = TOK_PERIOD;
363             };
364             break;
365         default:
366             {
367                 if (utf8IsDigit(utf8CharCode(p)))
368                 {
369                     E( getNumber(S, p) );
370                     ret = TOK_NUMBER;
371                 }
372                 else
373                 {
374                     if (utf8IsLetter(utf8CharCode(p)) || (*p == '_') || (*p == ':'))
375                     {
376                         // the following call finds TOK_NAME, TOK_FNAME,
377                         // TOK_AXISNAME,
378                         // as well as TOK_AND etc. (based on prev token)
379                         E( getName(S, ret, p, prevToken) );
380                     }
381                     else
382                     {
383                         Str temp;
384                         temp.nset(p, 1);
385                         Err1(S, ET_BAD_TOKEN, temp); //unknown token
386                     }
387                 }
388             };  //default
389         };      //switch
390     };          //else
391     return OK;
392 };              //getToken_
393 
getToken(Sit S,char * & p,TokenItem & item,ExToken prevToken)394 eFlag Tokenizer::getToken(Sit S, char*& p, TokenItem& item, ExToken prevToken)
395 {
396     ExToken t;
397     skipWhite(p);
398     item.firstc = p;
399     E( getToken_(S, t, p, prevToken) );
400     item.len = (long)(p - item.firstc);
401     item.tok = t;
402     return OK;
403 }
404 
getNumber(Sit S,char * & p)405 eFlag Tokenizer::getNumber(Sit S, char*& p)
406 {
407     Bool wasDot = FALSE;
408     while ((*p) && (utf8IsDigit(utf8CharCode(p))) || (*p == '.'))
409     {
410         if (*p == '.')
411             if (wasDot)
412             Err(S, ET_BAD_NUMBER)
413             else wasDot = TRUE;
414         p += utf8SingleCharLength(p);
415     };
416     return OK;
417 };
418 
419 /*================================================================
420 getWordOp
421 checks whether the sequence at p of given length is an operator name
422 RETURNS the appropriate token if so; TOK_NONE otherwise
423 ================================================================*/
424 
getWordOp(char * p,int length)425 static ExToken getWordOp(char *p, int length)
426 {
427     if (length > 3) return TOK_NONE;
428     if (length < 2) length = 2;
429     if (!strncmp(p,"or",length)) return TOK_OR;
430     if (length < 3) length = 3;
431     if (!strncmp(p,"and",length)) return TOK_AND;
432     if (!strncmp(p,"div",length)) return TOK_DIV;
433     if (!strncmp(p,"mod",length)) return TOK_MOD;
434     return TOK_NONE;
435 }
436 
isNodeTest(char * p,int length)437 static Bool isNodeTest(char *p, int length)
438 {
439     const char *q;
440     int qlen;
441     for (int i = 0; (q = exNodeTypeNames[i]) != NULL; i++)
442     {
443         if (!strncmp(q,p,
444             (length < (qlen = strlen(q))? qlen : length)))
445             break;
446     };
447     return (Bool)(q != NULL);
448 }
449 
450 #define nameCharExtended(CH, PTR) ((CH = utf8CharCode(PTR))!= 0) &&\
451         (utf8IsNameChar(CH) || strchr(".-_:*",CH))
452 
nameLength(char * from)453 int nameLength(char* from)
454 {
455     char *q = from;
456     int length = 0;
457     unsigned long c;
458     while(nameCharExtended(c,q)) {
459        q += utf8SingleCharLength(q);
460        length++;
461     }
462     return length;
463 }
464 
getName(Sit S,ExToken & ret,char * & p,ExToken prevToken)465 eFlag Tokenizer::getName(Sit S, ExToken &ret, char*& p, ExToken prevToken)
466 {
467     char *former = p;
468     unsigned long c;
469     BOOL wasColon = FALSE;
470 
471     if ((!utf8IsLetter(utf8CharCode(p))) && (*p != '_'))
472     {
473         ret = TOK_NONE;
474         return OK;
475     }
476 
477     while (nameCharExtended(c,p))
478     {
479         if (c == ':')
480         {
481             if (wasColon)
482             {
483                 // identify the bad qname;
484                 Str theName;
485                 theName.nset(former, nameLength(former));
486                 Err1(S, E1_EXTRA_COLON, theName);
487             }
488             else
489             {
490                 switch(*(p+1))
491                 {
492                 case ':':
493                     {
494                         ret = TOK_AXISNAME;
495                         return OK;
496                     };
497                 case '*':
498                     {
499                         ret = TOK_NAME;
500                         p += 2;
501                         return OK;
502                     };
503                 default:
504                     wasColon = TRUE;
505                 };
506             };
507         }
508         else if (c == '*')
509         {
510             if ((p - former) && *(p - 1) != ':')   // the first condition could be dropped
511             {
512                 ret = TOK_NAME;
513                 return OK;
514             }
515         }
516         p += utf8SingleCharLength (p);
517     }
518 
519     if (!wasColon && !isNamer(prevToken))
520     {
521         if ((ret = getWordOp(former, (int) (p - former))) != TOK_NONE)
522             return OK;
523     };
524 
525     ExToken next;
526 
527     // look at following token with prev=TOK_NAME
528     E( lookToken(S, next,p,TOK_NAME) );
529     switch(next)
530     {
531     case TOK_DCOLON:
532         ret = TOK_AXISNAME;
533         break;
534     case TOK_LPAREN:
535         {
536             if (isNodeTest(former, (int) (p - former)))
537                 ret = TOK_NTNAME;
538             else
539                 ret = TOK_FNAME;
540         }; break;
541     default:
542         ret = TOK_NAME;
543     };
544     return OK;
545 };
546 
547 /*================================================================
548 int findTop()
549     finds the first top-level occurence of 'token' starting with
550     position 'from'. If there is none, return value points at TOK_END.
551 ================================================================*/
552 
findTop(ExToken token,int from)553 int Tokenizer::findTop(ExToken token, int from)
554 {
555     int level = 0;
556     ExToken ct;
557     int i;
558     for (i = from;
559         ((ct = items[i] -> tok) != TOK_END) && (level || (ct != token));
560         i++)
561         {
562             if ((ct == TOK_LPAREN) || (ct == TOK_LBRACKET))
563                 level++;
564             if ((ct == TOK_RPAREN) || (ct == TOK_RBRACKET))
565                 level--;
566         }
567     return i;
568 }
569 
570 
571 /*================================================================
572 eFlag getDelim()
573 given a position in 'pos', finds the corresponding next token.
574 If the left token is ( or [, looks for the matching right paren/bracket,
575 Otherwise looks for the occurence of the same token.
576 Returns pos pointing at the matching token, or at TOK_END if there
577 is none. (In case of failed reverse search, returns -1.)
578 ================================================================*/
579 
getDelim(Sit S,int & pos,Bool reverse)580 eFlag Tokenizer::getDelim(Sit S, int &pos, Bool reverse /*=FALSE*/)
581 {
582     ExToken first, second, tok;
583     int level = 0,
584         i = pos;
585 
586     switch(first = items[pos] -> tok)
587     {
588     case TOK_LBRACKET:
589         second = TOK_RBRACKET;
590         break;
591     case TOK_LPAREN:
592         second = TOK_RPAREN;
593         break;
594     case TOK_RBRACKET:
595         second = TOK_LBRACKET;
596         break;
597     case TOK_RPAREN:
598         second = TOK_LPAREN;
599         break;
600     default:
601         second = first;
602     }
603 
604     i += reverse? -1 : 1;
605 
606     while ((i >= 0) && ((tok = items[i] -> tok) != TOK_END))
607     {
608         if (tok == second)
609         {
610             if (!level)
611             {
612                 pos = i;
613                 return OK;
614             }
615             else level--;
616         }
617         else if (tok == first) level++;
618         i += reverse? -1 : 1;
619     }
620     pos = i;
621     return OK;
622 }
623 
624 /*================================================================
625 stripParens()
626 given the left and right end positions of a tokenizer fragment,
627 shifts them inwards to strip any outer parentheses.
628 ================================================================*/
629 
stripParens(Sit S,int & left,int & right)630 eFlag Tokenizer::stripParens(Sit S, int &left, int &right)
631 {
632     int left0 = left;
633     if (items[right]->tok == TOK_END)
634         right--;
635 //    sabassert(left <= right);
636     while ((items[left]->tok == TOK_LPAREN)
637         && (items[right]->tok == TOK_RPAREN))
638     {
639         left0 = left;
640         E( getDelim(S, left0) );
641         if (left0 == right)
642         {
643             left++;
644             right--;
645         }
646         else break;
647     };
648     return OK;
649 }
650 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)651 void Tokenizer::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
652 {
653     owner.report(S, type, code, arg1, arg2);
654 }
655 
656 
657 /*****************************************************************
658 *                                                                *
659       L o c S t e p
660 *                                                                *
661 *****************************************************************/
662 
LocStep(Element & ownerV_,ExAxis _axis,ExNodeType _ntype)663 LocStep::LocStep(Element& ownerV_, ExAxis _axis       /*=AXIS_NONE*/,
664                  ExNodeType _ntype  /*=EXNODE_NONE*/)
665 : preds(LIST_SIZE_1), ownerV(ownerV_)
666 {
667     set(_axis, _ntype);
668     positional = FALSE;
669     badPreds = 0;
670 }
671 
~LocStep()672 LocStep::~LocStep()
673 {
674     preds.freeall(FALSE);
675 }
676 
set(ExAxis _axis,ExNodeType _ntype)677 void LocStep::set(ExAxis _axis, ExNodeType _ntype)
678 {
679     ax = _axis;
680     ntype = _ntype;
681 }
682 
speak(Sit S,DStr & strg,SpeakMode mode)683 void LocStep::speak(Sit S, DStr &strg, SpeakMode mode)
684 {
685     if (!(mode & SM_CONTENTS)) return;
686     switch(ax)
687     {
688     case AXIS_CHILD:
689 //    case AXIS_DESC_OR_SELF:
690     case AXIS_ROOT:
691         break;
692     case AXIS_ATTRIBUTE:
693         strg += '@';
694         break;
695     default:
696         {
697             strg += axisNames[ax];
698             strg += "::";
699         };
700     };
701     if((ntype != EXNODE_NONE) //&& (ax != AXIS_DESC_OR_SELF)
702         && (ax != AXIS_ROOT))
703     {
704         strg += exNodeTypeNames[ntype];
705         strg += "()";
706     }
707     else
708     {
709 	    Str fullName;
710 	    getOwnerElement().getOwner().expandQStr(ntest,fullName);
711         // ntest.speak(S, strg,mode);
712 	    strg += fullName;
713 	}
714     int i, predsNumber = preds.number();
715     for (i = 0; i < predsNumber; i++)
716     {
717         strg += '[';
718         preds[i] -> speak(S, strg,mode);
719         strg += ']';
720     };
721 };
722 
parse(Sit S,Tokenizer & tokens,int & pos,Bool defaultToo)723 eFlag LocStep::parse(Sit S, Tokenizer& tokens, int& pos,
724 		     Bool defaultToo /* = FALSE */)
725 {
726     int right;
727     int &i = pos;
728     DStr temp;
729     ExToken tok;
730 
731     tok = tokens.items[i++]->tok;
732     if (tok == TOK_END)
733         Err(S, ET_EMPTY_PATT);
734     switch (tok)
735     {
736     case TOK_PERIOD:
737         ax = AXIS_SELF;
738         ntype = EXNODE_NODE;
739         return OK;
740         break;
741     case TOK_DPERIOD:
742         ax = AXIS_PARENT;
743         ntype = EXNODE_NODE;
744         return OK;
745         break;
746     case TOK_ATSIGN:
747         {
748             ax = AXIS_ATTRIBUTE;
749             tok = tokens.items[i++]->tok;
750         };
751         break;
752     case TOK_STAR:
753         {
754             ax = AXIS_CHILD;
755         };
756         break;
757     case TOK_AXISNAME:
758         {
759             tokens.items[i-1] -> speak(temp, SM_OFFICIAL);
760             if ((ax = (ExAxis) lookup(temp, axisNames)) == AXIS_NONE)
761                 Err1(S, E1_UNKNOWN_AXIS, temp);
762             i++;
763             tok = tokens.items[i++] -> tok;
764         };
765         break;
766     case TOK_NAME:
767     case TOK_NTNAME:
768         {
769 	  //	  if (!defaultAx)
770 	  //  Err(S, ET_EXPR_SYNTAX);
771 	  ax = AXIS_CHILD;
772         };
773         break;
774     default:
775         Err(S, ET_EXPR_SYNTAX); // axis name or node-test expected
776     };
777 
778     // axis has been determined; tok must now be a name or a node-test
779     temp.empty();
780     if ((tok != TOK_NAME) && (tok != TOK_NTNAME))
781         Err(S, ET_EXPR_SYNTAX); // axis name or node-test expected
782     tokens.items[i-1] -> speak(temp,SM_OFFICIAL);
783     ntype = EXNODE_NONE;
784 
785     if (tok == TOK_NTNAME)
786     {
787         ntype = (ExNodeType) lookup(temp, exNodeTypeNames);
788         if (tokens.items[i++]->tok != TOK_LPAREN)
789             Err(S, ET_LPAREN_EXP);
790 
791 	//pi test may hav one literal param
792 	if (ntype == EXNODE_PI && tokens.items[i]->tok == TOK_LITERAL) {
793 	  DStr pilit;
794 	  tokens.items[i++]->speak(pilit, SM_CONTENTS);
795 	  piname = pilit;
796 	}
797 
798         if (tokens.items[i++]->tok != TOK_RPAREN)
799 	  {
800             Err(S, ET_RPAREN_EXP);
801 	  }
802     }
803     else
804     {
805         // set the QName from prefix:uri using
806         // the namespace declarations in 'ownerE'
807         // (passed through from the containing attribute)
808         // DEFAULT: without using the default namespace
809         E( getOwnerElement().setLogical(S, ntest, temp, defaultToo) );
810 	}
811 
812     while ((tokens.items[i] -> tok) == TOK_LBRACKET)
813     {
814         badPreds = 0;
815         E( tokens.getDelim(S, right = i) );
816         if (tokens.items[right] -> tok == TOK_END)
817             Err(S, ET_RBRACKET_EXP)
818         else
819         {
820             GP( Expression ) ex = new Expression(getOwnerElement());
821             E( (*ex).parse(S, tokens,i+1,right-1) );
822             // find out about the use of last() and position()
823             int exPositionalType = (*ex).optimizePositional(0);
824             if (exPositionalType)
825             {
826                 positional = TRUE;
827                 if (exPositionalType == 2)
828                     badPreds++;
829                 // find sufficient position bounds
830                 (*ex).optimizePositionBounds();
831             }
832             preds.append(ex.keep());
833         };
834         i = right + 1;
835     };
836 
837     return OK;  // pointing at the first char that does not start a predicate
838 
839 };      //  end LocStep::parse()
840 
841 
matchesWithoutPreds(Sit S,NodeHandle v)842 Bool LocStep::matchesWithoutPreds(Sit S, NodeHandle v)
843 {
844     // removed the following:
845     // sabassert(v);
846     // (because the parent-of-root calls etc.)
847     if (nhNull(v))
848         return FALSE;
849     // ANDed with VT_BASE for ordinary vertices
850     SXP_NodeType ty = S.dom().getNodeType(v);
851     switch(ntype)
852     {
853     case EXNODE_NODE:
854         break;
855     case EXNODE_TEXT:
856         if (ty != TEXT_NODE)
857             return FALSE;
858         break;
859     case EXNODE_PI:
860         if (ty != PROCESSING_INSTRUCTION_NODE)
861             return FALSE;
862         break;
863     case EXNODE_COMMENT:
864         if (ty != COMMENT_NODE)
865             return FALSE;
866         break;
867     case EXNODE_NONE:
868         if ((ty == TEXT_NODE) || (ty == COMMENT_NODE) ||
869 	    (ty == DOCUMENT_NODE) || (ty == PROCESSING_INSTRUCTION_NODE))
870 	  return FALSE;
871         break;
872     };
873 
874     switch(ax)
875     {
876     case AXIS_ROOT:
877         return (Bool) (ty == DOCUMENT_NODE);
878         break;
879     case AXIS_ATTRIBUTE:
880         if (ty != ATTRIBUTE_NODE) return FALSE;
881         break;
882     case AXIS_NAMESPACE:
883         if (ty != NAMESPACE_NODE) return FALSE;
884         break;
885     case AXIS_CHILD:
886     case AXIS_DESCENDANT:
887     case AXIS_DESC_OR_SELF:
888     case AXIS_ANCESTOR:
889     case AXIS_ANC_OR_SELF:
890     case AXIS_FOLL_SIBLING:
891     case AXIS_PREC_SIBLING:
892     case AXIS_FOLLOWING:
893     case AXIS_PRECEDING:
894         switch (ty)
895         {
896         case ATTRIBUTE_NODE:
897         case NAMESPACE_NODE:
898             return FALSE;
899         case DOCUMENT_NODE:
900             switch(ax)
901             {
902             case AXIS_DESC_OR_SELF:
903             case AXIS_ANCESTOR:
904             case AXIS_ANC_OR_SELF:
905                 break;
906             default:
907                 return FALSE;
908             };
909         };
910         break;
911     case AXIS_SELF:
912       {
913 	if (ntype == EXNODE_NONE && ty != ELEMENT_NODE) return false;
914       }; break;
915     case AXIS_PARENT:
916         break;
917     default: sabassert(0); //should be handled in parse
918     };
919 
920     //if (ntype != EXNODE_NONE)
921     //    return TRUE;
922     switch (ntype)
923       {
924       case EXNODE_NONE:
925 	break;
926       case EXNODE_PI:
927 	{
928 	  if (! S.domExternal(v) && ! (piname == ""))
929 	    {
930 	      ProcInstr *pi = toPI(v);
931 	      EQName ename;
932 	      pi->getOwner().expandQ(pi->name, ename);
933 	      return ename.getLocal() == piname;
934 	    }
935 	  else
936 	    return TRUE;
937 	};
938       default:
939 	return TRUE;
940       }
941 
942     //exnode_none are processed here
943     if (S.domExternal(v))
944       {
945 	const char *uri = S.dom().getNodeNameURI(v);
946 	const char *local = S.dom().getNodeNameLocal(v);
947         Bool ret =  getOwnerElement().getOwner()
948 	  .cmpQNameStrings(ntest, uri, local);
949 	S.dom().freeName(v, (char*)uri);
950 	S.dom().freeName(v, (char*)local);
951 	return ret;
952       }
953     else
954       {
955         const QName &hisname = toV(v) -> getName();
956         return getOwnerElement().getOwner()
957 	  .cmpQNamesForeign(ntest, toV(v) -> dict(), hisname);
958       }
959 }
960 
961 
shift(Sit S,NodeHandle & v,NodeHandle baseV)962 eFlag LocStep::shift(Sit S, NodeHandle &v, NodeHandle baseV)
963 {
964     NodeHandle w = NULL;       // the result
965     switch(ax)
966     {
967     case AXIS_ATTRIBUTE:
968     {
969 	sabassert(S.domExternal(v) || nhNull(v) ||
970 	       isElement(baseV) && baseV == toV(v) -> parent);
971 	// i.e. v==NULL and baseV isn't daddy
972 	if (S.dom().getNodeType(baseV) != ELEMENT_NODE) break;
973 	for (w = (!nhNull(v) ?
974 		  S.dom().getNextAttrNS(v) :
975 		  S.dom().getAttributeNo(baseV, 0));
976 	     !nhNull(w) && !matchesWithoutPreds(S, w);
977 	     w = S.dom().getNextAttrNS(w));
978     }; break;
979 
980     case AXIS_CHILD:
981     {
982 	sabassert(S.domExternal(v) || nhNull(v) ||
983 	       isDaddy(baseV) && baseV == toV(v) -> parent);
984 	if (S.dom().getNodeType(baseV) != ELEMENT_NODE &&
985 	    S.dom().getNodeType(baseV) != DOCUMENT_NODE) break;
986 	for (w = !nhNull(v) ?
987 	       S.dom().getNextSibling(v) :
988 	       S.dom().getFirstChild(baseV);
989 	     !nhNull(w) && !matchesWithoutPreds(S, w);
990 	     w = S.dom().getNextSibling(w));
991     }; break;
992 
993     case AXIS_NAMESPACE:
994     {
995 	sabassert(S.domExternal(v) || nhNull(v) ||
996 	       isElement(baseV) && baseV == toV(v) -> parent);
997 	if (S.dom().getNodeType(baseV) != ELEMENT_NODE) break;
998 	for (w = !nhNull(v) ?
999 	       S.dom().getNextAttrNS(v) :
1000 	       S.dom().getNamespaceNo(baseV, 0);
1001 	     !nhNull(w) && !matchesWithoutPreds(S, w);
1002 	     w = S.dom().getNextAttrNS(w));
1003     }; break;
1004 
1005     case AXIS_ROOT:     // technically not an axis
1006     {
1007 	if (nhNull(v))
1008 	{
1009 	    w = S.dom().getOwnerDocument(baseV);
1010 	    if (nhNull(w)) // w must have been the root itself
1011 		w = baseV;
1012 	}
1013     }; break;
1014 
1015     case AXIS_SELF:
1016     {
1017 	if (nhNull(v) && matchesWithoutPreds(S, baseV))
1018 	    w = baseV;
1019     }; break;
1020 
1021     case AXIS_PARENT:
1022     {
1023 	if (nhNull(v) && matchesWithoutPreds(S, S.dom().getParent(baseV)))
1024 	    w = S.dom().getParent(baseV);
1025     }; break;
1026 
1027     case AXIS_ANCESTOR:
1028     case AXIS_ANC_OR_SELF:
1029     {
1030 	if (!nhNull(v))
1031 	    w = S.dom().getParent(v);
1032 	else
1033 	    w = (ax == AXIS_ANCESTOR) ? S.dom().getParent(baseV) : baseV;
1034 	for (; !nhNull(w) && !matchesWithoutPreds(S, w);
1035 	       w = S.dom().getParent(w));
1036     }; break;
1037 
1038     case AXIS_FOLL_SIBLING:
1039     {
1040 	switch(S.dom().getNodeType(baseV))
1041 	{
1042 	case DOCUMENT_NODE:
1043 	case NAMESPACE_NODE:
1044 	case ATTRIBUTE_NODE:
1045 	    break;
1046 	default:
1047 	    for (w = S.dom().getNextSibling(!nhNull(v) ? v : baseV);
1048 		 !nhNull(w) && !matchesWithoutPreds(S, w);
1049 		 w = S.dom().getNextSibling(w));
1050 	}
1051     }; break;
1052 
1053     case AXIS_PREC_SIBLING:
1054     {
1055 	switch(S.dom().getNodeType(baseV))
1056 	{
1057 	case DOCUMENT_NODE:
1058 	case NAMESPACE_NODE:
1059 	case ATTRIBUTE_NODE:
1060 	    break;
1061 	default:
1062 	    for (w = S.dom().getPreviousSibling(!nhNull(v) ? v : baseV);
1063 		 !nhNull(w) && !matchesWithoutPreds(S, w);
1064 		 w = S.dom().getPreviousSibling(w));
1065 	}
1066     }; break;
1067 
1068     case AXIS_DESCENDANT:
1069     case AXIS_DESC_OR_SELF:
1070     {
1071 	if (nhNull(v))
1072 	{
1073 	    if (ax == AXIS_DESC_OR_SELF && matchesWithoutPreds(S, baseV))
1074 	    {
1075 		w = baseV;
1076 		break;
1077 	    }
1078 	    else
1079 		v = baseV;
1080 	}
1081 
1082 	// find next descendant
1083 	do
1084 	{
1085 	    if ((S.dom().getNodeType(v) == ELEMENT_NODE ||
1086 		 (S.dom().getNodeType(v) == DOCUMENT_NODE)) &&
1087 		S.dom().getChildCount(v))
1088 	      v = S.dom().getFirstChild(v);
1089 	    else
1090 	    {
1091 		while (v != baseV)
1092 		{
1093 		    SXP_Node v0 = v;
1094 		    v = S.dom().getNextSibling(v);
1095 		    if (!nhNull(v))
1096 			break;
1097 		    else
1098 			v = S.dom().getParent(v0);
1099 		}
1100 	    };
1101 	    if (v != baseV && matchesWithoutPreds(S, v))
1102 	    {
1103 		w = v;
1104 		break;
1105 	    };
1106 	}
1107 	while(v != baseV);
1108     }; break;
1109     case AXIS_FOLLOWING:
1110     {
1111       do {
1112 	if (!nhNull(v) && S.dom().getChildCount(v))
1113 	  w = S.dom().getChildNo(v,0);
1114 	else
1115 	  {
1116 	    if (nhNull(v))
1117 	      v = baseV;
1118 	    while (!nhNull(v) && nhNull(S.dom().getNextSibling(v)))
1119 	      v = S.dom().getParent(v);
1120 	    if (!nhNull(v))
1121 	      w = S.dom().getNextSibling(v);
1122 	    else
1123 	      w = NULL;
1124 	  }
1125 	v = w;
1126       } while (!nhNull(w) && !matchesWithoutPreds(S, w));
1127     }; break;
1128     case AXIS_PRECEDING:
1129     {
1130       do {
1131 	v = !nhNull(v) ? v : baseV;
1132 	w = S.dom().getPreviousSibling(v);
1133 	if (!nhNull(w)) {
1134 	  int childCount;
1135 	  while (0 != (childCount = S.dom().getChildCount(w)))
1136 	    w = S.dom().getChildNo(w,childCount - 1);
1137 	} else {
1138 	  w = S.dom().getParent(v);
1139 	  //eliminate ancestors of baseV
1140 	  for (v = S.dom().getParent(baseV);
1141 	       !nhNull(v) && v != w;
1142 	       v = S.dom().getParent(v));
1143 	  //we're in the ancestor line
1144 	  if (!nhNull(v)) {
1145 	    while (!nhNull(v) && !(S.dom().getPreviousSibling(v)))
1146 	      v = S.dom().getParent(v);
1147 	    if (!nhNull(v))
1148 	      w = S.dom().getPreviousSibling(v);
1149 	    else
1150 	      w = NULL;
1151 	  }
1152 	}
1153 	v = w;
1154       } while (!nhNull(w) && !matchesWithoutPreds(S, w));
1155     }; break;
1156     default:
1157         sabassert(0);
1158     };
1159     v = w;
1160     return OK;
1161 };
1162 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)1163 void LocStep::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
1164 {
1165     ownerV.report(S, type, code, arg1, arg2);
1166 }
1167 
1168 
1169 
1170 /**********************************************************
1171 N u m b e r
1172 **********************************************************/
1173 
Number()1174 Number::Number()
1175 {
1176     *this = 0.0;
1177 }
1178 
Number(double y)1179 Number::Number(double y)
1180 {
1181     *this = y;
1182 }
1183 
1184 Number&
operator =(double y)1185 Number::operator= (double y)
1186 {
1187     x = y;
1188     return *this;
1189 };
1190 
1191 Number&
operator =(const Str & s)1192 Number::operator= (const Str &s)
1193 {
1194     char *endptr, *startptr = s;
1195     skipWhite(startptr);
1196     if (*startptr)
1197     {
1198         x = strtod(startptr, &endptr);
1199         if (endptr) {
1200 	  skipWhite(endptr);
1201 	  if (*endptr)
1202             setNaN();
1203 	}
1204     }
1205     else
1206         setNaN();
1207     return *this;
1208 };
1209 
operator double() const1210 Number::operator double() const
1211 {
1212     return x;
1213 }
1214 
operator ==(double y)1215 Bool Number::operator== (double y)
1216 {
1217     if (isNaN() || isnan__(y))
1218         return FALSE;
1219     if (isInf() || isinf__(y))
1220         return isInf() && isinf__(y) && !((x > 0) ^ (y > 0));
1221     double d = x - y;
1222     return (Bool)((d < EPS) && (d > -EPS));
1223 }
1224 
operator ==(Number & y)1225 Bool Number::operator== (Number& y)
1226 {
1227     if (isNaN()) return FALSE;
1228     return (Bool)(operator== ((double) y));
1229 }
1230 
1231 
operator <(double y)1232 Bool Number::operator< (double y)
1233 {
1234     return (Bool)(x < y);
1235 }
1236 
operator <(Number & y)1237 Bool Number::operator< (Number& y)
1238 {
1239     return (Bool)(x < (double) y);
1240 }
1241 
operator >(double y)1242 Bool Number::operator> (double y)
1243 {
1244     return (Bool)(x > y);
1245 }
1246 
operator >(Number & y)1247 Bool Number::operator> (Number& y)
1248 {
1249     return (Bool)(x > (double) y);
1250 }
1251 
isNaN()1252 Bool Number::isNaN()
1253 {
1254     return isnan__(x);
1255 }
1256 
isInf()1257 Bool Number::isInf()
1258 {
1259     return isinf__(x);
1260 };
1261 
setNaN()1262 void Number::setNaN()
1263 {
1264     // divide by zero using a variable, to fool too clever compilers
1265     // 'volatile' suggested by Dirk Siebnich
1266     volatile int zero = 0;
1267     x = 0.0 / zero;
1268 }
1269 
round()1270 int Number::round()
1271 {
1272     if (isNaN() || isInf())
1273         return 0;
1274     else return (int)(floor(x + 0.5)); // FIXME: ignoring the 'negative zero'
1275 }
1276 
1277 
1278 //________________________________________________________________
1279 
1280 /*****************************************************************
1281 |                                                                |
1282     JS - External
1283 |                                                                |
1284 *****************************************************************/
1285 
1286 #ifdef ENABLE_JS
External(void * prv,void * val)1287 External::External(void *prv, void *val)
1288 {
1289   priv = new JSExternalPrivate(prv, val);
1290 }
1291 
External(External & other)1292 External::External(External& other)
1293   : priv(NULL)
1294 {
1295   assign(other);
1296 }
1297 
1298 
~External()1299 External::~External()
1300 {
1301   decref();
1302 }
1303 
getValue()1304 void* External::getValue()
1305 {
1306   return priv->value;
1307 };
1308 
assign(const External & other)1309 void External::assign(const External& other)
1310 {
1311   if (priv) decref();
1312   priv = other.priv; priv->refcnt++;
1313 }
1314 
decref()1315 void External::decref()
1316 {
1317   if (priv)
1318     {
1319       priv->refcnt--;
1320       if (!priv->refcnt)
1321 	{
1322 	  delete priv;
1323 	  priv = NULL;
1324 	}
1325     }
1326 }
1327 #endif
1328 
1329 /*****************************************************************
1330 |                                                                |
1331     E x p r e s s i o n
1332 |                                                                |
1333 *****************************************************************/
1334 
Expression(Element & owner_,ExFunctor _functor)1335 Expression::Expression(Element &owner_,
1336                        ExFunctor _functor   /* = EXF_NONE   */
1337                        )
1338 : args(1), owner(owner_)
1339 {
1340     functor = _functor;
1341     switch(functor)
1342     {
1343     case EXF_LOCSTEP:
1344         {
1345             step = new LocStep(owner_);
1346             type = EX_NODESET;
1347         }; break;
1348     case EXF_LOCPATH:
1349         {
1350             type = EX_NODESET;
1351         }; break;
1352     case EXF_STRINGSEQ:
1353         type = EX_STRING;
1354         break;
1355     default:
1356         {
1357             type = EX_UNKNOWN;
1358         }; break;
1359     };
1360     hasPath = FALSE;
1361     isPattern = FALSE;
1362     pTree = NULL;
1363     // the following sets patomnodeset, note that e.g. patomnumber
1364     // is with it in a union
1365     patomnodeset = NULL;
1366     usesLast = FALSE;
1367     positional = FALSE;
1368     optimizePositionFrom = optimizePositionTo = 0; // see header
1369 }
1370 
setLS(ExAxis _axis,ExNodeType _ntype)1371 void Expression::setLS(ExAxis _axis, ExNodeType _ntype)
1372 {
1373     sabassert(functor == EXF_LOCPATH);
1374     Expression *ls = new Expression(getOwnerElement(), EXF_LOCSTEP); // GP: OK
1375     args.append(ls);
1376     ls -> step -> set(_axis, _ntype);
1377 }
1378 
1379 //
1380 //  Expression destructor
1381 //
~Expression()1382 Expression::~Expression()
1383 {
1384     clearContent();
1385 }
1386 
1387 #define deleteZ( PTR )    { cdelete( PTR ); }
1388 
1389 //
1390 //  clearContent()
1391 //  called when setting the expression to a new value
1392 //  to dispose of any existing contents.
1393 //
clearContent()1394 void Expression::clearContent()
1395 {
1396     args.freeall(FALSE);
1397     switch(functor)
1398     {
1399     case EXF_ATOM:
1400         {
1401             switch(type)
1402             {
1403             case EX_NODESET:
1404                 deleteZ ( patomnodeset );
1405                 break;
1406             case EX_STRING:
1407                 deleteZ ( patomstring );
1408                 break;
1409             case EX_NUMBER:
1410                 deleteZ ( patomnumber );
1411                 break;
1412 #ifdef ENABLE_JS
1413 	    case EX_EXTERNAL:
1414 	        deleteZ( patomexternal);
1415 	        break;
1416 #endif
1417             };
1418         }; break;
1419     case EXF_LOCSTEP:
1420         deleteZ ( step );
1421         break;
1422     case EXF_VAR:
1423     case EXF_OTHER_FUNC:
1424         deleteZ ( pName );
1425         break;
1426     }
1427     cdelete( pTree );
1428 };
1429 
1430 
1431 
1432 /*================================================================
1433 speak
1434     writes the expression to string 'strg'. Formatting is specified
1435     by 'mode'.
1436 ================================================================*/
1437 
speak(Sit S,DStr & strg,SpeakMode mode)1438 eFlag Expression::speak(Sit S, DStr &strg, SpeakMode mode)
1439 {
1440     int i, argsNumber = args.number();
1441     switch(functor)
1442     {
1443     case EXF_ATOM:
1444         {
1445 	        Str temp;
1446 		    E( tostring(S, temp) );
1447             strg += temp;
1448         }; break;
1449     case EXF_LOCSTEP:
1450         {
1451             step -> speak(S, strg, mode);
1452         }; break;
1453     case EXF_LOCPATH:
1454         {
1455             for(i = 0; i < argsNumber; i++)
1456             {
1457                 args[i] -> speak(S, strg, mode);
1458                 if (i < argsNumber-1)
1459                     strg += "/";
1460                 else if ((argsNumber == 1) &&
1461                     (args[0] -> step -> ax == AXIS_ROOT))
1462                     strg += "/";
1463             }
1464         }; break;
1465     default:
1466         {
1467             strg += (DStr("\nfunctor ") + (int) functor + "\n--------ARGS:\n");
1468             for (i = 0; i < argsNumber; i++)
1469             {
1470                 strg += DStr("(") + (i+1) + ")   ";
1471                 args[i] -> speak(S, strg, mode);
1472                 strg += "\n";
1473             };
1474             strg += "--------ARGS end\n";
1475         }
1476     };
1477     return OK;
1478 }
1479 
1480 /*================================================================
1481 matches
1482     returns TRUE iff the current vertex of c satisfies the
1483     Expression's condition.
1484     PROBLEM:
1485     perhaps this should also return an error in case the expression is
1486     not of type nodeset?
1487 ================================================================*/
1488 
matchesPattern(Sit S,Context * c,Bool & result)1489 eFlag Expression::matchesPattern(Sit S, Context *c, Bool &result)
1490 {
1491     sabassert(type == EX_NODESET);
1492     if (functor == EXF_LOCPATH)
1493     {
1494         E(matchesSinglePath(S, c -> current(), args.number() - 1, result));
1495         return OK;
1496     }
1497     if (functor == EXFO_UNION)
1498     {
1499         int j, argsNumber = args.number();
1500         for (j = 0; j < argsNumber; j++)
1501         {
1502             E( args[j] -> matchesPattern(S, c, result) );
1503             if (result)
1504                 RetOK( result, TRUE );
1505         };
1506     }
1507     RetOK(result, FALSE);
1508 }
1509 
trueFor(Sit S,Context * c,Bool & result)1510 eFlag Expression::trueFor(Sit S, Context *c, Bool& result)
1511 {
1512     Expression ex(getOwnerElement());
1513     E( eval(S, ex, c) );
1514     switch(ex.type)
1515     {
1516     case EX_NUMBER:
1517         result = (Bool) (ex.tonumber(S) == (double) (c -> getPosition() + 1));
1518         break;
1519     default:
1520         result = ex.tobool();
1521     }
1522     return OK;
1523 }
1524 
1525 
tobool()1526 Bool Expression::tobool()
1527 {
1528     sabassert(functor == EXF_ATOM);
1529     switch(type)
1530     {
1531     case EX_NUMBER:
1532         return (Bool) !(*patomnumber == 0.0 || patomnumber -> isNaN());
1533         break;
1534     case EX_STRING:
1535         return (Bool) !(patomstring -> isEmpty());
1536         break;
1537     case EX_BOOLEAN:
1538         return atombool;
1539         break;
1540     case EX_NODESET:
1541         return (Bool) !!(patomnodeset -> getSize());
1542         break;
1543     default: sabassert(0);
1544     };
1545     return FALSE;   //just to return something
1546 }
1547 
tostring(Sit S,Str & strg)1548 eFlag Expression::tostring(Sit S, Str& strg)
1549 {
1550     sabassert(functor == EXF_ATOM);
1551     switch(type)
1552     {
1553     case EX_NUMBER:
1554         if (patomnumber -> isNaN())
1555             strg = (char*)"NaN";
1556         else
1557         {
1558             if (!patomnumber -> isInf())
1559                 strg = (double)(*patomnumber);
1560             else if (*patomnumber > 0.0)
1561                 strg = (char*)"+Infinity";
1562             else strg = (char*)"-Infinity";
1563         }
1564         break;
1565     case EX_STRING:
1566         strg = *patomstring;
1567         break;
1568     case EX_BOOLEAN:
1569         strg = (atombool ? (char *)"true" : (char *)"false");
1570         break;
1571     case EX_NODESET:
1572         if (!patomnodeset -> getSize())
1573             strg = (char*)"";
1574         else
1575         {
1576             DStr temp;
1577             S.dom().constructStringValue(patomnodeset -> current(), temp);
1578             strg = temp;
1579         }
1580         break;
1581     case EX_EXTERNAL:
1582       {
1583 	strg = (char*)"[External Object]";
1584       }; break;
1585     default: sabassert(0);
1586     };
1587     return OK;
1588 }
1589 
tostringRef() const1590 const Str& Expression::tostringRef() const
1591 {
1592     sabassert((functor == EXF_ATOM) && (type == EX_STRING));
1593     return (*NZ(patomstring));
1594 }
1595 
tonumber(Sit S)1596 Number Expression::tonumber(Sit S)
1597 {
1598     sabassert(functor == EXF_ATOM);
1599     Number n;
1600     switch(type)
1601     {
1602     case EX_NUMBER:
1603         n = *patomnumber;
1604         break;
1605     case EX_STRING:
1606         n = *patomstring;
1607         break;
1608     case EX_BOOLEAN:
1609         n = (atombool ? 1.0 : 0.0);
1610         break;
1611     case EX_NODESET:
1612       {
1613             // to avoid the following, tostring() must return const Str&:
1614             Str strg;
1615 	        tostring(S, strg);
1616             n = strg;
1617 	    // but note that changing it to n = tostringRef() failed
1618       };
1619         break;
1620     default: sabassert(0);
1621     };
1622     return n;
1623 }
1624 
1625 #ifdef ENABLE_JS
toexternal(Sit S)1626 External& Expression::toexternal(Sit S)
1627 {
1628   sabassert((functor == EXF_ATOM) && (type == EX_EXTERNAL));
1629   return *patomexternal;
1630   /*
1631     sabassert(functor == EXF_ATOM);
1632     //External e;
1633     switch(type)
1634     {
1635     case EX_EXTERNAL:
1636       {
1637 	e.assign(*patomexternal);
1638 	//e.setValue(patomexternal -> getValue());
1639       }; break;
1640     default: sabassert(0);
1641     };
1642     //return e;
1643     return NULL;
1644   */
1645 }
1646 #endif
1647 
tonodeset()1648 Context& Expression::tonodeset()
1649 {
1650     sabassert((functor == EXF_ATOM) && (type == EX_NODESET));
1651     return *(patomnodeset -> copy());
1652 }
1653 
tonodesetRef()1654 const Context& Expression::tonodesetRef()
1655 {
1656     sabassert((functor == EXF_ATOM) && (type == EX_NODESET));
1657     return *patomnodeset;
1658 }
1659 
patternOK(Sit S)1660 eFlag Expression::patternOK(Sit S)
1661 {
1662     int i,
1663         argsNumber = args.number();
1664     // sabassert(functor == EXFO_UNION || functor == EXF_LOCPATH);
1665 
1666     if ( containsFunctor(EXFF_CURRENT) )
1667       Err(S, E_BAD_PATTERN);
1668 
1669     switch(functor)
1670     {
1671     case EXF_LOCPATH:
1672         {
1673             for (i = 0; i < argsNumber; i++)
1674             {
1675                 LocStep *ls = args[i] -> step;
1676                 switch (ls -> ax)
1677                 {
1678                 case AXIS_CHILD:
1679                 case AXIS_ATTRIBUTE:
1680                 case AXIS_ROOT:
1681                     break;
1682                 case AXIS_DESC_OR_SELF:
1683                     if (ls -> ntype != EXNODE_NODE)
1684                         Err(S, E_BAD_PATTERN);
1685                     break;
1686                 default:
1687                     Err(S, E_BAD_AXIS_IN_PATTERN);
1688                 }
1689             }
1690         }; break;
1691     case EXFO_UNION:
1692         {
1693             for (i=0; i < argsNumber; i++)
1694                 E(args[i] -> patternOK(S));
1695         }; break;
1696     default:
1697         Err(S, E_BAD_PATTERN);
1698         // sabassert(!"patternOK()");
1699     };
1700     return OK;
1701 }
1702 
parse(Sit S,const DStr & string,Bool _isPattern,Bool defaultToo)1703 eFlag Expression::parse(Sit S, const DStr &string,
1704                         Bool _isPattern /* = FALSE  */,
1705 			Bool defaultToo /* = FALSE  */)
1706 {
1707     isPattern = _isPattern;
1708     Tokenizer t(*this);
1709     E( t.tokenize(S, string) );
1710     E( parse(S, t, 0, t.items.number() - 1, defaultToo) );
1711     if (_isPattern)
1712         E( patternOK(S) );
1713     return OK;
1714 }
1715 
1716 /*================================================================
1717 Bool isOp()
1718 returns True if the given token is an operator, in which case
1719 'precedence' is set to its precedence
1720 ================================================================*/
1721 
isOp(ExToken token,int & precedence)1722 Bool Expression::isOp(ExToken token, int &precedence)
1723 {
1724     Bool is = TRUE;
1725     switch(token)
1726     {
1727     case TOK_OR:
1728         precedence = 0;
1729         break;
1730     case TOK_AND:
1731         precedence = 1;
1732         break;
1733     case TOK_EQ:
1734     case TOK_NEQ:
1735         precedence = 2;
1736         break;
1737     case TOK_LT:
1738     case TOK_GT:
1739     case TOK_LE:
1740     case TOK_GE:
1741         precedence = 3;
1742         break;
1743     case TOK_PLUS:
1744     case TOK_MINUS:
1745         precedence = 4;
1746         break;
1747     case TOK_MULT:
1748     case TOK_DIV:
1749     case TOK_MOD:
1750         precedence = 5;
1751         break;
1752     case TOK_MINUS1:
1753         precedence = 6;
1754         break;
1755     case TOK_VERT:
1756         precedence = 7;
1757         break;
1758     default:
1759         {
1760             is = FALSE;
1761             precedence = -1;
1762         };
1763     };
1764     return is;
1765 }
1766 
1767 /*================================================================
1768 void getFunctionInfo()
1769 returns function code and type for the function with given name
1770     if no such builtin function, returns EXFF_NONE
1771 ================================================================*/
1772 
getFunctionInfo(const Str & s,ExFunctor & code,ExType & type)1773 void getFunctionInfo(const Str &s, ExFunctor &code, ExType &type)
1774 {
1775     char *p = (char *) s;
1776     int i;
1777 
1778     for (i = 0; funcInfoTable[i].name; i++)
1779     {
1780         if (!strcmp(funcInfoTable[i].name,p))
1781             break;
1782     };
1783     code = funcInfoTable[i].func;
1784     type = funcInfoTable[i].type;
1785 }
1786 
1787 /*================================================================
1788 void getExternalFunctionInfo()
1789 returns function code and type for the function with given name
1790     if no such builtin function, returns EXFF_NONE
1791 ================================================================*/
1792 
getExternalFunctionInfo(const Str & u,const Str & n,ExFunctor & code,ExType & type)1793 void getExternalFunctionInfo(const Str &u, const Str &n, ExFunctor &code, ExType &type)
1794 {
1795   char *p = (char *) n;
1796   char *u2 = (char *) u;
1797   int i;
1798   for (i = 0; extFuncInfoTable[i].name; i++)
1799     {
1800       if (!strcmp(extFuncInfoTable[i].name,p) &&
1801 	  ((!strcmp(theSabExtNamespace,u2)) || !strcmp(theEXSLTDynNamespace,u2)) )
1802 	break;
1803     };
1804   code = extFuncInfoTable[i].func;
1805   type = extFuncInfoTable[i].type;
1806 }
1807 
1808 struct OpItem
1809 {
1810     ExFunctor fu;
1811     ExType ty;
1812     int arity;
1813 }
1814 opTable[] =
1815 {
1816     {EXFO_OR, EX_BOOLEAN, 3},
1817     {EXFO_AND, EX_BOOLEAN, 3},
1818     {EXFO_EQ, EX_BOOLEAN, 2},
1819     {EXFO_NEQ, EX_BOOLEAN, 2},
1820     {EXFO_LT, EX_BOOLEAN, 2},
1821     {EXFO_GT, EX_BOOLEAN, 2},
1822     {EXFO_LE, EX_BOOLEAN, 2},
1823     {EXFO_GE, EX_BOOLEAN, 2},
1824     {EXFO_PLUS, EX_NUMBER, 2},
1825     {EXFO_MINUS2, EX_NUMBER, 2},
1826     {EXFO_MULT, EX_NUMBER, 2},
1827     {EXFO_MOD, EX_NUMBER, 2},
1828     {EXFO_DIV, EX_NUMBER, 2},
1829     {EXFO_MINUS1, EX_NUMBER, 1},
1830     {EXFO_UNION, EX_NODESET, 3}
1831 };
1832 
1833 /*================================================================
1834 eFlag parseLP()
1835 ================================================================*/
1836 
parseLP(Sit S,Tokenizer & tokens,int & pos,Bool dropRoot,Bool defaultToo)1837 eFlag Expression::parseLP(Sit S, Tokenizer& tokens, int &pos,
1838                      Bool dropRoot, Bool defaultToo /*=FALSE*/)
1839 {
1840     sabassert(functor == EXF_LOCPATH);
1841     ExToken tok;
1842     BOOL getaway = FALSE;
1843     Expression *ls; // GP: OK (immediately appended)
1844     int& i = pos;
1845     Bool
1846       slashPending = FALSE,
1847       nameWas = FALSE,
1848       nameRecent = FALSE;
1849 
1850     tok = tokens.items[i] -> tok;
1851     if (tok == TOK_END)
1852         Err(S, ET_EMPTY_PATT);
1853     if ((tok == TOK_SLASH) || (tok== TOK_DSLASH))
1854     {
1855         if (!dropRoot)
1856         {
1857             args.append(ls = new Expression(getOwnerElement(),EXF_LOCSTEP));
1858             ls -> step -> set(AXIS_ROOT,EXNODE_NODE);
1859         }
1860         if (tok == TOK_SLASH)
1861             i++;
1862     }
1863 
1864     while (!getaway)
1865     {
1866         tok = tokens.items[i] -> tok;
1867         switch(tok)
1868         {
1869         case TOK_NAME:
1870         case TOK_NTNAME:
1871         case TOK_AXISNAME:
1872         case TOK_ATSIGN:
1873         case TOK_PERIOD:
1874         case TOK_DPERIOD:
1875             {
1876 	      if (nameRecent)
1877 		Err(S, ET_EXPR_SYNTAX);
1878 	      args.append(ls = new Expression(getOwnerElement(),EXF_LOCSTEP));
1879 	      E( ls -> step -> parse(S, tokens, i, defaultToo) );
1880 	      slashPending = FALSE;
1881 	      nameWas = TRUE;
1882 	      //nameRecent = (tok == TOK_NAME || tok == TOK_NTNAME)
1883 	      nameRecent = TRUE;
1884             };
1885             break;
1886         case TOK_DSLASH:
1887             {
1888                 args.append(ls = new Expression(getOwnerElement(),EXF_LOCSTEP));
1889                 ls -> step -> set(AXIS_DESC_OR_SELF, EXNODE_NODE);
1890             };
1891             // no break here?
1892         case TOK_SLASH:
1893             {
1894                 if (slashPending)
1895                     Err(S, ET_EXPR_SYNTAX);
1896                 slashPending = TRUE;
1897                 i++;
1898                 if (tokens.items[i] -> tok == TOK_END)
1899                     Err(S, ET_EMPTY_PATT);
1900 		nameRecent = FALSE;
1901             };
1902             break;
1903         case TOK_VERT:
1904         case TOK_END:
1905         default: getaway = TRUE;
1906         };
1907     };
1908     if ((slashPending && nameWas) || !args.number())
1909         Err(S, ET_EMPTY_PATT);
1910 
1911     return OK;
1912 }
1913 
1914 
1915 /*================================================================
1916 eFlag parseBasic()
1917     parses the basic expression in tokenizer 't' between positions
1918     'from' and 'to' inclusive. The basic expression is guaranteed
1919     to contain no operators (except for / and //) nor outer
1920     parentheses.
1921 ================================================================*/
1922 
parseBasic(Sit S,Tokenizer & t,int from,int to,Bool defaultToo)1923 eFlag Expression::parseBasic(Sit S, Tokenizer &t, int from, int to,
1924     Bool defaultToo /* = FALSE */)
1925 {
1926     GP( Expression ) e, lp;
1927     // find the start of the filtering predicates
1928     int fstart, fright, fleft;
1929     ExToken tok;
1930 
1931     switch(t.items[from] -> tok)
1932     {
1933     case TOK_VAR:
1934     case TOK_LITERAL:
1935     case TOK_NUMBER:
1936         fstart = from + 1;
1937         break;
1938     case TOK_FNAME:
1939         {
1940             t.getDelim(S, fstart = from + 1);
1941             fstart++;
1942         };
1943         break;
1944     case TOK_LPAREN:
1945         {
1946             t.getDelim(S, fstart = from);
1947             fstart++;
1948         };
1949         break;
1950     default:
1951         fstart = -1;
1952     };
1953 
1954 //#pragma Msg("adding '+1':")
1955     if ((fstart != -1) && (fstart <= to))
1956     {
1957         switch(t.items[fstart] -> tok)
1958         {
1959         case TOK_LBRACKET:
1960         case TOK_SLASH:
1961         case TOK_DSLASH:
1962             {
1963                 // parse the filtered expression into args[0]
1964                 e = new Expression(getOwnerElement()); // is a GP
1965                 E( (*e).parse(S, t, from, fstart - 1));
1966                 args.append(e.keep());
1967                 //
1968                 functor = EXF_FILTER;
1969                 type = EX_NODESET;
1970                 fleft = fstart;
1971                 while (t.items[fleft] -> tok == TOK_LBRACKET)
1972                 {
1973                     t.getDelim(S, fright = fleft);
1974                     if ((t.items[fright] -> tok == TOK_END) || (fright > to))
1975                         Err(S, ET_RBRACKET_EXP);
1976                     if (fleft + 1 == fright)
1977                         Err(S, ET_EXPR_SYNTAX);
1978                     E( (e = new Expression(getOwnerElement())) -> parse(S, t,
1979                         fleft + 1, fright - 1, defaultToo) );
1980                     args.append(e.keep());
1981                     fleft = fright + 1;
1982                 };
1983                 if (((tok = t.items[fleft] -> tok) == TOK_SLASH)
1984                     || (tok == TOK_DSLASH))
1985                 {
1986                     E( (lp = new Expression(getOwnerElement(), EXF_LOCPATH)) -> parseLP(
1987                         S, t, fleft, TRUE, defaultToo) );
1988                     hasPath = TRUE;
1989                     args.append(lp.keep());
1990                 };
1991                 if (fleft != to + 1)
1992                     Err(S, ET_EXPR_SYNTAX);
1993                 return OK;
1994             };
1995             break;
1996         }
1997     };
1998 
1999     DStr temp;
2000     tok = t.items[from] -> tok;
2001     t.items[from] -> speak(temp,SM_OFFICIAL);
2002     if ((tok == TOK_VAR) || (tok == TOK_LITERAL)
2003         || (tok == TOK_NUMBER))
2004     {
2005         switch(t.items[from] -> tok)
2006         {
2007         case TOK_VAR:
2008             {
2009                 functor = EXF_VAR;
2010                 type = EX_UNKNOWN;
2011                 // GP: OK (member)
2012                 E( getOwnerElement().setLogical(S,
2013 		            *(pName = new QName), temp, FALSE) );
2014             }; break;
2015         case TOK_LITERAL:
2016             {
2017                 functor = EXF_ATOM;
2018                 type = EX_STRING;
2019                 patomstring = new Str(temp);
2020             }; break;
2021         case TOK_NUMBER:
2022             {
2023                 functor = EXF_ATOM;
2024                 type = EX_NUMBER;
2025                 *(patomnumber = new Number) = temp;
2026             }; break;
2027         };
2028         if (to != from)
2029             Err(S, ET_EXPR_SYNTAX);
2030     }
2031     else
2032     {
2033         if (tok == TOK_FNAME)
2034         {
2035             ExFunctor funcNo;
2036             ExType funcType;
2037             getFunctionInfo(temp,funcNo,funcType);
2038             if (funcNo != EXFF_NONE)
2039             {
2040                 functor = funcNo;
2041                 type = funcType;
2042             }
2043             else
2044 	    {
2045 	      QName funcName;
2046 	      E( getOwnerElement().setLogical(S, funcName, temp, FALSE) );
2047 	      Str uri = getOwnerTree().expand(funcName.getUri());
2048 	      Str name = getOwnerTree().expand(funcName.getLocal());
2049 	      getExternalFunctionInfo(uri,name,funcNo,funcType);
2050 	      if (funcNo != EXFF_NONE) {
2051                 functor = funcNo;
2052                 type = funcType;
2053 	      }
2054 	      else {
2055 
2056                 functor = EXF_OTHER_FUNC;
2057                 E( getOwnerElement().setLogical(S,
2058 		            *(pName = new QName), temp, FALSE) );
2059                 type = EX_UNKNOWN;
2060 	      };
2061 	    }
2062             int i = from+1,
2063                 j;
2064             sabassert(t.items[i] -> tok == TOK_LPAREN);
2065             i++;
2066             // original loop test:
2067             // while (t.items[j = t.findTop(TOK_COMMA,i)] -> tok != TOK_END)
2068             while (((j = t.findTop(TOK_COMMA,i)) <= to) && (t.items[j] -> tok != TOK_END))
2069             {
2070                 switch(t.items[j-1] -> tok)
2071                 {
2072                 case TOK_COMMA:
2073                 case TOK_LPAREN:
2074                     Err(S, ET_EXPR_SYNTAX);
2075                 };
2076                 args.append(e = new Expression(getOwnerElement()));
2077                 e.keep();
2078                 E( (*e).parse(S, t,i,j-1, defaultToo) );
2079                 i = j+1;
2080             };
2081 
2082             if ((t.items[j = t.findTop(TOK_RPAREN,i)]->tok == TOK_END) ||
2083 		(j > to))
2084 	      {
2085                 Err(S, ET_RPAREN_EXP);
2086 	      }
2087             if(t.items[j-1] -> tok == TOK_COMMA)
2088                 Err(S, ET_EXPR_SYNTAX);
2089             if (j > i)  // if any args
2090             {
2091                 args.append(e = new Expression(getOwnerElement()));
2092                 e.keep();
2093                 E( (*e).parse(S, t,i,j-1, defaultToo) );
2094             }
2095             if (to != j)
2096                 Err(S, ET_EXPR_SYNTAX);
2097         } // end "tok == TOK_FNAME"
2098         else
2099         {   // it must be a LocPath
2100             type = EX_NODESET;
2101             functor = EXF_LOCPATH;
2102             int howfar = from;
2103             E( parseLP(S, t, howfar, FALSE, defaultToo) );
2104             if (howfar != to + 1)
2105                 Err(S, ET_EXPR_SYNTAX);
2106         }
2107     }
2108     return OK;
2109 }
2110 
2111 /*================================================================
2112 eFlag parse()
2113     translates the given token list into an expression (a tree of
2114     'Expression' objects plus some leaves).
2115 INPUT
2116     t           a tokenizer whose tokenize() method has been called
2117     from,to     first and last position in the token list the parsing
2118                 applies to (i.e. a complex expression will parse the
2119                 subexpressions with the same tokenizer but different
2120                 limits)
2121 ================================================================*/
2122 
parse(Sit S,Tokenizer & t,int from,int to,Bool defaultToo)2123 eFlag Expression::parse(Sit S, Tokenizer& t, int from, int to,
2124     Bool defaultToo /* = FALSE */)
2125 // isOp, skipParens
2126 {
2127     int i;
2128     ExToken
2129         token,
2130         mintoken = TOK_NONE;
2131     int precedence,
2132         minprec = 999,
2133         minndx = -1,
2134         leftmost = 0,
2135         arity;
2136 
2137     if (from > to)
2138         Err(S, ET_EXPR_SYNTAX);
2139 
2140     t.stripParens(S, from,to);
2141     // search from right to left (left-associativity)
2142     for (i = to; i >= from; i--)
2143     {
2144         switch(token = t.items[i] -> tok)
2145         {
2146         case TOK_RPAREN:
2147         case TOK_RBRACKET:
2148             {
2149                 // reverse search:
2150                 E( t.getDelim(S, i,TRUE) ); // i is decremented at loop end
2151                 if (i == -1)
2152                     Err(S, ET_LPARCKET_EXP);
2153             };
2154             break;
2155         default:
2156             {
2157                 if (isOp(token, precedence) && (precedence < minprec))
2158                 {
2159                     minprec = precedence;
2160                     minndx = leftmost = i;
2161                     mintoken = token;
2162 //                    if (token == TOK_OR) break;
2163                 }
2164                 else
2165                     if (token == mintoken)
2166                         leftmost = i;
2167             };
2168         };
2169     };
2170 
2171     //minndx now points to the rightmost lowest-precedence operator
2172     // leftmost points at its leftmost occurence
2173 
2174     if (minndx == -1)
2175         E( parseBasic(S, t, from, to, defaultToo) )
2176     else
2177     {
2178         int tablendx = t.items[minndx] -> tok - TOKGROUP_OPERATORS;
2179         functor = opTable[tablendx].fu;
2180         type = opTable[tablendx].ty;
2181         arity = opTable[tablendx].arity;
2182         Expression *e = new Expression(getOwnerElement()); // GP: OK
2183 
2184         args.append(e);
2185         switch(arity)
2186         {
2187         case 1:
2188             {
2189             if (minndx != from)
2190                 Err(S, ET_EXPR_SYNTAX)
2191             else
2192                 E( e -> parse(S, t,from+1,to, defaultToo) );
2193             };
2194             break;
2195         case 2:
2196             {
2197                 E( e -> parse(S, t,from,minndx - 1, defaultToo) );
2198                 args.append(e = new Expression(getOwnerElement())); // GP: OK
2199                 E( e -> parse(S, t,minndx + 1, to, defaultToo) );
2200             };
2201             break;
2202         default:
2203             {
2204                 E( e -> parse(S, t,from,leftmost - 1, defaultToo) );
2205                 int another = leftmost,
2206                     lastone = leftmost;
2207                 // tom 24-10-00
2208                 // the following fails for "x and not(x and x)"
2209                 // t.getDelim(another);
2210                 // changing it to:
2211                 another = t.findTop(t.items[another]->tok, another+1);
2212                 while((another <= to) && (t.items[another]->tok != TOK_END))
2213                 {
2214                     args.append(e = new Expression(getOwnerElement())); // GP: OK
2215                     E( e -> parse(S, t, lastone + 1, another - 1, defaultToo));
2216                     lastone = another;
2217 
2218                     // tom 14-11-00
2219                     // t.getDelim(another);     failed too, for "x and x and (x and x)"
2220                     another = t.findTop(t.items[another]->tok, another+1);
2221                 };
2222                 args.append(e = new Expression(getOwnerElement())); // GP: OK
2223                 E( e -> parse(S, t,lastone + 1, to, defaultToo) );
2224             };
2225         };
2226     }
2227     return OK;
2228 }
2229 
2230 
setAtom(Context * c)2231 void Expression::setAtom(Context *c)
2232 {
2233     clearContent();
2234     functor = EXF_ATOM;
2235     type = EX_NODESET;
2236     patomnodeset = c;
2237 }
2238 
setAtom(const Number & n)2239 void Expression::setAtom(const Number& n)
2240 {
2241     clearContent();
2242     functor = EXF_ATOM;
2243     type = EX_NUMBER;
2244     *(patomnumber = new Number) = (Number&) n;
2245 }
2246 
setAtom(Bool b)2247 void Expression::setAtom(Bool b)
2248 {
2249     clearContent();
2250     functor = EXF_ATOM;
2251     type = EX_BOOLEAN;
2252     atombool = b;
2253 }
2254 
setAtom(const DStr & s)2255 void Expression::setAtom(const DStr &s)
2256 {
2257     clearContent();
2258     functor = EXF_ATOM;
2259     type = EX_STRING;
2260     patomstring = new Str(s);
2261 }
2262 
2263 #ifdef ENABLE_JS
setAtom(const External & ext)2264 void Expression::setAtom(const External &ext)
2265 {
2266     clearContent();
2267     functor = EXF_ATOM;
2268     type = EX_EXTERNAL;
2269     patomexternal = new External();
2270     patomexternal -> assign(ext);
2271 }
2272 #endif
2273 
2274 /*================================================================
2275 setFragment
2276     sets the expression to point to a 'result tree fragment' - a newly
2277     constructed tree - whose address it returns
2278 ================================================================*/
2279 
setFragment()2280 Tree* Expression::setFragment()
2281 {
2282     functor = EXF_FRAGMENT;
2283     type = EX_NODESET;
2284     return pTree = new Tree("RTF", FALSE); // not an XSL tree
2285 }
2286 
2287 #define funcIsOperator(f) ((EXFO_OR <= f) && (f <= EXFO_Z))
2288 #define funcIsBuiltin(f) ((EXF_FUNCTION <= f) && (f <= EXFF_NONE))
2289 
eval(Sit S,Expression & retxpr,Context * c,Bool resolvingGlobals)2290 eFlag Expression::eval(Sit S, Expression &retxpr, Context *c, Bool resolvingGlobals /* = FALSE */)
2291 {
2292     sabassert(!isPattern && "evaluating pattern!");
2293     GP( Context ) newc;
2294 
2295     switch(functor)
2296     {
2297     case EXF_ATOM:
2298     {
2299 	//cannot use retxpr = *this !!!
2300 	switch(type)
2301 	{
2302 	case EX_STRING:
2303 	    retxpr.setAtom(*patomstring);
2304 	    break;
2305 	case EX_NUMBER:
2306 	    retxpr.setAtom(*patomnumber);
2307 	    break;
2308 	case EX_NODESET:
2309 	    retxpr.setAtom(patomnodeset -> copy());
2310 	    break;
2311 	case EX_BOOLEAN:
2312 	    retxpr.setAtom(atombool);
2313 	    break;
2314 #ifdef ENABLE_JS
2315 	case EX_EXTERNAL:
2316 	    retxpr.setAtom(*patomexternal);
2317 	    break;
2318 #endif
2319 	default: sabassert(0);
2320 	}
2321     }; break;
2322     case EXF_VAR:
2323     {
2324 	Expression *ex = NZ(S.getProcessor()) -> getVarBinding(*pName);
2325 	if (!ex)
2326 	{
2327 	    // if we're resolving globals, this may mean a forward reference
2328 	    if (resolvingGlobals)
2329 	      {
2330 		E( S.getProcessor() -> resolveGlobal(S, c, *pName) );
2331 		ex = S.getProcessor() -> getVarBinding(*pName);
2332 	      }
2333 	    else
2334 	      {
2335 		Str fullName;
2336 		getOwnerTree().expandQStr(*pName, fullName);
2337 		Err1(S, E1_VAR_NOT_FOUND, fullName);
2338 	      }
2339 	};
2340     E( ex -> eval(S, retxpr, c) );
2341     }; break;
2342     case EXF_LOCPATH:
2343     case EXFO_UNION:
2344     {
2345 	sabassert(c && "context is null!");
2346 	newc.assign(c);
2347 	E( createContext(S, newc) );
2348 	newc.unkeep();
2349 	// assign newc directly without copying
2350 	retxpr.setAtom((*newc).copy());
2351 	newc.del();
2352     }; break;
2353     case EXF_OTHER_FUNC: // other function
2354         {
2355 	  Str ret;
2356 	  Str uri = getOwnerTree().expand(pName -> getUri());
2357 	  Str name = getOwnerTree().expand(pName -> getLocal());
2358 
2359 	  if (! S.getProcessor() -> supportsFunction(uri, name) )
2360 	    {
2361 	      Str fullName;
2362 	      getOwnerTree().expandQStr(*pName, fullName);
2363 	      Err1(S, ET_FUNC_NOT_SUPPORTED,fullName);
2364 	    }
2365 	  int i,
2366 	    argsNumber = args.number();
2367 	  // ExprList atoms(LIST_SIZE_1);
2368 	  GPD( ExprList ) atoms = new ExprList(LIST_SIZE_1);
2369 	  atoms.autodelete();
2370 	  GP( Expression ) ex;
2371 	  for (i = 0; i < argsNumber; i++)
2372 	    {
2373 	      ex = new Expression(getOwnerElement());
2374 	      E( args[i]->eval(S, *ex, c, resolvingGlobals) );
2375 	      (*atoms).append(ex.keep());
2376 	    };
2377 
2378 #ifdef ENABLE_JS
2379 	  E( S.getProcessor()->callJSFunction(S, c, uri, name, *atoms, retxpr) );
2380 #endif
2381         }; break;
2382     case EXF_FILTER:
2383     {
2384 	sabassert(c && "context is null!");
2385 	newc.assign(c);
2386 	E( createContext(S, newc, c -> getPosition()) );
2387 	newc.unkeep();
2388 	retxpr.setAtom((*newc).copy());
2389 	newc.del();
2390     }; break;
2391     case EXF_STRINGSEQ:
2392     {
2393 	DStr result;
2394 	Expression temp(getOwnerElement());
2395 	int i,
2396 	    argsNumber = args.number();
2397 	for (i = 0; i < argsNumber; i++)
2398 	{
2399 	    E( args[i] -> eval(S, temp, c, resolvingGlobals) );
2400 	    Str tempStr;
2401 	    E( temp.tostring(S, tempStr) );
2402 	    result += tempStr;
2403 	};
2404 	retxpr.setAtom(result);
2405     }; break;
2406     case EXF_FRAGMENT:
2407     {
2408         newc = new Context(NULL); //current nde not needed _cn_
2409 	(*newc).set(&(pTree -> getRoot()));
2410 	retxpr.setAtom((*newc).copy());
2411 	newc.del();
2412     }; break;
2413     default:
2414     {
2415 	int i,
2416 	    argsNumber = args.number();
2417 	// ExprList atoms(LIST_SIZE_1);
2418 	GPD( ExprList ) atoms = new ExprList(LIST_SIZE_1);
2419 	atoms.autodelete();
2420 	GP( Expression ) ex;
2421 	for (i = 0; i < argsNumber; i++)
2422 	{
2423 	    ex = new Expression(getOwnerElement());
2424 	    E( args[i]->eval(S, *ex, c, resolvingGlobals) );
2425 	    (*atoms).append(ex.keep());
2426 	};
2427 	if (funcIsOperator(functor))
2428 	  E( callOp(S, retxpr, *atoms) )           //an operator
2429 	    else
2430 	      if (funcIsBuiltin(functor))
2431 		E( callFunc(S, retxpr, *atoms, c) ) //a core XPath function
2432 		  else
2433 		    {
2434 		      Str fullName;
2435 		      getOwnerTree().expandQStr(*pName, fullName);
2436 		      Err1( S, ET_FUNC_NOT_SUPPORTED, fullName );
2437 		    }
2438 	// atoms autodeleted
2439     };
2440     };
2441     return OK;
2442 }
2443 
2444 
2445 
2446 template<class T>
hardCompare(ExFunctor op,T b1,T b2)2447 Bool hardCompare(ExFunctor op, T b1, T b2)
2448 {
2449         Str p,q;
2450     switch(op)
2451     {
2452     case EXFO_EQ: return (Bool) (b1 == b2); break;
2453     case EXFO_NEQ: return (Bool) !(b1 == b2); break;
2454     case EXFO_LT: return (Bool) (b1 < b2); break;
2455     case EXFO_GT: return (Bool) (b2 < b1); break;
2456     case EXFO_LE: return (Bool) ((b1 < b2) || (b1 == b2)); break;
2457     case EXFO_GE: return (Bool) ((b2 < b1) || (b1 == b2)); break;
2458     default: sabassert(0);
2459     }
2460     return FALSE; //just to return something
2461 }
2462 
_invertOp(ExFunctor op)2463 ExFunctor _invertOp(ExFunctor op)
2464 {
2465     switch(op)
2466     {
2467     case EXFO_EQ: return EXFO_EQ; break;
2468     case EXFO_NEQ: return EXFO_NEQ; break;
2469     case EXFO_LT: return EXFO_GT; break;
2470     case EXFO_GT: return EXFO_LT; break;
2471     case EXFO_LE: return EXFO_GE; break;
2472     case EXFO_GE: return EXFO_LE; break;
2473     default: sabassert(!"_invertOp"); return EXF_NONE; // to return something
2474     }
2475 }
2476 
atomicCompare(ExFunctor op,const Str & str1,const Str & str2,Number * num2)2477 Bool atomicCompare(ExFunctor op, const Str& str1, const Str& str2,
2478 		   Number* num2)
2479 {
2480   switch(op) {
2481   case EXFO_EQ:
2482   case EXFO_NEQ:
2483     {
2484       return hardCompare(op, str1, str2);
2485     }; break;
2486   case EXFO_LT:
2487   case EXFO_GT:
2488   case EXFO_LE:
2489   case EXFO_GE:
2490       {
2491 	Number n1, n2;
2492 	n1 = str1;
2493 	if (num2) n2 = *num2;
2494 	else n2 = str2;
2495 	return hardCompare(op, n1, n2);
2496       }; break;
2497   default:
2498     {
2499       sabassert(!"atomicCompare");
2500     }
2501   }
2502   return FALSE; //just to return something
2503 }
2504 
compareCC(Sit S,ExFunctor op,const Context & c1,const Context & c2)2505 Bool Expression::compareCC(Sit S, ExFunctor op, const Context &c1, const Context &c2)
2506 {
2507     DStr str1, str2;
2508     GP( Context )
2509         c1prime = ((Context&) c1).copy(),
2510         c2prime = ((Context&) c2).copy();
2511     Bool resulting = FALSE;
2512     (*c1prime).reset();
2513     while ((*c1prime).current())
2514     {
2515 	str1.empty();
2516 	S.dom().constructStringValue((*c1prime).current(), str1);
2517         (*c2prime).reset();
2518         while((*c2prime).current())
2519         {
2520 	    str2.empty();
2521             S.dom().constructStringValue((*c2prime).current(), str2);
2522             if ( atomicCompare(op, str1, str2, NULL) )
2523             {
2524                 resulting = TRUE;
2525                 break;
2526             }
2527             (*c2prime).shift();
2528         };
2529         (*c1prime).shift();
2530     };
2531     // would be done automatically:
2532     c1prime.del();
2533     c2prime.del();
2534     return resulting;
2535 }
2536 
compareCS(Sit S,ExFunctor op,const Context & c1,const Str & str2)2537 Bool Expression::compareCS(Sit S, ExFunctor op, const Context &c1, const Str &str2)
2538 {
2539     DStr str1;
2540     Bool resulting = FALSE;
2541     GP( Context ) c = ((Context&) c1).copy();
2542     //some optimization on str to num conversion
2543     Number* num2 = NULL;
2544     if (op != EXFO_EQ && op != EXFO_NEQ)
2545       {
2546 	num2 = new Number();
2547 	*num2 = str2;
2548       }
2549 
2550     (*c).reset();
2551     while((*c).current())
2552     {
2553         str1.empty();
2554         S.dom().constructStringValue((*c).current(), str1);
2555         if ( atomicCompare(op, str1, str2, num2) )
2556         {
2557             resulting = TRUE;
2558             break;
2559         }
2560         (*c).shift();
2561     };
2562     c.del();
2563     if (num2) delete num2;
2564     return resulting;
2565 }
2566 
compareCN(Sit S,ExFunctor op,const Context & c1,const Number & n2)2567 Bool Expression::compareCN(Sit S, ExFunctor op, const Context &c1, const Number& n2)
2568 {
2569     Number n1;
2570     DStr s1;
2571     GP( Context ) c = ((Context&) c1).copy();
2572     Bool resulting = FALSE;
2573 
2574     (*c).reset();
2575     while((*c).current())
2576     {
2577         s1.empty();
2578         S.dom().constructStringValue((*c).current(), s1);
2579         n1 = s1;
2580         if (hardCompare(op, n1, (Number)n2))
2581         {
2582             resulting = TRUE;
2583             break;
2584         }
2585         (*c).shift();
2586     };
2587     c.del();
2588     return resulting;
2589 }
2590 
compare(Sit S,Bool & result,Expression & other,ExFunctor op)2591 eFlag Expression::compare(Sit S, Bool &result, Expression &other, ExFunctor op)
2592 // Both *this and other are assumed to be ATOMS.
2593 {
2594   sabassert(functor == EXF_ATOM);
2595   sabassert(other.functor == EXF_ATOM);
2596 
2597   ExType histype = other.type;
2598 
2599   //check external object
2600   if (type == EX_EXTERNAL || histype == EX_EXTERNAL)
2601     {
2602       Err(S, E_INVALID_OPERAND_TYPE);
2603     }
2604 
2605   //
2606   if (type == EX_NODESET)
2607     {
2608       if (other.type == EX_BOOLEAN)
2609 	result = hardCompare(op, tobool(), other.tobool());
2610       else
2611         {
2612 	  Context& mynodeset = tonodeset(); // GP: OK
2613 	  switch(other.type)
2614             {
2615             case EX_NODESET:
2616 	      result = compareCC(S, op, mynodeset, other.tonodesetRef());
2617 	      break;
2618             case EX_STRING:
2619 	      {
2620 		Str temp;
2621 		E( other.tostring(S, temp) );
2622 		result = compareCS(S, op, mynodeset, temp);
2623 	      }; break;
2624             case EX_NUMBER:
2625 	      result = compareCN(S, op, mynodeset, other.tonumber(S));
2626 	      break;
2627             default: sabassert(0);
2628             };
2629 	  delete &mynodeset;
2630         }
2631     }
2632   else
2633     {
2634       if (histype == EX_NODESET)
2635 	{
2636 	  E( other.compare(S, result, *this, _invertOp(op)) );
2637 	}
2638       else
2639 	{   // none of the two are nodesets
2640 	  switch (op) {
2641 	  case EXFO_EQ:
2642 	  case EXFO_NEQ:
2643 	    {
2644 	      if (type == EX_BOOLEAN || histype == EX_BOOLEAN)
2645 		result = hardCompare(op, tobool(), other.tobool());
2646 	      else
2647 		{
2648 		  if (type == EX_NUMBER || histype == EX_NUMBER)
2649 		    result = hardCompare(op, tonumber(S), other.tonumber(S));
2650 		  else
2651 		    {
2652 		      if (type == EX_STRING || histype == EX_STRING)
2653 			{
2654 			  Str temp, otherTemp;
2655 			  E( tostring(S, temp) );
2656 			  E( other.tostring(S, otherTemp) );
2657 			  result = hardCompare(op, temp, otherTemp);
2658 			}
2659 		      else
2660 			sabassert(0);
2661 		    }
2662 		}
2663 	    }; break;
2664 	  case EXFO_LT:
2665 	  case EXFO_GT:
2666 	  case EXFO_LE:
2667 	  case EXFO_GE:
2668 	    {
2669 	      result = hardCompare(op, tonumber(S), other.tonumber(S));
2670 	    }; break;
2671 	  }
2672 	}
2673     }
2674   return OK;
2675 }
2676 
callOp(Sit S,Expression & retxpr,ExprList & atoms)2677 eFlag Expression::callOp(Sit S, Expression& retxpr, ExprList& atoms)
2678 {
2679     int i,
2680         atomsNumber = atoms.number();
2681     switch(functor)
2682     {
2683     case EXFO_OR:
2684     case EXFO_AND:
2685         {
2686             sabassert(atomsNumber > 1);
2687             Bool result;
2688             result = atoms[0] -> tobool();
2689             for (i = 1; i < atomsNumber; i++)
2690             {
2691                 if (functor == EXFO_OR)
2692                 {
2693                     if (atoms[i] -> tobool())
2694                     {
2695                         result = TRUE;
2696                         break;
2697                     }
2698                 }
2699                 else    //EXFO_AND
2700                 {
2701                     if (!atoms[i] -> tobool())
2702                     {
2703                         result = FALSE;
2704                         break;
2705                     }
2706                 };
2707             };
2708             retxpr.setAtom(result);
2709         }; break;
2710     case EXFO_EQ:
2711     case EXFO_NEQ:
2712     case EXFO_LT:
2713     case EXFO_LE:
2714     case EXFO_GT:
2715     case EXFO_GE:
2716         {
2717             sabassert(atomsNumber == 2);
2718             Bool result;
2719             E( atoms[0]->compare(S, result,*(atoms[1]),functor) );
2720             retxpr.setAtom(result);
2721         }; break;
2722     case EXFO_PLUS:
2723     case EXFO_MINUS2:
2724     case EXFO_MULT:
2725     case EXFO_DIV:
2726     case EXFO_MOD:
2727         {
2728             sabassert(atomsNumber > 1);
2729             double result;
2730             result = (double) (atoms[0] -> tonumber(S));
2731             for (i = 1; i < atomsNumber; i++)
2732             {
2733                 switch(functor)
2734                 {
2735                 case EXFO_PLUS:
2736                     result += atoms[i] -> tonumber(S);
2737                     break;
2738                 case EXFO_MINUS2:
2739                     result -= atoms[i] -> tonumber(S);
2740                     break;
2741                 case EXFO_MULT:
2742                     result *= atoms[i] -> tonumber(S);
2743                     break;
2744                 case EXFO_DIV:
2745                     result /= atoms[i] -> tonumber(S);
2746                     break;
2747                 case EXFO_MOD:
2748                     {
2749 		      double d = atoms[i] -> tonumber(S);
2750 		      double aux = result/d;
2751 		      aux = aux > 0 ? floor(aux) : ceil(aux);
2752 		      result =  result - (aux * d);
2753                     };
2754                     break;
2755                 };
2756             };
2757 	    //eliminate the -0 effect
2758 	    if (!result) result = 0;
2759             retxpr.setAtom(Number(result));
2760         }; break;
2761     case EXFO_MINUS1:
2762         {
2763             sabassert(atomsNumber == 1);
2764             retxpr.setAtom(Number(-(double)(atoms[0] -> tonumber(S))));
2765         }; break;
2766     };
2767     return OK;
2768 }
2769 
2770 // this appends the list of nodes with given ID, possibly with multiplicities
appendNodesWithID(Sit S,Str & ids,Context * c,Context & result)2771 void appendNodesWithID(Sit S, Str& ids, Context *c, Context& result)
2772 {
2773     char *p = (char*) ids;
2774     Str singleID;
2775     NodeHandle singleNode;
2776     int tokenLen;
2777     for (skipWhite(p); *p; skipWhite(p))
2778     {
2779 	singleID.nset(p, tokenLen = strcspn(p,theWhitespace));
2780 	SXP_Document doc = S.dom().getOwnerDocument(c -> current());
2781 	singleNode = S.dom().getNodeWithID(doc, singleID);
2782 	if (singleNode)
2783 	    result.append(singleNode);
2784 	p += tokenLen;
2785     };
2786 }
2787 
2788 /*================================================================
2789 callFunc
2790     calls the built-in XPath or XSLT function as determined by
2791     'this -> functor'. Returns an expression in 'retxpr'.
2792     'atoms' is a list of atomized arguments, 'c' is the current context
2793     necessary for certain functions.
2794 ================================================================*/
2795 
2796 #define checkArgsCount(x) if (atomsNumber != x)\
2797     Err(S, ET_BAD_ARGS_N);
2798 #define checkArgsCountMax(x) if (atomsNumber > x)\
2799     Err(S, ET_BAD_ARGS_N);
2800 #define checkArgsCountMin(x) if (atomsNumber < x)\
2801     Err(S, ET_BAD_ARGS_N);
2802 #define checkArgsCountBetween(x,y) if ((atomsNumber < x) || \
2803     (atomsNumber > y)) Err(S, ET_BAD_ARGS_N);
2804 
2805 // only check for being a nodeset
2806 #define checkIsNodeset(x) if (atoms[x] -> type != EX_NODESET)\
2807     Err(S, ET_BAD_ARG_TYPE);
2808 
2809 // Everything is a string, in a cosmic sense
2810 #define checkIsString(x)
2811 #define checkIsString2(x,y)
2812 #define checkIsNumber(x)
2813 
2814 /*................
2815 firstOccurence
2816 Finds the first complete occurence of q in p; returns the 0-based starting
2817 position, or -1 if not found
2818 Now works for UTF-8 strings.
2819 ................*/
2820 
firstOccurence(char * p,char * q)2821 int firstOccurence(char *p, char *q)
2822 {
2823     int i = 0,
2824         iCurr = 0,
2825         j = 0,
2826 	    pos = 0,
2827 	    charlen;
2828     while(p[i] && q[j])
2829     {
2830 	charlen = utf8SingleCharLength(p + i);
2831 	if (!strncmp(p + i, q + j, charlen))
2832 	{
2833 	    i += charlen;
2834 	    j += charlen;
2835 	}
2836 	else
2837 	{
2838 	    i = (iCurr += utf8SingleCharLength(p + iCurr));
2839 	    pos++;
2840 	    j = 0;
2841 	}
2842     };
2843     if (q[j])
2844         return -1;
2845     else
2846         return pos;
2847 }
2848 
2849 /*................
2850 getBetween
2851 Returns in s the portion of the source string between from and to inclusive.
2852 If to == -1 then copies the whole rest of the string.
2853 Now works for multibyte UTF-8 characters.
2854 ................*/
2855 
getBetween(Str & s,char * source,int from,int to)2856 void getBetween(Str& s, char *source, int from, int to)
2857 {
2858     sabassert(source);
2859     char *start = NULL;
2860     int i;
2861     if (from < 0) from = 0;
2862     for (i = 0; *source && (i <= to || to == -1); i++)
2863     {
2864 	    if (i == from)
2865 	    {
2866 	        start = source;
2867 		    if (to == -1)
2868 		        // no need to go through the rest of the string
2869 		        break;
2870         }
2871         if (!(*source & 0x80))
2872 	        // optimize for ASCII chars
2873             source++;
2874 	    else
2875             source += utf8SingleCharLength(source);
2876 	}
2877 	if (!start)
2878 	    s.empty();
2879 	else
2880 	{
2881 	    if (to == -1)
2882 	        s = start;
2883 		else
2884 	        s.nset(start,(int)(source - start));
2885 	}
2886 }
2887 
2888 /*................
2889 getCurrValue
2890 Returns the string value of the current node
2891 ................*/
2892 
getCurrValue(Sit S,Str & s,Context * c)2893 eFlag getCurrValue(Sit S, Str &s, Context *c)
2894 {
2895     NodeHandle v;
2896     DStr temp;
2897     if (!!(v = c -> current()))
2898         S.dom().constructStringValue(v, temp);
2899     else
2900         s.empty();
2901     s = temp;
2902     return OK;
2903 }
2904 
2905 // An auxiliary function which retrieves the document from a given URI,
2906 // regardless of whether DOM is external or not. Should be moved into S.dom().
2907 
2908 // new model for processing on external documents: first if have the
2909 // processor and we're running on external, the DOMProvider is asked
2910 
getDocument_(Sit S,NodeHandle & newroot,const Str & location,const Str & baseUri,Processor * proc)2911 eFlag Expression::getDocument_(Sit S, NodeHandle& newroot,
2912 			       const Str& location, const Str& baseUri,
2913 			       Processor* proc)
2914 {
2915   newroot = NULL;
2916   if ( proc && proc -> processingExternal() )
2917     {
2918       /* FIXME: this is incomplete */
2919       newroot = S.dom().retrieveDocument(location, baseUri);
2920     }
2921   //external not active or failed
2922   if ( nhNull(newroot) )
2923     {
2924       if ( proc )
2925 	{
2926 	  Tree *newtree;
2927 	  Str uri, locBase;
2928 	  if (baseUri == (const char*)"")
2929 	      locBase = proc -> baseForVertex(S, &getOwnerElement());
2930 	  else
2931 	      locBase = baseUri;
2932 	  makeAbsoluteURI(S, location, locBase, uri);
2933 
2934 	  //deny document fragments for the 'file' scheme
2935 	  const char* aux = (char*)uri;
2936 	  const char *colon = strchr(aux, ':');
2937 	  if ( colon
2938 	       && ( ((colon - aux == 4) && !strncmp(aux, "file", 4)) ||
2939 		    ((colon - aux == 3) && !strncmp(aux, "arg", 3))))
2940 	    {
2941 	      if ( strchr((const char*)uri, '#') )
2942 		Err1(S, E_DOC_FRAGMENT, (char*)uri);
2943 	    }
2944 	  //if we found no colon, it's bad, but we do not care right here
2945 
2946 	  Bool iserr =
2947 	    proc -> readTreeFromURI(S, newtree, uri,
2948 				    proc ->
2949 				    baseForVertex(S, &getOwnerElement()),
2950 				    FALSE,
2951 				    S.hasFlag(SAB_IGNORE_DOC_NOT_FOUND));
2952 	  if (!iserr) {
2953 	    newroot = (NodeHandle) &(newtree -> getRoot());
2954 	    //strip spaces
2955 	    proc -> stripTree(S, *(newtree));
2956 	  } else if (! S.hasFlag(SAB_IGNORE_DOC_NOT_FOUND))
2957 	    return NOT_OK; //propagate an error
2958 	}
2959       else
2960 	{
2961 	  Err1(S, E1_URI_OPEN, location);
2962 	}
2963     }
2964   return OK;
2965 }
2966 
2967 
2968 
callFunc(Sit S,Expression & retxpr,ExprList & atoms,Context * c)2969 eFlag Expression::callFunc(Sit S, Expression &retxpr, ExprList &atoms, Context *c)
2970 {
2971     NodeHandle v;
2972     int atomsNumber = atoms.number();
2973     switch(functor)
2974     {
2975     case EXFF_LAST:
2976     {
2977 	checkArgsCount(0);
2978 	retxpr.setAtom( Number(c -> getSize()) );
2979     }; break;
2980     case EXFF_POSITION:
2981     {
2982 	checkArgsCount(0);
2983 	retxpr.setAtom( Number(c -> getPosition() + 1) );
2984     }; break;
2985     case EXFF_COUNT:
2986     {
2987 	checkArgsCount(1);
2988 	checkIsNodeset(0);
2989 	retxpr.setAtom(
2990 	    Number(atoms[0] -> tonodesetRef().getSize()) );
2991     }; break;
2992     case EXFF_LOCAL_NAME:
2993     case EXFF_NAMESPACE_URI:
2994     case EXFF_NAME:
2995     {
2996 	checkArgsCountMax(1);
2997 	Str strg;
2998 	if (!atomsNumber)
2999 	    v = (c -> isFinished()) ? NULL : c -> current();
3000 	else
3001 	{
3002 	    checkIsNodeset(0);
3003 	    const Context& newc = atoms[0] -> tonodesetRef();
3004 	    v = (newc.isVoid()? NULL : newc.current());
3005 	};
3006 	if (v)
3007 	{
3008 	    if (!S.domExternal(v))
3009 	      {
3010 		const QName& q = toV(v) -> getName();
3011 		switch(functor)
3012 		{
3013 		case EXFF_NAME:
3014 		    toV(v) -> getOwner().expandQStr(q, strg); break;
3015 		case EXFF_LOCAL_NAME:
3016 		    strg = toV(v) -> getOwner().expand(q.getLocal()); break;
3017 		case EXFF_NAMESPACE_URI:
3018 		    strg = toV(v) -> getOwner().expand(q.getUri()); break;
3019 		}
3020 	      }
3021 	    else
3022 	      {
3023 		const char *aux;
3024 		switch(functor) {
3025 		case EXFF_NAME:
3026 		  {
3027 		    strg = (aux = S.dom().getNodeName(v));
3028 		    S.dom().freeName(v, (char*)aux);
3029 		  } break;
3030 		case EXFF_LOCAL_NAME:
3031 		  {
3032 		    strg = (aux = S.dom().getNodeNameLocal(v));
3033 		    S.dom().freeName(v, (char*)aux);
3034 		  } break;
3035 		case EXFF_NAMESPACE_URI:
3036 		  {
3037 		    strg = (aux = S.dom().getNodeNameURI(v));
3038 		    S.dom().freeName(v, (char*)aux);
3039 		  } break;
3040 		}
3041 	      }
3042 	};
3043 	retxpr.setAtom(strg);
3044     };
3045     break;
3046 
3047     case EXFF_STRING:
3048     {
3049 	Str string;
3050 	checkArgsCountMax(1);
3051 	if (!atomsNumber)
3052 	    E( getCurrValue(S, string, c) )
3053 		else
3054 		    E( atoms[0] -> tostring(S, string) );
3055 	retxpr.setAtom(string);
3056     }; break;
3057 
3058     case EXFF_CONCAT:
3059     {
3060 	checkArgsCountMin(2);
3061 	DStr strg;
3062 	for (int k = 0; k < atomsNumber; k++)
3063 	{
3064 	    checkIsString(k);
3065 	    Str atomStr;
3066 	    E( atoms[k] -> tostring(S, atomStr) );
3067 	    strg += atomStr;
3068 	};
3069 	retxpr.setAtom(strg);
3070     }; break;
3071 
3072     case EXFF_STARTS_WITH:
3073     {
3074 	checkArgsCount(2);
3075 	checkIsString2(0,1);
3076 	Str a0Str, a1Str;
3077 	E( atoms[0] -> tostring(S, a0Str) );
3078 	E( atoms[1] -> tostring(S, a1Str) );
3079 	retxpr.setAtom((Bool) !firstOccurence(
3080 	    a0Str, a1Str));
3081     }; break;
3082 
3083     case EXFF_CONTAINS:
3084     {
3085 	checkArgsCount(2);
3086 	checkIsString2(0,1);
3087 	Str a0Str, a1Str;
3088 	E( atoms[0] -> tostring(S, a0Str) );
3089 	E( atoms[1] -> tostring(S, a1Str) );
3090 	retxpr.setAtom((Bool) (firstOccurence(
3091 	    a0Str, a1Str) != -1));
3092     }; break;
3093 
3094     case EXFF_SUBSTRING_BEFORE:
3095     case EXFF_SUBSTRING_AFTER:
3096     {
3097 	Str strg;
3098 	Str theBigger, theSmaller;
3099 	E( atoms[0] -> tostring(S, theBigger) );
3100 	E( atoms[1] -> tostring(S, theSmaller) );
3101 	checkArgsCount(2);
3102 	checkIsString2(0,1);
3103 	int where = firstOccurence(theBigger,theSmaller);
3104 	if (where == -1)
3105 	    strg.empty();
3106 	else
3107 	{
3108 	    if (functor == EXFF_SUBSTRING_BEFORE)
3109 	    {
3110 		if (where == 0)
3111 		    strg.empty();
3112 		else
3113 		    getBetween(strg, theBigger, 0, where-1);
3114 	    }
3115 	    else
3116 		getBetween(strg, theBigger,
3117 			   where + utf8StrLength(theSmaller), -1);
3118 	};
3119 	retxpr.setAtom(strg);
3120     }; break;
3121 
3122     case EXFF_SUBSTRING:
3123     {
3124 	checkArgsCountBetween(2,3);
3125 	checkIsString(0); checkIsNumber(1);
3126 	/* useless test causing a warning in MSVC:
3127 
3128 	   if (atomsNumber == 3)
3129 	   checkIsNumber(2);
3130 	*/
3131 	Str strg;
3132 	Number from_ = atoms[1] -> tonumber(S) - 1;
3133 	if (!from_.isNaN() && !from_.isInf())
3134 	{
3135 	    int from = from_.round(),
3136 		to = -1;
3137 	    if (atomsNumber > 2)
3138 	    {
3139 		// use length in 3rd argument
3140 		Number len = atoms[2] -> tonumber(S);
3141 		if (len <= 0 || len.isNaN())
3142 		    to = -2;
3143 		else if (!len.isInf())
3144 		    to = from + len.round() - 1;  // otherwise it remains -1
3145 	    }
3146 	    Str a0Str;
3147 	    E( atoms[0] -> tostring(S, a0Str) );
3148 	    getBetween(strg, a0Str, from, to);
3149 	}
3150 	retxpr.setAtom(strg);
3151     }; break;
3152 
3153     case EXFF_STRING_LENGTH:
3154     {
3155 	checkArgsCountBetween(0,1);
3156 	if (atomsNumber)
3157 	{
3158 	    checkIsString(0);
3159 	    Str a0Str;
3160 	    E( atoms[0] -> tostring(S, a0Str) );
3161 	    retxpr.setAtom(Number(utf8StrLength(a0Str)));
3162 	}
3163 	else
3164 	{
3165 	    Str string;
3166 	    E( getCurrValue(S, string, c) );
3167 	    retxpr.setAtom(Number(utf8StrLength(string)));
3168 	}
3169     }; break;
3170 
3171     case EXFF_NORMALIZE_SPACE:
3172     {
3173 	checkArgsCountBetween(0,1);
3174 	Str string;
3175 	if (atomsNumber)
3176 	{
3177 	    checkIsString(0);
3178 	    E( atoms[0] -> tostring(S, string) );
3179 	}
3180 	else
3181 	    E( getCurrValue(S, string, c) );
3182 	char *p = (char*) string;
3183 	DStr stripped;
3184 	skipWhite(p);
3185 	while(*p)
3186 	{
3187 	    if (isWhite(*p))
3188 	    {
3189 		skipWhite(p);
3190 		if (*p)
3191 		    stripped += ' ';
3192 		p--;
3193 	    }
3194 	    else
3195 		stripped += *p;
3196 	    p++;
3197 	}
3198 	retxpr.setAtom(stripped);
3199     }; break;
3200 
3201     case EXFF_TRANSLATE:
3202     {
3203 	checkArgsCount(3);
3204 	checkIsString2(0,1);
3205 	checkIsString(2);
3206 
3207 	DStr resulting;
3208 	Str baseStr, srcStr, destStr;
3209 	int pos;
3210 	E( atoms[0] -> tostring(S, baseStr) );
3211 	E( atoms[1] -> tostring(S, srcStr) );
3212 	E( atoms[2] -> tostring(S, destStr) );
3213 	char
3214 	    // changing tostringCharPtr() to tostring():
3215 	    *p = baseStr,
3216 	    *src = srcStr,
3217 	    *dest = destStr,
3218 	    *destchar;
3219 	while(*p)
3220 	{
3221 	    pos = utf8Strchr(src, p);
3222 	    if (pos == -1) {
3223 	      destchar = p;
3224 	    }
3225 	    else if ((destchar = utf8StrIndex(dest,pos)) == NULL) {
3226 	      p += utf8SingleCharLength(p);
3227 	      continue;
3228 	    }
3229 	    resulting.nadd(destchar, utf8SingleCharLength(destchar));
3230 	    p += utf8SingleCharLength(p);
3231 	};
3232 	retxpr.setAtom(resulting);
3233     }; break;
3234 
3235     case EXFF_BOOLEAN:
3236     {
3237 	checkArgsCount(1);
3238 	retxpr.setAtom(atoms[0] -> tobool());
3239     }; break;
3240 
3241     case EXFF_NOT:
3242     {
3243 	checkArgsCount(1);
3244 	retxpr.setAtom((Bool)!(atoms[0] -> tobool()));
3245     }; break;
3246 
3247     case EXFF_TRUE:
3248     {
3249 	checkArgsCount(0);
3250 	retxpr.setAtom(TRUE);
3251     }; break;
3252 
3253     case EXFF_FALSE:
3254     {
3255 	checkArgsCount(0);
3256 	retxpr.setAtom(FALSE);
3257     }; break;
3258 
3259     case EXFF_LANG:
3260     {
3261 	checkArgsCount(1);
3262 	checkIsString(0);
3263 	// get the argument
3264 	Str langQuery;
3265 	E( atoms[0] -> tostring(S, langQuery) );
3266 	NodeHandle w, att = NULL;
3267 	int attCount, i;
3268 	const char* langValue = NULL;
3269 	for (w = c -> current(); w && !langValue; w = S.dom().getParent(w))
3270 	{
3271 	    // find whether w has an xml:lang attribute
3272 	  if (!S.domExternal(w)) {
3273 	    QName searchName;
3274 	    searchName.setUri(getOwnerTree().unexpand(theXMLNamespace));
3275 	    searchName.setLocal(getOwnerTree().unexpand("lang"));
3276 	    int idx = toE(w) -> atts.findNdx(searchName);
3277 	    if (idx != -1) {
3278 	      langValue = toA( toE(w) -> atts[idx]) -> cont;
3279 	    }
3280 	  } else {
3281 	    attCount = S.dom().getAttributeCount(w);
3282 	    for (i = 0; i < attCount && !langValue; i++)
3283 	      {
3284 		att = S.dom().getAttributeNo(w, i);
3285 		const char *uri = S.dom().getNodeNameURI(att);
3286 		const char *local = S.dom().getNodeNameLocal(att);
3287 		if (!strcmp(uri, theXMLNamespace)
3288 		    && !strcmp(local, "lang"))
3289 		    langValue = S.dom().getNodeValue(att);
3290 		S.dom().freeName(att, (char*)uri);
3291 		S.dom().freeName(att, (char*)local);
3292 	      }
3293 	  }
3294 	}
3295 	if (langValue)
3296 	{
3297 	  char *langQPtr = (char*) langQuery;
3298 	    int qlen;
3299 
3300 	    // if strings equal except for possibly a suffix starting with -
3301 	    // then return TRUE
3302 	    if (!strncasecmp(langQPtr, langValue, qlen = langQuery.length())
3303 		&& (langValue[qlen] == 0 || langValue[qlen] == '-'))
3304 	      retxpr.setAtom(TRUE);
3305 	    else
3306 	      retxpr.setAtom(FALSE);
3307 	    if (att)
3308 	      S.dom().freeValue(att, (char*)langValue);
3309 	}
3310 	else
3311 	    retxpr.setAtom(FALSE);
3312     }; break;
3313 
3314     case EXFF_NUMBER:
3315     {
3316 	checkArgsCountMax(1);
3317 	Number n;
3318 	if (!atomsNumber)
3319 	{
3320 	    Str string;
3321 	    E( getCurrValue(S, string, c) );
3322 	    n = string;
3323 	}
3324 	else
3325 	    n = atoms[0] -> tonumber(S);
3326 	retxpr.setAtom(n);
3327     }; break;
3328 
3329     case EXFF_SUM:
3330     {
3331 	DStr string;
3332 	Number n, sum = 0;
3333 	checkArgsCount(1);
3334 	checkIsNodeset(0);
3335 	GP( Context ) newc = &(atoms[0] -> tonodeset());
3336 	(*newc).reset();
3337 	while (!(*newc).isFinished())
3338 	{
3339 	    string.empty();
3340 	    S.dom().constructStringValue((*newc).current(), string);
3341 	    n = string;
3342 	    if (n.isNaN())
3343 	    {
3344 		sum.setNaN();
3345 		break;
3346 	    };
3347 	    sum = sum + n;
3348 	    (*newc).shift();
3349 	};
3350 	newc.del();
3351 	retxpr.setAtom(sum);
3352     }; break;
3353 
3354     case EXFF_FLOOR:
3355     case EXFF_CEILING:
3356     case EXFF_ROUND:
3357     {
3358 	checkArgsCount(1);
3359 	checkIsNumber(0);
3360 	Number n = atoms[0] -> tonumber(S);
3361 	switch(functor)
3362 	{
3363 	case EXFF_FLOOR:
3364 	    n = floor((double)n); break;
3365 	case EXFF_CEILING:
3366 	    n = ceil((double)n); break;
3367 	case EXFF_ROUND:
3368 	    n = floor((double)n + .5); break;
3369 	};
3370 	retxpr.setAtom(n);
3371     }; break;
3372 
3373     case EXFF_DOCUMENT:
3374     {
3375 	checkArgsCountMin(1);
3376 	checkArgsCountMax(2);
3377 	checkIsString(0);
3378 	DStr location;
3379 	Str baseUri;
3380 	if (atomsNumber == 2)
3381 	  {
3382 	    checkIsNodeset(1);
3383 	    const Context& aux = atoms[1] -> tonodesetRef();
3384 	    if ( ! aux.isVoid() )
3385 	      {
3386 		NodeHandle n = aux[0];
3387 		if (! S.domExternal(n) )
3388 		  {
3389 		    baseUri = NZ(toV(n) -> subtree) -> getBaseURI();
3390 		  } else {
3391 		    baseUri = "";
3392 		  }
3393 	      } else {
3394 		baseUri = "";
3395 	      }
3396 	    //atoms[1] -> tostring(S, baseUri);
3397 	  }
3398 	else
3399 	  baseUri = "";
3400 	NodeHandle newroot = NULL;
3401 	Processor *proc = S.getProcessor();
3402 	//sabassert(S.domExternal((void*)1) || proc); //_ph_ sxp
3403 	GP( Context ) newc = new Context(c->getCurrentNode());
3404 
3405 	// Current node doesn't change
3406 	//(*newc).setCurrentNode (c->getCurrentNode());
3407 
3408 	// GP: the context doesn't autodelete anything on error
3409 	// since readTreeFromURI adds the trees to datalines list
3410 	// All datalines removed on error (in cleanupAfterRun())
3411 
3412 	if (atoms[0] -> type == EX_NODESET)
3413 	{
3414 	    const Context& ctxt = atoms[0] -> tonodesetRef();
3415 	    int ctxtNumber = ctxt.getSize();
3416 	    for (int k = 0; k < ctxtNumber; k++)
3417 	    {
3418 		S.dom().constructStringValue(ctxt[k], location);
3419 		E( getDocument_(S, newroot, location, baseUri, proc) );
3420 		// check for duplicities and correct URI sorting!
3421 		if (! nhNull(newroot) )
3422 		  {
3423 		    (*newc).append(newroot);
3424 		    if (proc && !S.domExternal(newroot))  // _ph_ spx
3425 		      E( proc -> makeKeysForDoc(S, newroot) );
3426 		  }
3427 	    };
3428 	}
3429 	else
3430 	{
3431 	    E( atoms[0] -> tostring(S, location) );
3432 	    E( getDocument_(S, newroot, location, baseUri, proc) );
3433 	    if (! nhNull(newroot) )
3434 	      {
3435 		(*newc).append(newroot);
3436 		if (proc && !S.domExternal(newroot)) //_ph_ spx
3437 		  E( proc -> makeKeysForDoc(S, newroot) );
3438 	      }
3439 	}
3440 	retxpr.setAtom(newc.keep());
3441     }; break;
3442 
3443     case EXFF_GENERATE_ID:
3444     {
3445 	DStr s;
3446 	switch(atomsNumber)
3447 	{
3448 	case 0:
3449 	    v = (c -> isFinished() ? NULL : c -> current());
3450 	    break;
3451 	case 1:
3452 	{
3453 	    checkIsNodeset(0);
3454 	    const Context& newc = atoms[0] -> tonodesetRef();
3455 	    v = (newc.isVoid()? NULL : newc.current());
3456 	}; break;
3457 	default:
3458 	    Err(S, ET_BAD_ARGS_N);
3459 	};
3460 	if (v)
3461 	{
3462 	    s = "i__";
3463 	    if (S.domExternal(v))
3464 	      {
3465 		// need cast to long then to int to avoid
3466 		// compiler error on IBM AIX
3467 		s += (int) (long) v;
3468 	      }
3469 	    else
3470 	      {
3471 		s += (int) (long) &(toV(v) -> getOwner());
3472 		s += "_";
3473 		s += toV(v) -> stamp;
3474 	      }
3475 	}
3476 	retxpr.setAtom(s);
3477     }; break;
3478 
3479     case EXFF_SYSTEM_PROPERTY:
3480     {
3481 	checkArgsCount(1);
3482 	checkIsString(0);
3483 	QName q;
3484 	Str a0Str;
3485 	E( atoms[0] -> tostring(S, a0Str) );
3486 	E( getOwnerElement().setLogical(S, q, a0Str, FALSE) );
3487 	if (q.getUri() == getOwnerTree().stdPhrase(PHRASE_XSL_NAMESPACE))
3488 	  {
3489 	    const Str& localStr = getOwnerTree().expand(q.getLocal());
3490 	    if (localStr == (const char*) "version")
3491 	      retxpr.setAtom(Number(1.0));
3492 	    else if (localStr == (const char*) "vendor")
3493 	      retxpr.setAtom(Str("Ginger Alliance"));
3494 	    else if (localStr == (const char*) "vendor-url")
3495 	      retxpr.setAtom(Str("www.gingerall.com"));
3496 	    else
3497 	      retxpr.setAtom(Str(""));
3498 	}
3499 	else if (q.getUri() == getOwnerTree().stdPhrase(PHRASE_SABEXT_NAMESPACE))
3500 	  {
3501 	    const Str& localStr = getOwnerTree().expand(q.getLocal());
3502 	    if (localStr == (const char*) "version")
3503 	      retxpr.setAtom(Str(SAB_VERSION));
3504 	    else
3505 	      retxpr.setAtom(Str(""));
3506 	  }
3507 	else
3508 	    retxpr.setAtom(Str(""));
3509     }; break;
3510 
3511     case EXFF_EVAL:
3512     {
3513 	Str string;
3514 	checkArgsCount(1);
3515 	E( atoms[0] -> tostring(S, string) );
3516 	Expression *ex = new Expression(getOwnerElement());
3517 	E( (*ex).parse(S,string,FALSE,FALSE) );
3518 	E( (*ex).eval(S,retxpr,c) )
3519     }; break;
3520 
3521     case EXFF_CURRENT:
3522     {
3523 	Context *newc = new Context(NULL);  //_cn_ no need for cn
3524 	newc -> set ( NZ(c -> getCurrentNode()));
3525 	//Context *origc = getOwnerElement().getOrigContext();
3526 	//sabassert(origc);
3527 	//newc -> set ( origc -> current());
3528 	retxpr.setAtom (newc);
3529     }; break;
3530     case EXFF_KEY:
3531     {
3532 	checkArgsCount(2);
3533 	checkIsString(0);
3534 	QName q;
3535 	Str a0Str;
3536 	E( atoms[0] -> tostring(S, a0Str) );
3537 	getOwnerElement().setLogical(S, q, a0Str, FALSE);
3538 	EQName ename;
3539 	getOwnerTree().expandQ(q, ename);
3540 	Processor *proc = NZ(S.getProcessor());
3541 	GP( Context ) newc = new Context(NULL); //_cn_
3542 	GP( Context ) newc2;
3543 	Context auxContext(NULL);
3544 	DStr oneString;
3545 	if (atoms[1] -> type == EX_NODESET)
3546 	{
3547 	    const Context& ctxt = atoms[1] -> tonodesetRef();
3548 	    int ctxtNumber = ctxt.getSize();
3549 	    for (int k = 0; k < ctxtNumber; k++)
3550 	    {
3551 		S.dom().constructStringValue(ctxt[k], oneString);
3552 		E( proc -> getKeyNodes(S, ename,
3553 				       oneString, auxContext,
3554 				       S.dom().getOwnerDocument(c -> current())) );
3555 		newc2 = (*newc).swallow(S, &auxContext);
3556 		newc.del();
3557 		newc.assign(newc2.keep());
3558 	    };
3559 	}
3560 	else
3561 	{
3562 	    E( atoms[1] -> tostring(S, oneString) );
3563 	    E( proc -> getKeyNodes(S, ename,
3564 				   oneString, *newc,
3565 				   S.dom().getOwnerDocument(c -> current())) );
3566 	}
3567 	retxpr.setAtom(newc.keep());
3568     }; break;
3569     case EXFF_FORMAT_NUMBER:
3570     {
3571 	checkArgsCountBetween(2,3);
3572 	Number num = atoms[0] -> tonumber(S);
3573 	Str fmt;
3574 	E( atoms[1] -> tostring(S, fmt) );
3575 	EQName ename;
3576 	if (atomsNumber == 3)
3577 	{
3578 	    Str nameStr;
3579 	    E( atoms[2] -> tostring(S, nameStr) );
3580 	    QName q;
3581 	    getOwnerElement().setLogical(S, q, nameStr, FALSE);
3582 	    getOwnerTree().expandQ(q, ename);
3583 	}
3584 	Str result;
3585 	E( NZ(S.getProcessor()) -> decimals().format(S, ename, num, fmt, result) );
3586 	retxpr.setAtom(result);
3587     }; break;
3588 
3589     case EXFF_ID:
3590     {
3591 	checkArgsCount(1);
3592 	GP( Context ) result = new Context(NULL);
3593 	DStr ids;
3594 	if (atoms[0] -> type == EX_NODESET)
3595 	{
3596 	    const Context& ctxt = atoms[0] -> tonodesetRef();
3597 	    int ctxtNumber = ctxt.getSize();
3598 	    for (int k = 0; k < ctxtNumber; k++)
3599 	    {
3600 		S.dom().constructStringValue(ctxt[k], ids);
3601 		appendNodesWithID(S, ids, c, *result);
3602 	    };
3603 	}
3604 	else
3605 	{
3606 	    E( atoms[0] -> tostring(S, ids) );
3607 	    appendNodesWithID(S, ids, c, *result);
3608 	};
3609 	E( (*result).sort(S) );
3610 	(*result).uniquize();
3611 	retxpr.setAtom(result.keep());
3612     }; break;
3613 
3614     case EXFF_FUNCTION_AVAILABLE:
3615       {
3616 	checkArgsCount(1);
3617 	Str nameStr;
3618 	QName funcName;
3619 	ExFunctor funcNo;
3620 	ExType funcType;
3621 	E( atoms[0] -> tostring(S, nameStr));
3622 	E( getOwnerElement().setLogical(S, funcName, nameStr, FALSE) );
3623 	Str uri = getOwnerTree().expand(funcName.getUri());
3624 	Str name = getOwnerTree().expand(funcName.getLocal());
3625 	getExternalFunctionInfo(uri,name,funcNo,funcType);
3626 	if (funcNo == EXFF_NONE) {
3627 	  retxpr.setAtom(S.getProcessor() -> supportsFunction(uri, name));
3628 	} else {
3629 	  retxpr.setAtom(TRUE);
3630 	};
3631       }; break;
3632 
3633     case EXFF_ELEMENT_AVAILABLE:
3634       {
3635 	checkArgsCount(1);
3636 	Str nameStr;
3637 	QName elName;
3638 	E( atoms[0] -> tostring(S, nameStr));
3639 	E( getOwnerElement().setLogical(S, elName, nameStr, FALSE) );
3640 	Bool ret = ExtensionElement::elementAvailable(getOwnerTree(), elName);
3641 	retxpr.setAtom(ret);
3642       }; break;
3643     case EXFF_UNPARSED_ENTITY_URI:
3644       {
3645 	checkArgsCount(1);
3646 	NodeHandle curr;
3647 	NZ( curr = c -> current() );
3648 	if (S.domExternal(curr))
3649 	  {
3650 	    retxpr.setAtom(""); //not supported for external docs
3651 	    //add check for SXPF_SUPPORTS_UNPARSED_ENTITIES
3652 	  }
3653 	else
3654 	  {
3655 	    Str name;
3656 	    E( atoms[0] -> tostring(S, name) );
3657 	    Str *uri = toV(curr) -> getOwner().getUnparsedEntityUri(name);
3658 	    if (uri)
3659 	      retxpr.setAtom(*uri);
3660 	    else
3661 	      retxpr.setAtom("");
3662 	  }
3663       }; break;
3664 
3665     default:
3666         Err1(S, ET_FUNC_NOT_SUPPORTED, getFuncName(functor));
3667     }
3668     return OK;
3669 }
3670 
createLPContext(Sit S,Context * & c,int baseNdx,NodeHandle givenGlobalCurrent)3671 eFlag Expression::createLPContext(Sit S, Context *&c, int baseNdx, NodeHandle givenGlobalCurrent /* = NULL */)
3672 {
3673     sabassert(functor == EXF_LOCPATH);
3674     GP( Context ) theResult = new Context(c->getCurrentNode()); //_cn_ result has no cn
3675     Context info(givenGlobalCurrent ? givenGlobalCurrent : c -> getCurrentNode()); //_cn_
3676     //info.setCurrentNode(givenGlobalCurrent ? givenGlobalCurrent : c -> current());
3677     //(*theResult).setCurrentNode(c -> getCurrentNode());
3678     E( createLPContextLevel(S, 0, args.number(), c -> current(), info, theResult) );
3679     E( (*theResult).sort(S) );
3680     (*theResult).uniquize();
3681     c = theResult.keep();
3682     return OK;
3683 }
3684 
3685 /*
3686  *  createLPContextLevel
3687  *  ranges over all nodes that satisfy the stepLevel-th step, calling self
3688  *  recursively until the last one is reached. The vertices satisfying the last
3689  *  step are added to theResult.
3690  *  Base is passed from the preceding step and used for expression
3691  *  evaluation. info holds the 'globally current' vertex.
3692  *  The purpose of this routine is to generate a context without having to
3693  *  also generate the intermediate contexts for each step. Also, some of the predicates
3694  *  may be known to use last(), in which case we first have to compute the number
3695  *  of nodes that reach such a predicate at all.
3696  */
3697 
createLPContextLevel(Sit S,int stepLevel,int stepsCount,NodeHandle base,Context & info,Context * theResult)3698 eFlag Expression::createLPContextLevel(Sit S,
3699     int stepLevel, int stepsCount, NodeHandle base,
3700     Context &info, Context *theResult)
3701 {
3702     // GP: theResult will be freed on error since the caller (createLPContext) holds it in a GP
3703 
3704     sabassert(functor == EXF_LOCPATH);
3705     int i, j, init,
3706         predsCount = args[stepLevel] -> step -> preds.number(),
3707         lastBad = -1;     // last bad predicate, or the step itself
3708 
3709 
3710     // keep a stack of positions, one for each predicate IN THIS STEP
3711     List<int> reached(predsCount),  // serves as position for next pred
3712         totalReached(predsCount);   // serves as size for next (bad) pred
3713 
3714     // there will be as many dry (size-counting) runs as there are bad preds
3715     Bool dryRun = TRUE,
3716         quitThisRound = FALSE, quitThisVertex = FALSE;
3717 
3718     // i ranges over predicates. Value i==predsCount is the special last run
3719     for (i = 0; i <= predsCount; i++)
3720     {
3721         if (i == predsCount)
3722             // the last run, not a dry-run
3723             dryRun = FALSE;
3724         // if this is the last run, or if the current pred uses last(), compute
3725         // the context size
3726         if (!dryRun || args[stepLevel] -> step -> preds[i] -> usesLast)
3727         {
3728             // initialize the size arrays:
3729             // append base values for preds past the last bad one,
3730             // up to this bad one (incl.)
3731             for (init = 0; init <= lastBad; init++)
3732                 reached[init] = 0;
3733             for (init = lastBad + 1; init <= i; init++)
3734             {
3735                 reached.append(0);
3736                 totalReached.append(-1);     // -1 just for safety
3737             };
3738 
3739             // locally current vertex
3740             NodeHandle locCurr = NULL;
3741 
3742             quitThisRound = FALSE;
3743             do
3744             {
3745                 // shift the locally current vertex
3746 	      //_speed_ this should be replaced with smart context
3747 	      //created with createContext on local step argument
3748                 E( args[stepLevel] -> step -> shift(S, locCurr, base) );
3749                 if (!nhNull(locCurr))
3750                 {
3751                     if ((lastBad < 0) || !dryRun) ++reached[0];
3752                     quitThisVertex = FALSE;
3753                     for (j = 0; j < i; j++)
3754                     {
3755                         Bool satisfies;
3756                         info.deppendall();
3757                         // set locCurr as current at position reached[j]-1 in the context
3758                         info.setVirtual(locCurr, reached[j] - 1, totalReached[j]);
3759 
3760                         Expression *thisPred =
3761                             args[stepLevel] -> step -> preds[j];
3762                         // find whether we're in position bounds for this pred
3763                         switch(thisPred -> inBounds(reached[j] - 1))
3764                         {
3765                         case 0:
3766                             // within bounds
3767                             {
3768                                 E( thisPred -> trueFor(S, &info, satisfies) );
3769                                 if (satisfies)
3770                                     ++reached[j + 1];
3771                                 else
3772                                     quitThisVertex = TRUE;
3773                             }; break;
3774                         case -1:
3775                             // before start, move to another vertex
3776                             quitThisVertex = TRUE;
3777                             break;
3778                         case 1:
3779                             // past the end, bail out
3780                             quitThisRound = TRUE;
3781                             break;
3782                         };
3783                         if (quitThisVertex || quitThisRound)
3784                             break;
3785                     };
3786                     if (j == i && !dryRun)     // passed all preds
3787                     {
3788                         if (stepLevel < stepsCount - 1)
3789                             E( createLPContextLevel(S,
3790                                 stepLevel + 1, stepsCount,
3791                                 locCurr, info, theResult))
3792                         else
3793                             theResult -> append(locCurr);
3794 
3795                     }   // if ! dryRun
3796                 }       // if locCurr
3797             } while (!nhNull(locCurr) && !quitThisRound);
3798             // move all data collected to safe places
3799             for (init = lastBad + 1; init <= i; init++)
3800                 totalReached[init] = reached[init];
3801             lastBad = i;
3802         }               // if bad predicate
3803     }                   // for, over all preds
3804     return OK;
3805 }
3806 
3807 
createLPContextSum(Sit S,Context * & c,NodeHandle globalCurrent)3808 eFlag Expression::createLPContextSum(Sit S, Context *&c, NodeHandle globalCurrent /* = NULL */)
3809 {
3810     sabassert(functor == EXF_LOCPATH);
3811     GP( Context ) newc = new Context(c->getCurrentNode()); //_cn_ needed?
3812     Context
3813         *newc2, *returnedc;
3814     int cNumber = c -> getSize();
3815     for (int j = 0; j < cNumber; j++)
3816     {
3817         E( createLPContext(S, returnedc = c, j, globalCurrent) );
3818         newc2 = (*newc).swallow(S, returnedc);
3819         newc.del();
3820         newc = newc2;
3821         delete returnedc;
3822 	/* tom 01/11/25 */
3823 	c -> shift();
3824     }
3825     c = newc.keep();
3826     return OK;
3827 }
3828 
3829 
3830 /*................................................................
3831 createContext()
3832     creates a context for this expression, based on its functor.
3833 ................................................................*/
3834 
3835 // GP: createContext is clean
3836 // if unsuccessful, returns NULL in c and performs no allocations
3837 
3838 
createContext(Sit S,Context * & c,int baseNdx)3839 eFlag Expression::createContext(Sit S, Context *& c, int baseNdx /* = -1 */)
3840 {
3841     GP( Context ) newc; // newc gets assigned c ONLY IN THE END
3842     Context *c_orig = c;
3843     newc.assign(c);
3844     c = NULL;
3845 
3846     int i, j,
3847         argsNumber = args.number();
3848     if (baseNdx == -1)
3849         baseNdx = (*newc).getPosition();
3850     switch(functor)
3851     {
3852     case EXF_VAR:
3853         {
3854 	  Expression *deref = NULL;
3855 	  if (S.getProcessor())
3856 	    deref = S.getProcessor() -> getVarBinding(*pName);
3857 	  if (!deref)
3858 	  {
3859 	      Str fullName;
3860 	      getOwnerTree().expandQStr(*pName, fullName);
3861 	      Err1(S, E1_VAR_NOT_FOUND, fullName);
3862 	  }
3863 	  NodeHandle current_node = (*newc).getCurrentNode();
3864 	  E( deref -> createContext(S, newc, baseNdx) );
3865 	  newc.unkeep();
3866 	  (*newc).setCurrentNode(current_node);
3867         };
3868         break;
3869     case EXF_ATOM:
3870         {
3871             if (type != EX_NODESET)
3872                 Err(S, ET_CONTEXT_FOR_BAD_EXPR);
3873             newc = patomnodeset -> copy();
3874             newc.unkeep();
3875         }; break;
3876     case EXFO_UNION:
3877         {
3878             sabassert(baseNdx != -1);  // meaningful only for a locpath
3879             GP( Context ) csummand;
3880             Context *newc2;     // GP: OK
3881             sabassert(argsNumber);
3882             E( args[0] -> createContext(S, newc, baseNdx) );
3883             newc.unkeep();
3884             for (i = 1; i < argsNumber; i++)
3885             {
3886                 csummand.assign(c_orig);
3887                 E( args[i] -> createContext(S, csummand, baseNdx) );
3888                 newc2 = (*newc).swallow(S, csummand);
3889                 csummand.del();
3890                 newc.del();
3891                 newc = newc2;
3892             }
3893             // clean up newc!
3894             (*newc).reset();
3895         }
3896         break;
3897     case EXF_LOCPATH:
3898         {
3899             E( createLPContext(S, newc, baseNdx) );
3900             newc.unkeep();
3901         }
3902         break;
3903     case EXF_FILTER:
3904         {
3905             sabassert(baseNdx != -1);  // meaningful only for a locpath
3906             NodeHandle wasCurrent = (*newc).getCurrentNode();
3907             E( args[0] -> createContext(S, newc, baseNdx) );
3908             newc.unkeep();
3909             (*newc).setCurrentNode(wasCurrent);
3910 
3911             GP( Context ) filteredc;
3912             for (i = 1; i < argsNumber - (int) hasPath; i++)
3913             {
3914                 filteredc = new Context(c_orig -> getCurrentNode());
3915                 (*newc).reset();
3916                 Bool istrue;
3917                 int newcNumber = (*newc).getSize();
3918                 for (j = 0; j < newcNumber; j++)
3919                 {
3920                     E(args[i] -> trueFor(S, newc, istrue));
3921                     if (istrue)
3922                         (*filteredc).append((*newc)[j]);
3923                     (*newc).shift();
3924                 };
3925                 newc.del();
3926                 newc = filteredc.keep();
3927                 if (!(*newc).getSize()) break;
3928             };
3929             if (hasPath)
3930             {
3931                 filteredc.assign(newc);
3932 		filteredc = newc;  // a patch due to SGI MIPSpro compiler
3933                 E( args[argsNumber-1] -> createLPContextSum(S, filteredc, (*newc).getCurrentNode()) );
3934                 newc.del();
3935                 newc = filteredc.keep();
3936             }
3937         }
3938         break;
3939     case EXF_LOCSTEP:
3940         {
3941             sabassert(step);
3942             sabassert(baseNdx != -1);  // meaningful only for a locpath
3943 
3944             /////////
3945             // E( step -> createContextNoPreds(newc = c, baseNdx) );    - done as follows:
3946             GP( Context ) newc2 = new Context(c_orig -> getCurrentNode());
3947             NodeHandle curr = NULL;
3948             do
3949             {
3950 	      //_speed_ here we should test the axis type
3951 	      // and use smart context if possible
3952                 E( step -> shift(S, curr, (*newc)[baseNdx]) );
3953                 if (!nhNull(curr))
3954                     (*newc2).append(curr);
3955             }
3956             while (!nhNull(curr));
3957             /////////
3958 
3959             GP( Context ) filteredc;
3960             int stepPredsNumber = step -> preds.number();
3961             for (i = 0; i < stepPredsNumber; i++)
3962             {
3963                 filteredc = new Context(c_orig -> getCurrentNode());
3964                 (*newc2).reset();
3965                 Bool istrue;
3966                 int newc2Number = (*newc2).getSize();
3967                 for (j = 0; j < newc2Number; j++)
3968                 {
3969                     E( step -> preds[i] -> trueFor(S, newc2,istrue) );
3970                     if (istrue)
3971                         (*filteredc).append((*newc2)[j]);
3972                     (*newc2).shift();
3973                 };
3974                 newc2.del();
3975                 newc2 = filteredc.keep();
3976                 if (!(*newc2).getSize()) break;
3977             };
3978             newc = newc2.keep();
3979         };
3980         break;
3981     case EXF_OTHER_FUNC:
3982 	{
3983 	  Expression resolved(getOwnerElement());
3984 	  E( eval(S, resolved, newc) );
3985 	  E( resolved.createContext(S, newc, baseNdx) );
3986 	  newc.unkeep();
3987 	}; break;
3988     default:
3989       if (funcIsBuiltin(functor))
3990         {
3991             Expression resolved(getOwnerElement());
3992             E( eval(S, resolved, newc) );
3993             E( resolved.createContext(S, newc, baseNdx) );
3994             newc.unkeep();
3995         }
3996         else
3997         Err(S, ET_CONTEXT_FOR_BAD_EXPR);
3998     };
3999     c = newc.keep();
4000     return OK;
4001 }
4002 
4003 
matchesSingleStep(Sit S,NodeHandle v,Bool & result)4004 eFlag Expression::matchesSingleStep(Sit S, NodeHandle v, Bool &result)
4005 {
4006     sabassert(functor == EXF_LOCSTEP);
4007     if (!NZ(step) -> matchesWithoutPreds(S, v))
4008         RetOK(result, FALSE);
4009     if (!step -> preds.number())
4010         RetOK(result, TRUE);
4011     if (!S.dom().getParent(v))
4012         RetOK(result, FALSE);
4013     if (!step -> positional)
4014     {
4015       GP( Context ) c = new Context(NULL); //_cn_ current() is not allowed in patterns
4016         (*c).set(v);
4017         Bool stillOK = TRUE;
4018         for (int i = 0; i < step -> preds.number() && stillOK; i++)
4019             E(step -> preds[i] -> trueFor(S, c,stillOK));
4020         c.del();
4021         RetOK(result,stillOK);
4022     }
4023     else // positional case
4024     {
4025         GP( Context ) c = new Context(NULL);  //_cn_ current() is not allowed in patterns
4026         Context *newc; // GP: OK
4027         (*c).set(S.dom().getParent(v));
4028         E( createContext(S, newc = c+0, 0) );
4029         result = (newc -> contains(v));
4030         c.del();
4031         delete newc;
4032     }
4033     return OK;
4034 }
4035 
4036 
matchesSinglePath(Sit S,NodeHandle v,int lastIndex,Bool & result)4037 eFlag Expression::matchesSinglePath(Sit S, NodeHandle v, int lastIndex, Bool& result)
4038 {
4039     sabassert(functor == EXF_LOCPATH);
4040     int i;
4041     NodeHandle w = v;
4042     for (i = lastIndex; i >= 0; i--)
4043     {
4044         if (!w)
4045             RetOK(result, FALSE);
4046         switch(args[i] -> step -> ax)
4047         {
4048         case AXIS_ROOT:
4049 	        {
4050                 if (i)
4051                     sabassert(!"root not first");
4052                 E( args[i] -> matchesSingleStep(S, w, result) );
4053                 if (!result) RetOK(result, FALSE);
4054 		    };
4055             break;
4056         case AXIS_CHILD:
4057         case AXIS_ATTRIBUTE:
4058             {
4059                 E( args[i] -> matchesSingleStep(S, w, result) );
4060                 if (!result) RetOK(result, FALSE);
4061                 w = S.dom().getParent(w);
4062             };
4063             break;
4064         case AXIS_DESC_OR_SELF:
4065             {
4066                 E( args[i] -> matchesSingleStep(S, w, result) );
4067                 if (!result) RetOK(result, FALSE);
4068                 NodeHandle previous = w;
4069                 while (previous)
4070                 {
4071                     E(matchesSinglePath(S, previous, i-1, result));
4072                     if (result)
4073                         return OK;
4074                     else
4075                         previous = S.dom().getParent(previous);
4076                 };
4077                 RetOK( result, FALSE );
4078             }
4079             break;
4080         default:
4081             sabassert(!"bad axis in pattern");
4082         }
4083     }
4084     result = TRUE;
4085     return OK;
4086 }
4087 
4088 /*
4089  *  optimizePositional()
4090  *  called for a predicate of a locstep
4091  *  returns 2 if the predicate uses the last() function
4092  *    so the size of the context has to be determined
4093  *  returns 1 if the predicate only uses position()
4094  *          0 if neither
4095  */
4096 
optimizePositional(int level)4097 int Expression::optimizePositional(int level)
4098 {
4099     int result = 0;
4100 
4101     switch(functor)
4102     {
4103     case EXFF_LAST:
4104         result = 2; break;
4105     case EXFF_POSITION:
4106         result = 1; break;
4107     case EXF_ATOM:
4108     case EXF_VAR:
4109     case EXF_LOCPATH:
4110         /* result = 0; */ break;
4111     case EXF_STRINGSEQ:
4112     case EXF_FRAGMENT:
4113     case EXF_LOCSTEP:
4114         sabassert(!"invalid predicate type");
4115         break;
4116     case EXF_FILTER: // can be e.g. "current()/@attr"
4117     default: // all the functions and operators, including EXF_OTHER_FUNC
4118         {
4119             int sub = 0;
4120             for (int i = 0; i < args.number(); i++)
4121             {
4122                 if (!!(sub = args[i] -> optimizePositional(level + 1)))
4123                 {
4124                     result = sub;
4125                     if (result == 2) break;
4126                 }
4127             }
4128         }
4129     }
4130     //PH: when we're called w/o recursion,
4131     //we might be called for situation like foo[45],
4132     //so we should return 1, if the expression
4133     //is of the type of EX_NUMBER
4134     if (!level && type == EX_NUMBER && !result) result = 1;
4135 
4136     usesLast = (result == 2);
4137     positional = (result >= 1);
4138     return result;
4139 }
4140 
4141 /*
4142  *  optimizePositionBounds()
4143  *  called for a predicate of a locstep
4144  *  returns the range of positions that need to be examined for a context
4145  *  e.g. the predicate in foo[1] will return both set to 1.
4146  *  the positions returned are 1-based, 0 means "no restriction"
4147  */
4148 
optimizePositionBounds()4149 void Expression::optimizePositionBounds()
4150 {
4151     int from = 0, to = 0;
4152     switch(functor)
4153     {
4154     case EXF_ATOM:
4155         {
4156             if (type == EX_NUMBER)
4157                 from = to = NZ(patomnumber) -> round();    // bad values like NaN return 0 which is OK.
4158         }; break;
4159     case EXFO_EQ:
4160     case EXFO_LE:
4161     case EXFO_LT:
4162     case EXFO_GE:
4163     case EXFO_GT:
4164         {
4165             if (args[0] -> functor == EXFF_POSITION &&
4166                 args[1] -> functor == EXF_ATOM && args[1] -> type == EX_NUMBER)
4167             {
4168                 int bound = args[1] -> patomnumber -> round();
4169                 switch(functor)
4170                 {
4171                 case EXFO_EQ: from = to = bound; break;
4172                 case EXFO_LE: to = bound; break;
4173                 case EXFO_LT: to = bound - 1; break;
4174                 case EXFO_GE: from = bound; break;
4175                 case EXFO_GT: from = bound + 1; break;
4176                 }
4177             }
4178         }; break;
4179     }
4180     optimizePositionFrom = from;
4181     optimizePositionTo = to;
4182 }
4183 
inBounds(int position) const4184 int Expression::inBounds(int position) const
4185 {
4186     if (optimizePositionTo && position > optimizePositionTo-1)
4187         return 1;
4188     if (optimizePositionFrom && position < optimizePositionFrom-1)
4189         return -1;
4190     return 0;
4191 }
4192 
getOwnerElement() const4193 Element& Expression::getOwnerElement() const
4194 {
4195     return owner;
4196 };
4197 
getOwnerTree() const4198 Tree& Expression::getOwnerTree() const
4199 {
4200     return owner.getOwner();
4201 }
4202 
4203 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)4204 void Expression::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
4205 {
4206     getOwnerElement().report(S,type,code,arg1,arg2);
4207 }
4208 
containsFunctor(ExFunctor func)4209 Bool Expression::containsFunctor(ExFunctor func)
4210 {
4211   if (functor == func)
4212     return TRUE;
4213   else if (functor == EXF_LOCSTEP)
4214     {
4215       for (int i = 0; i < step -> preds.number(); i++)
4216 	{
4217 	  if (step -> preds[i] -> containsFunctor(func))
4218 	    return TRUE;
4219 	}
4220     }
4221 
4222   for (int i = 0; i < args.number(); i++)
4223     {
4224       if (args[i] -> containsFunctor(func))
4225 	return TRUE;
4226     }
4227   return FALSE;
4228 }
4229