1 /*
2 * rasqal_xsd_datatypes.c - Rasqal XML Schema Datatypes support
3 *
4 * Copyright (C) 2005-2010, David Beckett http://www.dajobe.org/
5 * Copyright (C) 2005-2005, University of Bristol, UK http://www.bristol.ac.uk/
6 *
7 * This package is Free Software and part of Redland http://librdf.org/
8 *
9 * It is licensed under the following three licenses as alternatives:
10 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
11 * 2. GNU General Public License (GPL) V2 or any newer version
12 * 3. Apache License, V2.0 or any newer version
13 *
14 * You may not use this file except in compliance with at least one of
15 * the above three licenses.
16 *
17 * See LICENSE.html or LICENSE.txt at the top of this package for the
18 * complete terms and further detail along with the license texts for
19 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
20 *
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <rasqal_config.h>
26 #endif
27
28 #ifdef WIN32
29 #include <win32_rasqal_config.h>
30 #endif
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 #include <stdarg.h>
39 #ifdef HAVE_LIMITS_H
40 #include <limits.h>
41 #endif
42 #ifdef HAVE_ERRNO_H
43 #include <errno.h>
44 #endif
45
46 #include "rasqal.h"
47 #include "rasqal_internal.h"
48
49 /* local prototypes */
50 int rasqal_xsd_check_double_format(const unsigned char* string, int flags);
51
52
53 #ifndef STANDALONE
54
55 /*
56 *
57 * References
58 *
59 * XPath Functions and Operators
60 * http://www.w3.org/TR/xpath-functions/
61 *
62 * Datatypes hierarchy
63 * http://www.w3.org/TR/xpath-functions/#datatypes
64 *
65 * Casting
66 * http://www.w3.org/TR/xpath-functions/#casting-from-primitive-to-primitive
67 *
68 */
69
70
71 int
rasqal_xsd_boolean_value_from_string(const unsigned char * string)72 rasqal_xsd_boolean_value_from_string(const unsigned char* string)
73 {
74 int integer = 0;
75
76 /* FIXME
77 * Strictly only {true, false, 1, 0} are allowed according to
78 * http://www.w3.org/TR/xmlschema-2/#boolean
79 */
80 if(!strcmp(RASQAL_GOOD_CAST(const char*, string), "true") ||
81 !strcmp(RASQAL_GOOD_CAST(const char*, string), "TRUE") ||
82 !strcmp(RASQAL_GOOD_CAST(const char*, string), "1"))
83 integer = 1;
84
85 return integer;
86 }
87
88
89 static int
rasqal_xsd_check_boolean_format(const unsigned char * string,int flags)90 rasqal_xsd_check_boolean_format(const unsigned char* string, int flags)
91 {
92 /* FIXME
93 * Strictly only {true, false, 1, 0} are allowed according to
94 * http://www.w3.org/TR/xmlschema-2/#boolean
95 */
96 if(!strcmp(RASQAL_GOOD_CAST(const char*, string), "true") ||
97 !strcmp(RASQAL_GOOD_CAST(const char*, string), "TRUE") ||
98 !strcmp(RASQAL_GOOD_CAST(const char*, string), "1") ||
99 !strcmp(RASQAL_GOOD_CAST(const char*, string), "false") ||
100 !strcmp(RASQAL_GOOD_CAST(const char*, string), "FALSE") ||
101 !strcmp(RASQAL_GOOD_CAST(const char*, string), "0"))
102 return 1;
103
104 return 0;
105 }
106
107
108 #define ADVANCE_OR_DIE(p) if(!*(++p)) return 0;
109
110
111 /**
112 * rasqal_xsd_check_date_format:
113 * @string: lexical form string
114 * flags: flags
115 *
116 * INTERNAL - Check an XSD date lexical form
117 *
118 * Return value: non-0 if the string is valid
119 */
120 static int
rasqal_xsd_check_date_format(const unsigned char * string,int flags)121 rasqal_xsd_check_date_format(const unsigned char* string, int flags)
122 {
123 /* This should be correct according to
124 * http://www.w3.org/TR/xmlschema-2/#date
125 */
126 return rasqal_xsd_date_check(RASQAL_GOOD_CAST(const char*, string));
127 }
128
129
130 /**
131 * rasqal_xsd_check_dateTime_format:
132 * @string: lexical form string
133 * flags: flags
134 *
135 * INTERNAL - Check an XSD dateTime lexical form
136 *
137 * Return value: non-0 if the string is valid
138 */
139 static int
rasqal_xsd_check_dateTime_format(const unsigned char * string,int flags)140 rasqal_xsd_check_dateTime_format(const unsigned char* string, int flags)
141 {
142 /* This should be correct according to
143 * http://www.w3.org/TR/xmlschema-2/#dateTime
144 */
145 return rasqal_xsd_datetime_check(RASQAL_GOOD_CAST(const char*, string));
146 }
147
148
149 /**
150 * rasqal_xsd_check_decimal_format:
151 * @string: lexical form string
152 * flags: flags
153 *
154 * INTERNAL - Check an XSD decimal lexical form
155 *
156 * Return value: non-0 if the string is valid
157 */
158 static int
rasqal_xsd_check_decimal_format(const unsigned char * string,int flags)159 rasqal_xsd_check_decimal_format(const unsigned char* string, int flags)
160 {
161 const char* p;
162
163 /* This should be correct according to
164 * http://www.w3.org/TR/xmlschema-2/#decimal
165 */
166 p = RASQAL_GOOD_CAST(const char*, string);
167 if(*p == '+' || *p == '-') {
168 ADVANCE_OR_DIE(p);
169 }
170
171 while(*p && isdigit(RASQAL_GOOD_CAST(int, *p)))
172 p++;
173 if(!*p)
174 return 1;
175 /* Fail if first non-digit is not '.' */
176 if(*p != '.')
177 return 0;
178 p++;
179
180 while(*p && isdigit(RASQAL_GOOD_CAST(int, *p)))
181 p++;
182 /* Fail if anything other than a digit seen before NUL */
183 if(*p)
184 return 0;
185
186 return 1;
187 }
188
189
190 /* Legal special double values */
191 #define XSD_DOUBLE_SPECIALS_LEN 3
192 static const char * const xsd_double_specials[XSD_DOUBLE_SPECIALS_LEN] = {
193 "-INF",
194 "INF",
195 "NaN"
196 };
197
198 /**
199 * rasqal_xsd_check_double_format:
200 * @string: lexical form string
201 * flags: flags
202 *
203 * INTERNAL - Check an XSD double lexical form
204 *
205 * Return value: non-0 if the string is valid
206 */
207 int
rasqal_xsd_check_double_format(const unsigned char * string,int flags)208 rasqal_xsd_check_double_format(const unsigned char* string, int flags)
209 {
210 const char *p = RASQAL_GOOD_CAST(const char*, string);
211 const char *saved_p;
212 int i;
213
214 if(!*p)
215 return 0;
216
217 /* Validating http://www.w3.org/TR/xmlschema-2/#double */
218
219 /* check for specials */
220 for(i = 0; i < XSD_DOUBLE_SPECIALS_LEN; i++) {
221 if(!strcmp(xsd_double_specials[i], p))
222 return 1;
223 }
224
225 /* mantissa: follows http://www.w3.org/TR/xmlschema-2/#decimal */
226 if(*p == '-' || *p == '+')
227 p++;
228 if(!*p)
229 return 0;
230
231 saved_p = p;
232 while(isdigit(*p))
233 p++;
234
235 /* no digits is a failure */
236 if(p == saved_p)
237 return 0;
238
239 /* ending now is ok - whole number (-1, +2, 3) */
240 if(!*p)
241 return 1;
242
243 /* .DIGITS is optional */
244 if(*p == '.') {
245 p++;
246 /* ending after . is not ok */
247 if(!*p)
248 return 0;
249
250 while(isdigit(*p))
251 p++;
252
253 /* ending with digits now is ok (-1.2, +2.3, 2.3) */
254 if(!*p)
255 return 1;
256 }
257
258 /* must be an exponent letter here (-1E... +2e... , -1.3E...,
259 * +2.4e..., 2E..., -4e...) */
260 if(*p != 'e' && *p != 'E')
261 return 0;
262 p++;
263
264 /* exponent: follows http://www.w3.org/TR/xmlschema-2/#integer */
265 if(*p == '-' || *p == '+')
266 p++;
267
268 saved_p = p;
269 while(isdigit(*p))
270 p++;
271 if(p == saved_p)
272 return 0;
273
274 if(*p)
275 return 0;
276
277 return 1;
278 }
279
280
281 /**
282 * rasqal_xsd_check_float_format:
283 * @string: lexical form string
284 * flags: flags
285 *
286 * INTERNAL - Check an XSD float lexical form
287 *
288 * Return value: non-0 if the string is valid
289 */
290 static int
rasqal_xsd_check_float_format(const unsigned char * string,int flags)291 rasqal_xsd_check_float_format(const unsigned char* string, int flags)
292 {
293 /* http://www.w3.org/TR/xmlschema-2/#float is the same as double */
294 return rasqal_xsd_check_double_format(string, flags);
295 }
296
297
298 /**
299 * rasqal_xsd_check_integer_format:
300 * @string: lexical form string
301 * flags: flags
302 *
303 * INTERNAL - Check an XSD integer lexical form
304 *
305 * Return value: non-0 if the string is valid
306 */
307 static int
rasqal_xsd_check_integer_format(const unsigned char * string,int flags)308 rasqal_xsd_check_integer_format(const unsigned char* string, int flags)
309 {
310 /* This should be correct according to
311 * http://www.w3.org/TR/xmlschema-2/#integer
312 */
313
314 /* Forbid empty string */
315 if(!*string)
316 return 0;
317
318 if(*string == '+' || *string == '-') {
319 string++;
320 /* Forbid "+" and "-" */
321 if(!*string)
322 return 0;
323 }
324
325 /* Digits */
326 for(;*string; string++) {
327 if(*string < '0' || *string > '9')
328 return 0;
329 }
330 return 1;
331 }
332
333
334 /**
335 * rasqal_xsd_format_integer:
336 * @i: integer
337 * @len_p: pointer to length of result or NULL
338 *
339 * INTERNAL - Format a C integer as a string in XSD decimal integer format.
340 *
341 * This is suitable for multiple XSD decimal integer types that are
342 * xsd:integer or sub-types such as xsd:short, xsd:int, xsd:long,
343 *
344 * See http://www.w3.org/TR/xmlschema-2/#built-in-datatypes for the full list.
345 *
346 * Return value: new string or NULL on failure
347 */
348 unsigned char*
rasqal_xsd_format_integer(int i,size_t * len_p)349 rasqal_xsd_format_integer(int i, size_t *len_p)
350 {
351 unsigned char* string;
352
353 /* Buffer sizes need to format:
354 * 4: 8 bit decimal integers (xsd:byte) "-128" to "127"
355 * 6: 16 bit decimal integers (xsd:short) "-32768" to "32767"
356 * 11: 32 bit decimal integers (xsd:int) "-2147483648" to "2147483647"
357 * 20: 64 bit decimal integers (xsd:long) "-9223372036854775808" to "9223372036854775807"
358 * (the lexical form may have leading 0s in non-canonical representations)
359 */
360 #define INTEGER_BUFFER_SIZE 20
361 string = RASQAL_MALLOC(unsigned char*, INTEGER_BUFFER_SIZE + 1);
362 if(!string)
363 return NULL;
364 /* snprintf() takes as length the buffer size including NUL */
365 snprintf(RASQAL_GOOD_CAST(char*, string), INTEGER_BUFFER_SIZE + 1, "%d", i);
366 if(len_p)
367 *len_p = strlen(RASQAL_GOOD_CAST(const char*, string));
368
369 return string;
370 }
371
372
373 /**
374 * rasqal_xsd_format_float:
375 * @i: float
376 * @len_p: pointer to length of result or NULL
377 *
378 * INTERNAL - Format a new an xsd:float correctly
379 *
380 * Return value: new string or NULL on failure
381 */
382 unsigned char*
rasqal_xsd_format_float(float f,size_t * len_p)383 rasqal_xsd_format_float(float f, size_t *len_p)
384 {
385 unsigned char* string;
386
387 /* FIXME: This is big enough for C float formatted in decimal as %1g */
388 #define FLOAT_BUFFER_SIZE 30
389 string = RASQAL_MALLOC(unsigned char*, FLOAT_BUFFER_SIZE + 1);
390 if(!string)
391 return NULL;
392 /* snprintf() takes as length the buffer size including NUL */
393 /* FIXME: %1g may not be the nearest to XSD xsd:float canonical format */
394 snprintf(RASQAL_GOOD_CAST(char*, string), FLOAT_BUFFER_SIZE + 1, "%1g", (double)f);
395 if(len_p)
396 *len_p = strlen(RASQAL_GOOD_CAST(const char*, string));
397
398 return string;
399 }
400
401
402 /**
403 * rasqal_xsd_format_double:
404 * @d: double
405 * @len_p: pointer to length of result or NULL
406 *
407 * INTERNAL - Format a new an xsd:double correctly
408 *
409 * Return value: new string or NULL on failure
410 */
411 unsigned char*
rasqal_xsd_format_double(double d,size_t * len_p)412 rasqal_xsd_format_double(double d, size_t *len_p)
413 {
414 unsigned int e_index = 0;
415 char have_trailing_zero = 0;
416 size_t trailing_zero_start = 0;
417 unsigned int exponent_start;
418 size_t len = 0;
419 unsigned char* buf = NULL;
420
421 len = 20;
422 buf = RASQAL_MALLOC(unsigned char*, len + 1);
423 if(!buf)
424 return NULL;
425
426 /* snprintf needs the length + 1 because it writes a \0 too */
427 snprintf(RASQAL_GOOD_CAST(char*, buf), len + 1, "%1.14E", d);
428
429 /* find the 'e' and start of mantissa trailing zeros */
430
431 for( ; buf[e_index]; ++e_index) {
432 if(e_index > 0 && buf[e_index] == '0' && buf[e_index - 1] != '0') {
433 trailing_zero_start = e_index;
434 have_trailing_zero = 1;
435 }
436
437 else if(buf[e_index] == 'E')
438 break;
439 }
440
441 if(have_trailing_zero) {
442 if(buf[trailing_zero_start - 1] == '.')
443 ++trailing_zero_start;
444
445 /* write an 'E' where the trailing zeros started */
446 buf[trailing_zero_start] = 'E';
447 if(buf[e_index + 1] == '-') {
448 buf[trailing_zero_start + 1] = '-';
449 ++trailing_zero_start;
450 }
451 } else {
452 buf[e_index] = 'E';
453 trailing_zero_start = e_index + 1;
454 have_trailing_zero = 1;
455 }
456
457 exponent_start = e_index + 2;
458 while(buf[exponent_start] == '0')
459 ++exponent_start;
460
461 if(have_trailing_zero) {
462 len = strlen(RASQAL_GOOD_CAST(const char*, buf));
463 if(exponent_start == len) {
464 len = trailing_zero_start + 2;
465 buf[len - 1] = '0';
466 buf[len] = '\0';
467 } else {
468 /* copy the exponent (minus leading zeros) after the new E */
469 memmove(buf + trailing_zero_start + 1, buf + exponent_start,
470 len - exponent_start + 1);
471 len = strlen(RASQAL_GOOD_CAST(const char*, buf));
472 }
473 }
474
475 if(len_p)
476 *len_p = len;
477
478 return buf;
479 }
480
481
482 typedef rasqal_literal* (*rasqal_extension_fn)(raptor_uri* name, raptor_sequence *args, char **error_p);
483
484
485 typedef struct {
486 const unsigned char *name;
487 int min_nargs;
488 int max_nargs;
489 rasqal_extension_fn fn;
490 raptor_uri* uri;
491 } rasqal_xsd_datatype_fn_info;
492
493
494 #define XSD_INTEGER_DERIVED_COUNT 12
495 #define XSD_INTEGER_DERIVED_FIRST (RASQAL_LITERAL_LAST_XSD + 1)
496 #define XSD_INTEGER_DERIVED_LAST (RASQAL_LITERAL_LAST_XSD + XSD_INTEGER_DERIVED_COUNT - 1)
497
498 #define XSD_DATE_OFFSET (XSD_INTEGER_DERIVED_LAST + 2)
499
500 /* atomic XSD literals + 12 types derived from xsd:integer plus DATE plus a NULL */
501 #define SPARQL_XSD_NAMES_COUNT (RASQAL_LITERAL_LAST_XSD + 1 + XSD_INTEGER_DERIVED_COUNT + 1)
502
503
504 static const char* const sparql_xsd_names[SPARQL_XSD_NAMES_COUNT + 1] =
505 {
506 NULL, /* RASQAL_LITERAL_UNKNOWN */
507 NULL, /* ...BLANK */
508 NULL, /* ...URI */
509 NULL, /* ...LITERAL */
510 "string",
511 "boolean",
512 "integer", /* may type-promote all the way to xsd:decimal */
513 "float",
514 "double",
515 "decimal",
516 "dateTime",
517 /* all of the following always type-promote to xsd:integer */
518 "nonPositiveInteger", "negativeInteger",
519 "long", "int", "short", "byte",
520 "nonNegativeInteger", "unsignedLong", "postiveInteger",
521 "unsignedInt", "unsignedShort", "unsignedByte",
522 /* RASQAL_LITERAL_DATE onwards (NOT next to dateTime) */
523 "date",
524 NULL
525 };
526
527 #define CHECKFNS_COUNT (RASQAL_LITERAL_LAST_XSD - RASQAL_LITERAL_FIRST_XSD + 2)
528 static int (*const sparql_xsd_checkfns[CHECKFNS_COUNT])(const unsigned char* string, int flags) =
529 {
530 NULL, /* RASQAL_LITERAL_XSD_STRING */
531 rasqal_xsd_check_boolean_format, /* RASQAL_LITERAL_BOOLEAN */
532 rasqal_xsd_check_integer_format, /* RASQAL_LITERAL_INTEGER */
533 rasqal_xsd_check_float_format, /* RASQAL_LITERAL_FLOAT */
534 rasqal_xsd_check_double_format, /* RASQAL_LITERAL_DOUBLE */
535 rasqal_xsd_check_decimal_format, /* RASQAL_LITERAL_DECIMAL */
536 rasqal_xsd_check_dateTime_format, /* RASQAL_LITERAL_DATETIME */
537 /* GAP */
538 rasqal_xsd_check_date_format /* RASQAL_LITERAL_DATE */
539 };
540
541 #define CHECKFN_DATE_OFFSET (RASQAL_LITERAL_DATETIME - RASQAL_LITERAL_FIRST_XSD + 1)
542
543
544 int
rasqal_xsd_init(rasqal_world * world)545 rasqal_xsd_init(rasqal_world* world)
546 {
547 int i;
548
549 world->xsd_namespace_uri = raptor_new_uri(world->raptor_world_ptr,
550 raptor_xmlschema_datatypes_namespace_uri);
551 if(!world->xsd_namespace_uri)
552 return 1;
553
554 world->xsd_datatype_uris = RASQAL_CALLOC(raptor_uri**, SPARQL_XSD_NAMES_COUNT + 1, sizeof(raptor_uri*));
555 if(!world->xsd_datatype_uris)
556 return 1;
557
558 for(i = RASQAL_LITERAL_FIRST_XSD; i < SPARQL_XSD_NAMES_COUNT; i++) {
559 const unsigned char* name = RASQAL_GOOD_CAST(const unsigned char*, sparql_xsd_names[i]);
560 world->xsd_datatype_uris[i] =
561 raptor_new_uri_from_uri_local_name(world->raptor_world_ptr,
562 world->xsd_namespace_uri, name);
563 if(!world->xsd_datatype_uris[i])
564 return 1;
565 }
566
567 return 0;
568 }
569
570
571 void
rasqal_xsd_finish(rasqal_world * world)572 rasqal_xsd_finish(rasqal_world* world)
573 {
574 if(world->xsd_datatype_uris) {
575 int i;
576
577 for(i = RASQAL_LITERAL_FIRST_XSD; i < SPARQL_XSD_NAMES_COUNT; i++) {
578 if(world->xsd_datatype_uris[i])
579 raptor_free_uri(world->xsd_datatype_uris[i]);
580 }
581
582 RASQAL_FREE(table, world->xsd_datatype_uris);
583 world->xsd_datatype_uris = NULL;
584 }
585
586 if(world->xsd_namespace_uri) {
587 raptor_free_uri(world->xsd_namespace_uri);
588 world->xsd_namespace_uri = NULL;
589 }
590 }
591
592
593
594 rasqal_literal_type
rasqal_xsd_datatype_uri_to_type(rasqal_world * world,raptor_uri * uri)595 rasqal_xsd_datatype_uri_to_type(rasqal_world* world, raptor_uri* uri)
596 {
597 int i;
598 rasqal_literal_type native_type = RASQAL_LITERAL_UNKNOWN;
599
600 if(!uri || !world->xsd_datatype_uris)
601 return native_type;
602
603 for(i = RASQAL_GOOD_CAST(int, RASQAL_LITERAL_FIRST_XSD); i <= RASQAL_GOOD_CAST(int, XSD_INTEGER_DERIVED_LAST); i++) {
604 if(raptor_uri_equals(uri, world->xsd_datatype_uris[i])) {
605 if(i >= XSD_INTEGER_DERIVED_FIRST)
606 native_type = RASQAL_LITERAL_INTEGER_SUBTYPE;
607 else
608 native_type = (rasqal_literal_type)i;
609 break;
610 }
611 }
612
613 if(native_type == RASQAL_LITERAL_UNKNOWN) {
614 /* DATE is not in the range FIRST_XSD .. INTEGER_DERIVED_LAST */
615 i = RASQAL_GOOD_CAST(int, XSD_DATE_OFFSET);
616 if(raptor_uri_equals(uri, world->xsd_datatype_uris[i]))
617 native_type = RASQAL_LITERAL_DATE;
618 }
619
620 return native_type;
621 }
622
623
624 raptor_uri*
rasqal_xsd_datatype_type_to_uri(rasqal_world * world,rasqal_literal_type type)625 rasqal_xsd_datatype_type_to_uri(rasqal_world* world, rasqal_literal_type type)
626 {
627 if(world->xsd_datatype_uris &&
628 ((type >= RASQAL_LITERAL_FIRST_XSD &&
629 type <= RASQAL_LITERAL_LAST_XSD) ||
630 type == RASQAL_LITERAL_DATE))
631 return world->xsd_datatype_uris[RASQAL_GOOD_CAST(int, type)];
632
633 return NULL;
634 }
635
636
637 /**
638 * rasqal_xsd_datatype_check:
639 * @native_type: rasqal XSD type
640 * @string: string
641 * @flags: check flags
642 *
643 * INTERNAL - check a string as a valid lexical form of an XSD datatype
644 *
645 * Return value: non-0 if the string is valid
646 */
647 int
rasqal_xsd_datatype_check(rasqal_literal_type native_type,const unsigned char * string,int flags)648 rasqal_xsd_datatype_check(rasqal_literal_type native_type,
649 const unsigned char* string, int flags)
650 {
651 /* calculate check function index in sparql_xsd_checkfns table */
652 int checkidx = -1;
653
654 if(native_type >= RASQAL_GOOD_CAST(int, RASQAL_LITERAL_FIRST_XSD) &&
655 native_type <= RASQAL_GOOD_CAST(int, RASQAL_LITERAL_LAST_XSD))
656 checkidx = RASQAL_GOOD_CAST(int, native_type - RASQAL_LITERAL_FIRST_XSD);
657 else if(native_type == RASQAL_LITERAL_DATE)
658 checkidx = CHECKFN_DATE_OFFSET;
659
660 /* test for index out of bounds and check function not defined */
661 if(checkidx < 0 || !sparql_xsd_checkfns[checkidx])
662 return 1;
663
664 return sparql_xsd_checkfns[checkidx](string, flags);
665 }
666
667
668 const char*
rasqal_xsd_datatype_label(rasqal_literal_type native_type)669 rasqal_xsd_datatype_label(rasqal_literal_type native_type)
670 {
671 return sparql_xsd_names[native_type];
672 }
673
674
675 int
rasqal_xsd_is_datatype_uri(rasqal_world * world,raptor_uri * uri)676 rasqal_xsd_is_datatype_uri(rasqal_world* world, raptor_uri* uri)
677 {
678 return (rasqal_xsd_datatype_uri_to_type(world, uri) != RASQAL_LITERAL_UNKNOWN);
679 }
680
681
682 int
rasqal_xsd_datatype_is_numeric(rasqal_literal_type type)683 rasqal_xsd_datatype_is_numeric(rasqal_literal_type type)
684 {
685 return ((type >= RASQAL_LITERAL_BOOLEAN && type <= RASQAL_LITERAL_DECIMAL) ||
686 (type == RASQAL_LITERAL_INTEGER_SUBTYPE));
687 }
688
689
690 static const rasqal_literal_type parent_xsd_type[RASQAL_LITERAL_LAST + 1] =
691 {
692 /* RASQAL_LITERAL_UNKNOWN */ RASQAL_LITERAL_UNKNOWN,
693 /* RDF Blank / RDF Term: Blank */
694 /* RASQAL_LITERAL_BLANK */ RASQAL_LITERAL_UNKNOWN,
695 /* RDF URI / RDF Term: URI */
696 /* RASQAL_LITERAL_URI */ RASQAL_LITERAL_UNKNOWN,
697 /* RDF Plain Literal / RDF Term: Literal */
698 /* RASQAL_LITERAL_STRING */ RASQAL_LITERAL_UNKNOWN,
699 /* XSD types / RDF Term Literal */
700 /* RASQAL_LITERAL_XSD_STRING */ RASQAL_LITERAL_UNKNOWN,
701 /* RASQAL_LITERAL_BOOLEAN */ RASQAL_LITERAL_INTEGER,
702 /* RASQAL_LITERAL_INTEGER */ RASQAL_LITERAL_FLOAT,
703 /* RASQAL_LITERAL_FLOAT */ RASQAL_LITERAL_DOUBLE,
704 /* RASQAL_LITERAL_DOUBLE */ RASQAL_LITERAL_DECIMAL,
705 /* RASQAL_LITERAL_DECIMAL */ RASQAL_LITERAL_UNKNOWN,
706 /* RASQAL_LITERAL_DATETIME */ RASQAL_LITERAL_UNKNOWN,
707 /* not datatypes */
708 /* RASQAL_LITERAL_UDT */ RASQAL_LITERAL_UNKNOWN,
709 /* RASQAL_LITERAL_PATTERN */ RASQAL_LITERAL_UNKNOWN,
710 /* RASQAL_LITERAL_QNAME */ RASQAL_LITERAL_UNKNOWN,
711 /* RASQAL_LITERAL_VARIABLE */ RASQAL_LITERAL_UNKNOWN,
712 /* RASQAL_LITERAL_INTEGER_SUBTYPE */ RASQAL_LITERAL_UNKNOWN,
713 /* RASQAL_LITERAL_DATE */ RASQAL_LITERAL_UNKNOWN
714 };
715
716 rasqal_literal_type
rasqal_xsd_datatype_parent_type(rasqal_literal_type type)717 rasqal_xsd_datatype_parent_type(rasqal_literal_type type)
718 {
719 if(type == RASQAL_LITERAL_INTEGER_SUBTYPE)
720 return RASQAL_LITERAL_INTEGER;
721
722 if((type >= RASQAL_LITERAL_FIRST_XSD && type <= RASQAL_LITERAL_LAST_XSD) ||
723 type == RASQAL_LITERAL_DATE)
724 return parent_xsd_type[type];
725
726 return RASQAL_LITERAL_UNKNOWN;
727 }
728
729 #endif /* not STANDALONE */
730
731
732 #ifdef STANDALONE
733 #include <stdio.h>
734
735 int main(int argc, char *argv[]);
736
737 #define N_VALID_TESTS 27
738 const char *double_valid_tests[N_VALID_TESTS+1] = {
739 "-INF", "INF",
740 "NaN",
741 "-0", "+0", "0",
742 "-12", "+12", "12",
743 "-12.34", "+12.34", "12.34",
744 "-1E4", "+1E4", "1267.43233E12", "-1267.43233E12", "12.78E-2",
745 "-1e4", "+1e4", "1267.43233e12", "-1267.43233e12", "12.78e-2",
746 "-1e0", "1e0", "1267.43233e0", "-1267.43233e0", "12.78e-0",
747 NULL
748 };
749
750 #define N_INVALID_TESTS 27
751 const char *double_invalid_tests[N_INVALID_TESTS+1] = {
752 "-inf", "inf", "+inf", "+INF",
753 "NAN", "nan",
754 "-0.", "+0.", "0.",
755 "-12.", "+12.", "12.",
756 "-E4", "E4", "+E4",
757 "-e4", "e4", "+e4",
758 "-1E", "+1E", "1E",
759 "-1e", "+1e", "1e",
760 "-1.E", "+1.E", "1.E",
761 NULL
762 };
763
764 int
main(int argc,char * argv[])765 main(int argc, char *argv[])
766 {
767 rasqal_world* world;
768 const char *program = rasqal_basename(argv[0]);
769 int failures = 0;
770 int test = 0;
771
772 world = rasqal_new_world();
773 if(!world || rasqal_world_open(world)) {
774 fprintf(stderr, "%s: rasqal_world init failed\n", program);
775 failures++;
776 goto tidy;
777 }
778
779 for(test = 0; test < N_VALID_TESTS; test++) {
780 const unsigned char *str;
781 str = RASQAL_GOOD_CAST(const unsigned char*, double_valid_tests[test]);
782
783 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
784 fprintf(stderr, "%s: Valid Test %3d value: %s\n", program, test, str);
785 #endif
786 if(!rasqal_xsd_check_double_format(str, 0 /* flags */)) {
787 fprintf(stderr, "%s: Valid Test %3d value: %s FAILED\n",
788 program, test, str);
789 failures++;
790 }
791 }
792
793 for(test = 0; test < N_INVALID_TESTS; test++) {
794 const unsigned char *str;
795 str = RASQAL_GOOD_CAST(const unsigned char*, double_invalid_tests[test]);
796
797 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
798 fprintf(stderr, "%s: Invalid Test %3d value: %s\n", program, test, str);
799 #endif
800 if(rasqal_xsd_check_double_format(str, 0 /* flags */)) {
801 fprintf(stderr,
802 "%s: Invalid Test %3d value: %s PASSED (expected failure)\n",
803 program, test, str);
804 failures++;
805 }
806 }
807
808 tidy:
809
810 rasqal_free_world(world);
811
812 return failures;
813 }
814 #endif /* STANDALONE */
815