Initial revision
[TestXSLT.git] / libsablot / src / engine / base.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable 
23  * instead of those above.  If you wish to allow use of your 
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32
33 #include "base.h"
34 #include "platform.h"
35 #include "proc.h"
36 #include "utf8.h"
37 // #include <new.h>
38 #include <ctype.h>
39 // #include <strings.h>
40
41 // GP: clean
42
43 #if defined(CHECK_LEAKS)
44 #pragma Msg("Building with leak checking")
45 #endif
46
47 // includes for time measurement moved to platform.cpp
48
49 /****************************************
50 X S L   c o n s t a n t s
51 ****************************************/
52
53 // !!!!!!!!!!!!!!!!!!!!!
54 // the order of items in the following tables must agree with
55 // that in the corresponding enums as defined in base.h
56
57 const char* xslOpNames[]=
58 {
59     "apply-imports","apply-templates",
60     "attribute","attribute-set",
61     "call-template","choose",
62     "comment", "copy","copy-of",
63     "decimal-format","element",
64     "fallback","for-each",
65     "if","import",
66     "include","key",
67     "message","namespace-alias",
68     "number","otherwise",
69     "output","param",
70     "preserve-space","processing-instruction",
71     "sort","strip-space",
72     "stylesheet","template",
73     "text","transform",
74     "value-of","variable",
75     "when","with-param",
76     NULL
77 };
78
79 const char* xslAttNames[]=
80 {
81     "case-order", "cdata-section-elements", "count",
82     "data-type", "decimal-separator", "digit", "disable-output-escaping", "doctype-public", "doctype-system",
83     "elements", "encoding", "exclude-result-prefixes", "extension-element-prefixes",
84     "format", "from",
85     "grouping-separator", "grouping-size",
86     "href",
87     "id", "indent", "infinity",
88     "lang", "letter-value", "level",
89     "match", "media-type", "method", "minus-sign", "mode",
90     "name", "namespace", "NaN",
91     "omit-xml-declaration", "order",
92     "pattern-separator", "percent", "per-mille", "priority",
93     "result-prefix", 
94     "select", "standalone", "stylesheet-prefix",
95     "terminate", "test",
96     "use", "use-attribute-sets",
97     "value", "version",
98     "zero-digit",
99     NULL
100 };
101
102 const char* axisNames[]=
103 {
104     "ancestor","ancestor-or-self",
105         "attribute","child",
106         "descendant","descendant-or-self",
107         "following","following-sibling",
108         "namespace","parent",
109         "preceding","preceding-sibling",
110         "self",
111         NULL,
112         "root"
113 };
114
115 const char* vertexTypeNames[] =
116 {
117     "","root","element","attribute",
118         "text","processing instruction","comment","namespace"
119 };
120
121 const char* exNodeTypeNames[] =
122 {
123     "node", "text",
124         "processing-instruction", "comment",
125         NULL
126 };
127
128 const char* theXSLTNamespace = "http://www.w3.org/1999/XSL/Transform";
129 const char* oldXSLTNamespace = "http://www.w3.org/XSL/Transform/1.0";
130 const char* theXMLNamespace = "http://www.w3.org/XML/1998/namespace";
131 const char* theXHTMLNamespace = "http://www.w3.org/1999/xhtml";
132 const char* theXMLNSNamespace = "http://www.w3.org/2000/xmlns/";
133 const char* theSabExtNamespace = "http://www.gingerall.org/sablotron/extension";
134
135 const char* theWhitespace = " \t\x0a\x0d";
136
137 //
138 //  escape strings
139 //
140
141 const char
142     * escNewline = "&#10;",
143     * escTab = "&#9;",
144     * escLess = "&lt;",
145     * escGreater = "&gt;",
146     * escQuote = "&quot;",
147     * escApos = "&apos;";
148
149 //
150 //  handler types
151 //  to match HandlerType in shandler.h
152 //
153
154 const char* hlrTypeNames[] = {"message", "scheme", "streaming",
155                               "miscellaneous", "encoding"};
156
157 /*****************************************************************
158 Global handlers that can be set via Sablot functions
159 *****************************************************************/
160
161 // URI scheme handler
162 SchemeHandler* theSchemeHandler = NULL;
163 // message handler (errors, warnings, log messages...)
164 MessageHandler* theMessageHandler = NULL;
165 // SAX call handler (streamed access to the result document)
166 SAXHandler* theSAXHandler = NULL;
167 void* theSAXUserData = NULL;
168
169 /****************************************
170 l o o k u p
171 ****************************************/
172
173 // Finds a string in a NULL-terminated table of pointers.
174
175 int lookup(const char* str, const char** table)
176 {
177     const char **p = table;
178     int i = 0;
179     while (*p)
180     {
181         if (!strcmp(str,*p)) return i;
182         p++; i++;
183     };
184     return i;
185 }
186
187 int lookupNoCase(const char* str, const char** table)
188 {
189     const char **p = table;
190     int i = 0;
191     while (*p)
192     {
193         if (strEqNoCase(str,*p)) return i;
194         p++; i++;
195     };
196     return i;
197 }
198
199
200
201 /*****************************************************************
202 stdopen(), stdclose()
203 *****************************************************************/
204
205 Bool isstd(const char *fname)
206 {
207     if (!strcmp(fname,"stdin") || !strcmp(fname,"stderr")
208         || !strcmp(fname,"stdout"))
209         return TRUE;
210     return FALSE;
211 }
212
213 int stdclose(FILE *f)
214 {
215     if ((!f) || (f == stdin) || (f == stdout) || (f == stderr))
216         return 0;
217     else return fclose(f);
218 }
219
220 FILE* stdopen(const char *fn, const char *mode)
221 {
222     if (!strcmp(fn,"stderr"))
223         return stderr;
224     else if (!strcmp(fn,"stdout"))
225         return stdout;
226     else if (!strcmp(fn,"stdin"))
227         return stdin;
228     else 
229     {
230         FILE* x = fopen(fn,mode);
231         if (x) return x;
232         return NULL;
233     };
234 };
235
236 /*****************************************************************
237 strEqNoCase
238 *****************************************************************/
239
240 Bool strEqNoCase(const char* s1, const char* s2)
241 {
242     int i;
243     for (i = 0; s1[i]; i++)
244     {
245         if (tolower(s1[i]) != tolower(s2[i]))
246             return FALSE;
247     }
248     return s2[i] ? FALSE : TRUE;
249 }
250
251 /*****************************************************************
252 Memory leaks
253 *****************************************************************/
254
255 void checkLeak()
256 {
257 #if (defined(WIN32) && defined(CHECK_LEAKS))
258     _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
259     _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
260     _CrtMemDumpAllObjectsSince(NULL);
261 #endif
262 }
263
264 void memStats()
265 {
266 #if (defined(WIN32) && defined(CHECK_LEAKS))
267     _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
268     _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
269     _CrtMemState memsnap;
270     _CrtMemCheckpoint(&memsnap);
271     _CrtMemDumpStatistics(&memsnap);
272 #endif
273 }
274
275 /*****************************************************************
276 new handler
277 *****************************************************************/
278
279 //#ifdef _DEBUG
280 //#pragma Msg("'new' handler in linux?")
281 //#endif
282 /*
283 #ifdef WIN32
284 static _PNH oldNewHandler = NULL;
285 #endif
286
287 int sablotNewHandler(size_t size)
288 {
289 #if defined(WIN32) || defined(__linux__) || defined(__unix)
290         throw(E_MEMORY);
291 #else
292         //situation.error(E_MEMORY, *theEmptyString, theEmptyString);
293 #endif
294     return 0;
295 }
296
297 void pushNewHandler()
298 {
299 #ifdef WIN32
300     assert(!oldNewHandler);
301     oldNewHandler = _set_new_handler(sablotNewHandler);
302 #endif
303 }
304
305 void popNewHandler()
306 {
307 #ifdef WIN32
308     _set_new_handler( oldNewHandler );
309     oldNewHandler = NULL; 
310 #endif
311 }
312 */
313 /*****************************************************************
314 fcomp
315
316   float comparison: returns 0 / 1 / -1 if p1 == / > / < p2.
317 *****************************************************************/
318
319 int fcomp(double p1, double p2)
320 {
321     double d = p1 - p2;
322     if ((d < EPS) && (d > -EPS)) return 0;
323     else return (d > 0 ? 1 : -1);
324 }
325
326 //  time
327
328 Str getMillisecsDiff(double originalTime)
329 {
330     char buf[20];
331     // getMillisecs() is in platform.cpp
332     sprintf(buf, "%.3f", getMillisecs() - originalTime);
333     return Str(buf);
334 }
335
336
337 /**************** XML name checks ********************/
338
339 Bool isValidNCName(const char* name)
340 {
341   int len = utf8StrLength(name);
342   if (len == 0) return FALSE;
343
344   wchar_t *buff = new wchar_t[len + 1];
345
346   utf8ToUtf16(buff, name);
347   
348   Bool result = utf8IsLetter(buff[0]) || buff[0] == 0x005F; //underscore  
349   for (int i = 1; i < len && result; i++)
350     {
351       result = 
352         utf8IsLetter(buff[i]) ||
353         utf8IsDigit(buff[i]) ||
354         utf8IsCombiningChar(buff[i]) ||
355         utf8IsExtender(buff[i]) ||
356         buff[i] == 0x002E || //dot
357         buff[i] == 0x002D || //hyphen
358         buff[i] == 0x005F; //underscore
359     }
360
361   delete[] buff;
362   return result;
363 }
364
365 Bool isValidQName(const char* name)
366 {
367   char *local = NULL;
368   Bool result = TRUE;
369
370   char *colon = (char *)strchr(name, ':');
371   if (colon) 
372     {
373       *colon = '\0';
374       local = colon + 1;
375     }
376
377   result = isValidNCName(name) && (local == NULL || isValidNCName(local));
378
379   if (colon) *colon = ':';
380   return result;
381 }
382
383
384 //string parsing
385 Bool getWhDelimString(char *&list, Str& firstPart)
386 {
387     skipWhite(list);
388     if (!*list) return FALSE;
389     char *list_was = list;
390     for(; *list && !isWhite(*list); list++);
391     firstPart.nset(list_was, (int)(list - list_was));
392     return TRUE;
393 }