Volksdata 1.0b10
RDF library
Loading...
Searching...
No Matches
term.c
Go to the documentation of this file.
1#include "volksdata/term.h"
2
3#define MAX_VALID_TERM_TYPE VOLK_TERM_BNODE /* For type validation. */
4
5
6/*
7 * Data structures.
8 */
9
11typedef struct keyed_term {
14} KeyedTerm;
15
16
22typedef struct link {
25} Link;
26
27
31 size_t i;
32 size_t j;
33 const Link * link;
34};
35
36
37/*
38 * A link map is thus nested:
39 *
40 * - A link map contains a hash map of Link instances (link).
41 * - It also contains the single term that the other terms are related to
42 * (linked_t).
43 * - Each Link contains a KeyedTerm (term) and a TermSet (tset).
44 * - Each term set is a hash map of KeyedTerm instances.
45 * - Each KeyedTerm contains a Term and its hash.
46 */
47typedef struct link_map {
50 struct hashmap *links;
52
53
54/*
55 * External variables.
56 */
57
62
63
64/*
65 * Static variables.
66 */
67
68// Characters not allowed in a URI string.
69static const char *invalid_uri_chars = "<>\" {}|\\^`";
70
72static const VOLK_TermType MIN_VALID_TYPE = VOLK_TERM_IRIREF;
74static const VOLK_TermType MAX_VALID_TYPE = VOLK_TERM_BNODE;
75
76/*
77 * Static prototypes.
78 */
79
80static VOLK_rc
81term_init (
82 VOLK_Term *term, VOLK_TermType type, const char *data, void *metadata);
83
84
85/*
86 * Term set callbacks.
87 */
88
89static uint64_t
90tset_hash_fn (
91 const void *item, uint64_t _unused, uint64_t _unused2)
92{
93 (void) _unused;
94 (void) _unused2;
95
96 return ((const KeyedTerm *) item)->key;
97}
98
99
100static int
101tset_cmp_fn (const void *a, const void *b, void *_unused)
102{
103 (void) _unused;
104
105 return
106 ((const KeyedTerm *) a)->key -
107 ((const KeyedTerm *) b)->key;
108}
109
110
111static void
112tset_free_fn (void *item)
113{ VOLK_term_free (((KeyedTerm *) item)->term); }
114
115
116/*
117 * Link map callbacks.
118 */
119
120static uint64_t
121link_map_hash_fn (
122 const void *item, uint64_t _unused, uint64_t _unused2)
123{
124 (void) _unused;
125 (void) _unused2;
126
127 return ((const Link *)item)->term->key;
128}
129
130
131static int
132link_map_cmp_fn (const void *a, const void *b, void *_unused)
133{
134 (void) _unused;
135
136 return
137 ((const Link *)a)->term->key -
138 ((const Link *)b)->term->key;
139}
140
141
142static void
143link_map_free_fn (void *item)
144{
145 Link *link = item;
146 VOLK_term_free (link->term->term);
147 free (link->term);
148 VOLK_term_set_free (link->tset);
149}
150
151
152 /*
153 * Term API.
154 */
155
156VOLK_Term *
158 VOLK_TermType type, const char *data, void *metadata)
159{
160 VOLK_Term *term;
161 CALLOC_GUARD (term, NULL);
162
163 if (UNLIKELY (term_init (
164 term, type, data, metadata) != VOLK_OK)) {
165 free (term);
166 return NULL;
167 }
168
169 return term;
170}
171
172
173VOLK_Term *
175{
176 switch (src->type) {
177 case VOLK_TERM_IRIREF:
178 return VOLK_iriref_new (src->data);
180 return VOLK_literal_new (src->data, src->datatype);
182 return VOLK_lt_literal_new (src->data, (char *) src->lang);
183 case VOLK_TERM_BNODE:
184 return VOLK_term_new (VOLK_TERM_BNODE, src->data, src->metadata);
185 default:
186 log_error ("Unsupported term type: %d", src->type);
187 return NULL;
188 }
189}
190
191
193VOLK_Term *
195{
196 if (UNLIKELY (!sterm)) return NULL;
197
198 VOLK_TermType type;
199 char *data;
200 void *metadata = NULL;
201
202 // Copy term type.
203 size_t cplen = sizeof (type);
204 char *cpcur = (char *)sterm->addr;
205 memcpy (&type, cpcur, cplen);
206
207 // Copy term data.
208 cpcur += cplen;
209 cplen = strlen (cpcur) + 1;
210 data = malloc (cplen);
211 NLNL (data);
212 memcpy (data, cpcur, cplen);
213
214 // If applicable, create term metadata.
215 cpcur += cplen;
216 if (type == VOLK_TERM_LITERAL) {
217 if (strlen(cpcur) > 0)
218 NLNL (metadata = (void *) VOLK_iriref_new (cpcur));
219 } else if (type == VOLK_TERM_LT_LITERAL) {
220 cplen = sizeof (VOLK_LangTag);
221 metadata = malloc (cplen);
222 NLNL (metadata);
223 memcpy (metadata, cpcur, cplen);
224 }
225
226 VOLK_Term *ret = VOLK_term_new (type, data, metadata);
227
228 free (data);
229 if (type == VOLK_TERM_LT_LITERAL) free (metadata);
230
231 return ret;
232}
233
234
235VOLK_Term *
236VOLK_iriref_new_abs (const VOLK_Term *root, const VOLK_Term *iri)
237{
238 if (iri->type != VOLK_TERM_IRIREF) {
239 log_error ("Provided path is not an IRI.");
240 return NULL;
241 }
242 if (root->type != VOLK_TERM_IRIREF) {
243 log_error ("Provided root is not an IRI.");
244 return NULL;
245 }
246
247 char
248 *data,
249 *pfx = VOLK_iriref_prefix (iri);
250
251 if (strlen (pfx) > 0) data = iri->data;
252
253 else if (iri->data[0] == '/') {
254 free (pfx);
255
256 pfx = VOLK_iriref_prefix (root);
257 data = malloc (strlen (iri->data) + strlen (pfx) + 1);
258 if (!data) return NULL;
259
260 sprintf (data, "%s%s", pfx, iri->data);
261
262 } else {
263 data = malloc (strlen (iri->data) + strlen (root->data) + 1);
264 if (!data) return NULL;
265
266 sprintf (data, "%s%s", root->data, iri->data);
267 }
268 free (pfx);
269
270 VOLK_Term *ret = VOLK_iriref_new (data);
271 if (data != iri->data) free (data);
272
273 return ret;
274}
275
276
277VOLK_Term *
278VOLK_iriref_new_rel (const VOLK_Term *root, const VOLK_Term *iri)
279{
280 if (iri->type != VOLK_TERM_IRIREF) {
281 log_error ("Provided path is not an IRI.");
282 return NULL;
283 }
284 if (root->type != VOLK_TERM_IRIREF) {
285 log_error ("Provided root is not an IRI.");
286 return NULL;
287 }
288
289 size_t offset = (
290 strstr (iri->data, root->data) == iri->data ?
291 strlen (root->data) : 0);
292
293 return VOLK_iriref_new (iri->data + offset);
294}
295
296
299{
300 /* The serialized data are a byte string (unsigned char *) formatted in
301 * the following way:
302 *
303 * - (unsigned char) term->type
304 * - (char *) NUL-delimited term->data
305 * - (char *) serialized metadata as byte string
306 *
307 * All fields are cast to uchar. The first field is fixed, the
308 * second and third are NUL-delimited, hence all fields are easily
309 * identifiable.
310 *
311 * Metadata are:
312 *
313 * - For VOLK_TERM_IRIREF, no data. IRI info is calculated on demand.
314 * - For VOLK_TERM_LITERAL, a `char` (`\1` or `\2`) indicating if a
315 * language tag is present, followed by the fully-qualified data type URI
316 * or the language tag, as a `NUL`-delimited string. For a `xsd:string`
317 * literal with no language, it is a zero-length string.
318 * - For VOLK_TERM_BNODE, no data. Skolemization ID is calculated on
319 * deserialization.
320 *
321 * In serializing a term, the fact that two terms of different types may
322 * be semantically identical must be taken into account. Specifically, a
323 * VOLK_TERM_LT_LITERAL with no language tag is identical to a
324 * VOLK_TERM_LITERAL of xsd:string type, made up of the same string. Such
325 * terms must have identical serializations.
326 */
327
328 if (UNLIKELY (!term)) return NULL;
329
330 VOLK_Buffer *sterm;
331 CALLOC_GUARD (sterm, NULL);
332
333 sterm->size = sizeof(VOLK_TermType) + strlen(term->data) + 1;
334 NLNL (sterm->addr = malloc (sterm->size));
335
336 // Copy term type.
337 size_t offset = 0;
338 size_t cplen = sizeof(term->type);
339 memcpy (sterm->addr, &term->type, cplen);
340
341 // Copy term data.
342 offset += cplen;
343 cplen = strlen (term->data) + 1;
344 memcpy (sterm->addr + offset, term->data, cplen);
345
346 // If applicable, copy literal metadata.
347 offset += cplen;
348 // Copy data type URI string or lang tag.
349 if (term->type == VOLK_TERM_LITERAL) {
350 // Non-language-tagged term.
351 // Don't store default datatype (xsd:string).
352 if (term->datatype == VOLK_default_datatype) {
353 NLNL (sterm->addr = realloc (sterm->addr, ++sterm->size));
354 sterm->addr[offset] = '\0';
355 }
356 else {
357 cplen = strlen (term->datatype->data) + 1;
358 sterm->size += cplen;
359 NLNL (sterm->addr = realloc (sterm->addr, sterm->size));
360 memcpy (
361 sterm->addr + offset, term->datatype->data, cplen);
362 }
363 } else if (term->type == VOLK_TERM_LT_LITERAL) {
364 // Language-tagged term.
365 cplen = sizeof (VOLK_LangTag);
366 sterm->size += cplen;
367 NLNL (sterm->addr = realloc (sterm->addr, sterm->size));
368 memcpy (sterm->addr + offset, &term->lang, sizeof (VOLK_LangTag));
369 }
370
371 return sterm;
372}
373
374
377{
378 VOLK_Buffer *buf;
379
380 if (UNLIKELY (!term)) buf = BUF_DUMMY;
381 else buf = VOLK_term_serialize (term);
382
383 VOLK_Key key = VOLK_buffer_hash (buf);
384
385 VOLK_buffer_free (buf);
386
387 return key;
388}
389
390
391void
393{
394 if (UNLIKELY (!term)) return;
395
396 free (term->data);
397 free (term);
398}
399
400
401char *
403{
404 if (iri->type != VOLK_TERM_IRIREF) {
405 log_error ("Term is not a IRI ref type.");
406 return NULL;
407 }
408
409 // if (iri->iri_info->prefix.size == 0) return NULL;
410 VOLK_IRIInfo iri_info;
411 RCNL (VOLK_parse_iri (iri->data, &iri_info));
412
413 return strndup (
414 iri->data + iri_info.prefix.offset, iri_info.prefix.size);
415}
416
417
418char *
420{
421 if (iri->type != VOLK_TERM_IRIREF) {
422 log_error ("Term is not a IRI ref type.");
423 return NULL;
424 }
425
426 // if (iri->iri_info->path.size == 0) return NULL;
427 VOLK_IRIInfo iri_info;
428 RCNL (VOLK_parse_iri (iri->data, &iri_info));
429
430 return strndup (iri->data + iri_info.path.offset, iri_info.path.size);
431}
432
433
434char *
436{
437 if (iri->type != VOLK_TERM_IRIREF) {
438 log_error ("Term is not a IRI ref type.");
439 return NULL;
440 }
441
442 // if (iri->iri_info->frag.size == 0) return NULL;
443 VOLK_IRIInfo iri_info;
444 RCNL (VOLK_parse_iri (iri->data, &iri_info));
445
446 return strndup (iri->data + iri_info.frag.offset, iri_info.frag.size);
447}
448
449
450/*
451 * Triple API.
452 */
453
456{
457 VOLK_Triple *spo = malloc (sizeof (*spo));
458 if (!spo) return NULL;
459
460 if (UNLIKELY (VOLK_triple_init (spo, s, p, o))) {
461 free (spo);
462 return NULL;
463 }
464
465 return spo;
466}
467
468
471{
472 VOLK_Triple *spo = malloc (sizeof (*spo));
473 if (!spo) return NULL;
474
475 spo->s = VOLK_term_new_from_buffer (sspo->s);
476 spo->p = VOLK_term_new_from_buffer (sspo->p);
477 spo->o = VOLK_term_new_from_buffer (sspo->o);
478
479 return spo;
480}
481
482
485{
486 VOLK_BufferTriple *sspo = malloc (sizeof (*sspo));
487 if (!sspo) return NULL;
488
489 sspo->s = VOLK_term_serialize (spo->s);
490 sspo->p = VOLK_term_serialize (spo->p);
491 sspo->o = VOLK_term_serialize (spo->o);
492
493 return sspo;
494}
495
496
499{
500 /* FIXME TRP_DUMMY is a problem here.
501 if (! VOLK_IS_IRI (s) && s->type != VOLK_TERM_BNODE) {
502 log_error ("Subject is not of a valid term type: %d", s->type);
503 return VOLK_VALUE_ERR;
504 }
505 if (! VOLK_IS_IRI (p)) {
506 log_error ("Predicate is not of a valid term type: %d", p->type);
507 return VOLK_VALUE_ERR;
508 }
509 */
510
511 spo->s = s;
512 spo->p = p;
513 spo->o = o;
514
515 return VOLK_OK;
516}
517
518
519void
521{
522 if (UNLIKELY (!spo)) return;
523
524 VOLK_term_free (spo->s);
525 VOLK_term_free (spo->p);
526 VOLK_term_free (spo->o);
527}
528
529
530void
532{
533 if (UNLIKELY (!spo)) return;
534
535 VOLK_term_free (spo->s);
536 VOLK_term_free (spo->p);
537 VOLK_term_free (spo->o);
538
539 free (spo);
540}
541
542
543/*
544 * Multi-add functions.
545 */
546
549{
550 // Capacity of 4 is an arbitrary guess.
551 VOLK_TermSet *ts = hashmap_new (
552 sizeof (KeyedTerm), 4, VOLK_HASH_SEED, 0,
553 tset_hash_fn, tset_cmp_fn, tset_free_fn, NULL);
554 if (UNLIKELY (hashmap_oom (ts))) return NULL;
555
556 return ts;
557}
558
559
562 VOLK_TermSet *ts, VOLK_Term *term, VOLK_Term **ins)
563{
564 VOLK_Hash key = VOLK_term_hash (term);
565 KeyedTerm entry_s = {.key = key, .term = term};
566
567 const KeyedTerm *ex = hashmap_get (ts, &entry_s);
568 if (ex) {
569 if (ins) *ins = ex->term;
570 if (term != ex->term) VOLK_term_free (term);
571 return VOLK_NOACTION;
572 }
573
574 hashmap_set (ts, &entry_s);
575 if (hashmap_oom (ts)) {
576 VOLK_term_free (term);
577 return VOLK_MEM_ERR;
578 }
579
580 if (ins) *ins = term;
581 return VOLK_OK;
582}
583
584
585const VOLK_Term *
587{
588 const KeyedTerm *entry = hashmap_get (ts, &(KeyedTerm){.key=key});
589 if (entry) log_trace ("ID found for key %lx: %s", key, entry->term->data);
590 else log_trace ("No ID found for key %lx.", key);
591
592 return (entry) ? entry->term : NULL;
593}
594
595
598{
599 KeyedTerm *kt = NULL;
600 if (!hashmap_iter (ts, i, (void **)&kt)) return VOLK_END;
601
602 if (term) *term = kt->term;
603
604 return VOLK_OK;
605}
606
607
608void
610{
611 if (UNLIKELY (!ts)) return;
612 hashmap_free (ts);
613}
614
615
618{
619 KeyedTerm kt_s = {.key = VOLK_term_hash (term)};
620
621 const KeyedTerm *res = hashmap_delete (ts, &kt_s);
622
623 if (res) {
624 VOLK_term_free (res->term);
625 return VOLK_OK;
626 }
627
628 return VOLK_NOACTION;
629}
630
631
632VOLK_Term *
634{
635 const KeyedTerm *kt = NULL;
636 size_t i = 0;
637 if (!hashmap_iter (ts, &i, (void **)&kt)) return NULL;
638
639 kt = hashmap_delete (ts, kt);
640
641 return kt->term;
642}
643
644
645size_t
647{ return hashmap_count (ts); }
648
649
651VOLK_link_map_new (const VOLK_Term *linked_term, VOLK_LinkType type)
652{
653 VOLK_LinkMap *lm;
654 MALLOC_GUARD (lm, NULL);
655 lm->type = type;
656 lm->links = hashmap_new (
657 sizeof (Link), 0, VOLK_HASH_SEED, 0,
658 link_map_hash_fn, link_map_cmp_fn, link_map_free_fn, NULL);
659 if (!linked_term) {
660 log_error ("term must not be NULL.");
661 free (lm);
662 return NULL;
663 }
664 lm->linked_t = VOLK_term_copy (linked_term);
665
666 return lm;
667}
668
669
670void
672{
673 hashmap_free (lm->links);
675 free (lm);
676}
677
678
681{ return map->type; }
682
683
684// TODO Memory error handling.
687 VOLK_LinkMap *lmap, VOLK_Term *term, VOLK_TermSet *tset)
688{
689 // Keyed term to look up the link term and insert it, if necessary.
690 KeyedTerm entry_s = {.key=VOLK_term_hash (term), .term=term};
691
692 const Link *ex = hashmap_get (lmap->links, &(Link){.term=&entry_s});
693 if (ex) {
694 // Add terms one by one to the existing term set.
695 log_trace (
696 "Linking term %s exists. Adding individual terms.",
697 ex->term->term->data);
698 size_t i = 0;
699 KeyedTerm *kt;
700 while (hashmap_iter (tset, &i, (void **)&kt)) {
701 log_trace (
702 "Adding term %s to link %s",
703 kt->term->data, ex->term->term->data);
704 if (hashmap_get (ex->tset, kt))
705 // Term already exist, free the new one and move on.
706 VOLK_term_free (kt->term);
707 else
708 // Insert KeyedTerm, the term set now owns the underlying term.
709 hashmap_set (ex->tset, kt);
710 }
711 // Free link term that hasn't been used.
712 VOLK_term_free (term);
713 } else {
714 // Add the new term and the termset wholesale.
715 log_trace ("Adding new linking term %s.", term->data);
716 // Allocate inserted member on heap, it will be owned by the map.
717 KeyedTerm *ins;
719 memcpy (ins, &entry_s, sizeof (entry_s));
720 Link link = {.term=ins, .tset=tset};
721 hashmap_set (lmap->links, &link);
722 }
723
724 return VOLK_OK;
725}
726
727
728VOLK_LinkMapIterator *
730{
731 VOLK_LinkMapIterator *it;
732 CALLOC_GUARD (it, NULL);
733 it->map = lmap;
734
735 return it;
736}
737
738
739// This leaves the link and link map references intact.
740void
741VOLK_link_map_iter_free (VOLK_LinkMapIterator *it) { free (it); }
742
743
746 VOLK_LinkMapIterator *it, VOLK_Term **lt, VOLK_TermSet **ts)
747{
748 if (!hashmap_iter (it->map->links, &it->i, (void **)&it->link))
749 return VOLK_END;
750
751 *lt = it->link->term->term;
752 *ts = it->link->tset;
753
754 return VOLK_OK;
755}
756
757
758// TODO dismantle if the only triple generator is for the graph.
761 VOLK_LinkMapIterator *it, VOLK_Triple *spo)
762{
763 // Assign external (related) term.
764 if (it->map->type == VOLK_LINK_INBOUND)
765 spo->o = it->map->linked_t;
766 else if (it->map->type == VOLK_LINK_OUTBOUND)
767 spo->s = it->map->linked_t;
768 else spo->p = it->map->linked_t;
769
770 KeyedTerm *kt;
771
772 // If we are already handling a link, continue the internal loop.
773 if (it->link) goto int_loop;
774ext_loop:
775 // Advance external counter and start new internal loop.
776 it->j = 0;
777 if (!hashmap_iter (it->map->links, &it->i, (void **)&it->link))
778 return VOLK_END;
779int_loop:
780 // If end of the term set is reached, start with a new linking term.
781 if (!hashmap_iter (it->link->tset, &it->j, (void **)&kt)) goto ext_loop;
782
783 // Continue pulling from term set.
784 // Assign linking term.
785 if (it->map->type == VOLK_LINK_EDGE) spo->s = it->link->term->term;
786 else spo->p = it->link->term->term;
787
788 // Assign term in term set.
789 if (it->map->type == VOLK_LINK_INBOUND) spo->s = kt->term;
790 else spo->o = kt->term;
791
792 return VOLK_OK;
793}
794
795
796/*
797 * Static functions.
798 */
799
800static VOLK_rc
801term_init (
802 VOLK_Term *term, VOLK_TermType type,
803 const char *data, void *metadata)
804{
805 // Exit early if environment is not initialized.
806 // EXCEPT for IRIRef which is used inside of VOLK_init().
807 if (!VOLK_env_is_init && type != VOLK_TERM_IRIREF)
808 return VOLK_ENV_ERR;
809
810 // Undefined type. Make quick work of it.
811 if (type == VOLK_TERM_UNDEFINED) {
812 term->type = type;
813 if (data) {
814 term->data = malloc (strlen (data) + 1);
815 if (UNLIKELY (!term->data)) return VOLK_MEM_ERR;
816 strcpy (term->data, data);
817 }
818 return VOLK_OK;
819 }
820
821 if (type < MIN_VALID_TYPE || type > MAX_VALID_TYPE) {
822 log_error ("%d is not a valid term type.", type);
823 return VOLK_VALUE_ERR;
824 }
825
826 term->type = type;
827
828 if (data) {
829 // Validate IRI.
830 if (term->type == VOLK_TERM_IRIREF) {
831 if (strpbrk (data, invalid_uri_chars) != NULL) {
832 log_warn (
833 "Characters %s are not valid in a URI. Got: %s\n",
834 invalid_uri_chars, data);
835#if 0
836 // TODO This causes W3C TTL test #29 to fail. Remove?
837 return VOLK_VALUE_ERR;
838#endif
839 }
840 }
841 term->data = strdup (data);
842
843 } else {
844 // No data. Make up a random UUID or URI if allowed.
845 if (type == VOLK_TERM_IRIREF || type == VOLK_TERM_BNODE) {
846 uuid_t uuid;
847 uuid_generate_random (uuid);
848
849 uuid_str_t uuid_str;
850 uuid_unparse_lower (uuid, uuid_str);
851
852 if (type == VOLK_TERM_IRIREF) {
853 term->data = malloc (UUID4_URN_SIZE);
854 snprintf (
855 term->data, UUID4_URN_SIZE, "urn:uuid:%s", uuid_str);
856 } else term->data = strdup (uuid_str);
857 } else {
858 log_error ("No data provided for term.");
859 return VOLK_VALUE_ERR;
860 }
861 }
862
863 if (term->type == VOLK_TERM_LT_LITERAL) {
864 if (!metadata) {
865 log_warn ("Lang tag is NULL. Creating a non-tagged literal.");
866 term->type = VOLK_TERM_LITERAL;
867 } else {
868 // FIXME metadata should be const all across.
869 char *lang_str = (char *) metadata;
870 log_trace ("Lang string: '%s'", lang_str);
871 // Lang tags longer than 7 characters will be truncated.
872 strncpy(term->lang, lang_str, sizeof (term->lang) - 1);
873 if (strlen (term->lang) < 1) {
874 log_error ("Lang tag cannot be an empty string.");
875 return VOLK_VALUE_ERR;
876 }
877 term->lang[7] = '\0';
878 }
879 }
880
881 // This also captures a LT_LITERAL with no lang tag.
882 if (term->type == VOLK_TERM_LITERAL) {
883 term->datatype = metadata ? metadata : VOLK_default_datatype;
884
885 if (term->datatype->type != VOLK_TERM_IRIREF) {
886 log_error (
887 "Literal data type is not an IRI: %s",
888 term->datatype->data);
889
890 return VOLK_VALUE_ERR;
891 }
892
894 VOLK_term_cache, term->datatype, &term->datatype));
895
896 } else if (term->type == VOLK_TERM_BNODE) {
897 // TODO This is not usable for global skolemization.
898 term->bnode_id = VOLK_HASH (
899 term->data, strlen (term->data) + 1, VOLK_HASH_SEED);
900 }
901
902 return VOLK_OK;
903}
904
905
907VOLK_parse_iri (char *iri_str, VOLK_IRIInfo *iri_info) {
908 char *cur = iri_str;
909 size_t iri_len = strlen (iri_str);
910 MatchCoord tmp = {}; // Temporary storage for capture groups
911
912 memset (iri_info, 0, sizeof (*iri_info));
913 //log_debug ("Parsing IRI: %s", iri_str);
914 // #2: ([^:/?#]+)
915 while (
916 *cur != ':' && *cur != '/' && *cur != '?'
917 && *cur != '#' && *cur != '\0') {
918 tmp.size++;
919 cur++;
920 }
921
922 // Non-capturing: (?([^:/?#]+):)?
923 if (tmp.size > 0 && *cur == ':') {
924 // Got capture groups #2 and #3. Store them.
925 iri_info->scheme.offset = 0;
926 iri_info->scheme.size = tmp.size;
927 cur++;
928 //log_debug ("Group #2: %lu, %lu", coord[2].offset, coord[2].size);
929 } else cur = iri_str; // Backtrack if no match.
930
931 // Non-capturing: (?//([^/?#]*))?
932 if (*cur == '/' && *(cur + 1) == '/') {
933 cur += 2;
934 tmp.offset = cur - iri_str;
935 tmp.size = 0;
936
937 // #3: ([^/?#]*)
938 while (*cur != '/' && *cur != '?' && *cur != '#' && *cur != '\0') {
939 tmp.size++;
940 cur++;
941 }
942 iri_info->auth.offset = tmp.offset;
943 iri_info->auth.size = tmp.size;
944 //log_debug ("Group #3: %lu, %lu", coord[3].offset, coord[3].size);
945 }
946
947 // Capture group 1.
948 iri_info->prefix.offset = 0;
949 iri_info->prefix.size = cur - iri_str;
950 //log_debug ("Group #1: %lu, %lu", coord[1].offset, coord[1].size);
951
952 tmp.offset = cur - iri_str;
953 tmp.size = 0;
954
955 iri_info->path.offset = tmp.offset;
956 iri_info->path.size = iri_len - tmp.offset;
957 //log_debug ("Group #4: %lu, %lu", coord[4].offset, coord[4].size);
958
959 // Non-capturing: (?[^?#]*)
960 while (*cur != '?' && *cur != '#' && *cur != '\0') {
961 tmp.size++;
962 cur++;
963 }
964
965 // Non-capturing: (?\?([^#]*))
966 if (*cur == '?') {
967 // 5: ([^#]*)
968 tmp.offset = ++cur - iri_str;
969 tmp.size = 0;
970 while (*cur != '#' && *cur != '\0') {
971 tmp.size++;
972 cur++;
973 }
974
975 if (tmp.size > 0) {
976 // Got capture group #5.
977 iri_info->query.offset = tmp.offset;
978 iri_info->query.size = tmp.size;
979 //log_debug ("Group #5: %lu, %lu", coord[5].offset, coord[5].size);
980 }
981 }
982
983 // Non-capturing: (?#(.*))?
984 if (*cur == '#') {
985 // #6: (.*)
986 iri_info->frag.offset = ++cur - iri_str;
987 iri_info->frag.size = iri_str + iri_len - cur;
988 //log_debug ("Group #6: %lu, %lu", coord[6].offset, coord[6].size);
989 }
990
991 /* TODO add error cases.
992 if (UNLIKELY (rc != VOLK_OK)) {
993 log_error ("Error matching URI pattern.");
994
995 return VOLK_VALUE_ERR;
996 }
997 */
998
999 return VOLK_OK;
1000}
1001
1002
1003/*
1004 * Extern inline functions.
1005 */
1006
1007VOLK_Key VOLK_term_hash (const VOLK_Term *term);
1008VOLK_Term *VOLK_iriref_new (const char *data);
1009VOLK_Term *VOLK_iriref_new_ns (const char *data);
1010VOLK_Term *VOLK_literal_new (const char *data, VOLK_Term *datatype);
1011VOLK_Term *VOLK_lt_literal_new (const char *data, char *lang);
1012VOLK_Term *VOLK_bnode_new (const char *data);
1013bool VOLK_term_equals (const VOLK_Term *term1, const VOLK_Term *term2);
#define UNLIKELY(x)
Definition core.h:39
#define VOLK_HASH_SEED
Seed used for all hashing. Compile-time configurable.
Definition core.h:189
VOLK_Hash64 VOLK_Hash
Default hash data type.
Definition core.h:228
bool VOLK_env_is_init
Whether the environment is initialized.
Definition core.c:11
#define VOLK_HASH(...)
Default hashing function. Depends on architecture.
Definition core.h:200
#define MALLOC_GUARD(var, rc)
Allocate one pointer with malloc and return rc if it fails.
Definition core.h:409
#define RCNL(exp)
Return NULL if exp returns a nonzero value.
Definition core.h:379
#define NLNL(exp)
Log error and return NULL if exp is NULL.
Definition core.h:401
#define CALLOC_GUARD(var, rc)
Allocate one pointer with calloc and return rc if it fails.
Definition core.h:415
#define PRCCK(exp)
Return exp return value if it is of VOLK_rc type and negative (=error).
Definition core.h:358
#define log_trace(...)
Definition core.h:296
char * strdup(const char *src)
Replacement for GNU strdup.
Definition core.c:109
char * strndup(const char *src, size_t max)
Replacement for GNU strndup.
Definition core.c:92
#define VOLK_VALUE_ERR
An invalid input value was provided.
Definition core.h:141
#define VOLK_MEM_ERR
Memory allocation error.
Definition core.h:156
#define VOLK_END
Loop end.
Definition core.h:119
#define VOLK_OK
Generic success return code.
Definition core.h:95
#define VOLK_NOACTION
No action taken.
Definition core.h:105
int VOLK_rc
Return code.
Definition core.h:91
#define VOLK_ENV_ERR
Error while handling environment setup; or environment not initialized.
Definition core.h:170
VOLK_Key VOLK_triple_hash(const VOLK_Triple *trp)
Hash a triple.
Definition term.h:515
VOLK_Term * VOLK_lt_literal_new(const char *data, char *lang)
Shortcut to create a language-tagged literal term.
Definition term.h:317
VOLK_Triple * VOLK_triple_new_from_btriple(const VOLK_BufferTriple *sspo)
Definition term.c:470
struct hashmap VOLK_TermSet
a set of unique terms.
Definition term.h:123
VOLK_rc VOLK_term_set_next(VOLK_TermSet *ts, size_t *i, VOLK_Term **term)
Iterate trough a term set.
Definition term.c:597
VOLK_Triple * VOLK_triple_new(VOLK_Term *s, VOLK_Term *p, VOLK_Term *o)
Create a new triple from three terms.
Definition term.c:455
char * VOLK_iriref_frag(const VOLK_Term *iri)
Get the fragment portion of a IRI ref.
Definition term.c:435
VOLK_Term * VOLK_iriref_new_rel(const VOLK_Term *root, const VOLK_Term *iri)
Create a new relative IRI from an absolute IRI and a web root IRI.
Definition term.c:278
VOLK_rc VOLK_parse_iri(char *iri_str, VOLK_IRIInfo *iri_info)
scan an IRI string and parse IRI parts.
Definition term.c:907
void VOLK_link_map_iter_free(VOLK_LinkMapIterator *it)
Free a link map iterator.
Definition term.c:741
VOLK_LinkType
Link type.
Definition term.h:93
VOLK_Term * VOLK_iriref_new(const char *data)
Create an IRI reference.
Definition term.h:191
VOLK_TermType
Term type.
Definition term.h:30
bool VOLK_term_equals(const VOLK_Term *term1, const VOLK_Term *term2)
Compare two terms.
Definition term.h:379
size_t VOLK_term_set_size(VOLK_TermSet *ts)
Size of a term set.
Definition term.c:646
VOLK_rc VOLK_term_set_remove(VOLK_TermSet *ts, VOLK_Term *term)
Remove a specific term from a term set.
Definition term.c:617
VOLK_Term * VOLK_iriref_new_abs(const VOLK_Term *root, const VOLK_Term *iri)
Create a new absolute IRI from a path relative to a root IRI.
Definition term.c:236
VOLK_Term * VOLK_literal_new(const char *data, VOLK_Term *datatype)
Shortcut to create a literal term.
Definition term.h:266
VOLK_LinkMapIterator * VOLK_link_map_iter_new(const VOLK_LinkMap *lmap)
Create a new iterator to loop through a link map.
Definition term.c:729
char * VOLK_iriref_prefix(const VOLK_Term *iri)
Get the prefix portion of a IRI ref.
Definition term.c:402
VOLK_LinkMap * VOLK_link_map_new(const VOLK_Term *linked_term, VOLK_LinkType type)
New link map.
Definition term.c:651
VOLK_Term * VOLK_default_datatype
Default literal data type URI.
Definition term.c:60
VOLK_rc VOLK_link_map_triples(VOLK_LinkMapIterator *it, VOLK_Triple *spo)
Iterate over a link map and generate triples.
Definition term.c:760
void VOLK_triple_done(VOLK_Triple *spo)
Free the internal pointers of a triple.
Definition term.c:520
VOLK_rc VOLK_triple_init(VOLK_Triple *spo, VOLK_Term *s, VOLK_Term *p, VOLK_Term *o)
Initialize internal term pointers in a heap-allocated triple.
Definition term.c:498
const VOLK_Term * VOLK_term_set_get(VOLK_TermSet *ts, VOLK_Key key)
Get a term from a term set.
Definition term.c:586
VOLK_Term * VOLK_bnode_new(const char *data)
Shortcut to create a blank node.
Definition term.h:331
VOLK_TermSet * VOLK_term_set_new()
Create a new term set.
Definition term.c:548
uint32_t VOLK_default_dtype_key
Compiled hash of default literal data type.
Definition term.c:58
void VOLK_term_set_free(VOLK_TermSet *ts)
Free a term set.
Definition term.c:609
VOLK_Key VOLK_term_hash(const VOLK_Term *term)
Hash a buffer.
Definition term.c:376
VOLK_rc VOLK_link_map_next(VOLK_LinkMapIterator *it, VOLK_Term **lt, VOLK_TermSet **ts)
Iterate through a link map.
Definition term.c:745
void VOLK_link_map_free(VOLK_LinkMap *lm)
Free a link map.
Definition term.c:671
VOLK_Term * VOLK_iriref_new_ns(const char *data)
Create an IRI reference from a namespace-prefixed string.
Definition term.h:204
#define UUID4_URN_SIZE
Definition term.h:13
char * VOLK_iriref_path(const VOLK_Term *iri)
Get the path portion of a IRI ref.
Definition term.c:419
char VOLK_LangTag[8]
Language tag, currently restricted to 7 characters.
Definition term.h:27
void VOLK_term_free(VOLK_Term *term)
Definition term.c:392
VOLK_Term * VOLK_triple_pos(const VOLK_Triple *trp, VOLK_TriplePos n)
Get triple by term position.
Definition term.h:501
VOLK_Buffer * VOLK_term_serialize(const VOLK_Term *term)
Serialize a term into a buffer.
Definition term.c:298
VOLK_Term * VOLK_default_ctx
Default context.
Definition term.c:59
VOLK_Term * VOLK_term_new_from_buffer(const VOLK_Buffer *sterm)
See notes in VOLK_term_serialize function body for format info.
Definition term.c:194
VOLK_rc VOLK_link_map_add(VOLK_LinkMap *lmap, VOLK_Term *term, VOLK_TermSet *tset)
Add a term - term set pair to a link map.
Definition term.c:686
VOLK_Term * VOLK_term_set_pop(VOLK_TermSet *ts)
Pop a term from a term set.
Definition term.c:633
VOLK_rc VOLK_term_set_add(VOLK_TermSet *ts, VOLK_Term *term, VOLK_Term **ins)
Add term to a term set.
Definition term.c:561
VOLK_LinkType VOLK_link_map_type(const VOLK_LinkMap *map)
Return the link map type.
Definition term.c:680
VOLK_BufferTriple * VOLK_triple_serialize(const VOLK_Triple *spo)
Definition term.c:484
VOLK_Term * VOLK_term_new(VOLK_TermType type, const char *data, void *metadata)
Create a new term.
Definition term.c:157
VOLK_TermSet * VOLK_term_cache
Global term cache.
Definition term.c:61
void VOLK_triple_free(VOLK_Triple *spo)
Free a triple and all its internal pointers.
Definition term.c:531
VOLK_Term * VOLK_term_copy(const VOLK_Term *src)
Copy a term.
Definition term.c:174
@ VOLK_LINK_EDGE
Edge link (so).
Definition term.h:96
@ VOLK_LINK_INBOUND
Inbound link (sp).
Definition term.h:94
@ VOLK_LINK_OUTBOUND
Outbound link (po).
Definition term.h:95
@ VOLK_TERM_IRIREF
IRI reference.
Definition term.h:34
@ VOLK_TERM_UNDEFINED
Definition term.h:31
@ VOLK_TERM_LT_LITERAL
Language-tagged string literal.
Definition term.h:36
@ VOLK_TERM_LITERAL
Literal without language tag.
Definition term.h:35
@ VOLK_TERM_BNODE
Blank node.
Definition term.h:37
VOLK_Key VOLK_buffer_hash(const VOLK_Buffer *buf)
Hash a buffer.
Definition buffer.h:175
VOLK_TriplePos
Triple position of s, p, o.
Definition buffer.h:19
#define BUF_DUMMY
Dummy buffer to be used with VOLK_buffer_init.
Definition buffer.h:154
void VOLK_buffer_free(VOLK_Buffer *buf)
Free a buffer.
Definition buffer.c:97
size_t VOLK_Key
Term key, i.e., hash of a serialized term.
Definition core.h:244
char uuid_str_t[37]
UUID string tpe.
Definition core.h:253
Key-term pair in term set.
Definition term.c:11
VOLK_Term * term
Term handle.
Definition term.c:13
VOLK_Key key
Key (hash) of the term.
Definition term.c:12
Match coordinates in IRI parsing results.
Definition term.h:41
unsigned int size
Length of match.
Definition term.h:43
unsigned int offset
Offset of match from start of string.
Definition term.h:42
Triple of byte buffers.
Definition buffer.h:60
VOLK_Buffer * o
Definition buffer.h:63
VOLK_Buffer * s
Definition buffer.h:61
VOLK_Buffer * p
Definition buffer.h:62
General-purpose data buffer.
Definition buffer.h:47
unsigned char * addr
Definition buffer.h:48
size_t size
Definition buffer.h:49
Matching sub-patterns for IRI parts.
Definition term.h:47
MatchCoord frag
Fragment (frag).
Definition term.h:54
MatchCoord auth
Authority (example.org).
Definition term.h:50
MatchCoord query
Query (query=blah).
Definition term.h:53
MatchCoord prefix
Prefix (http://example.org).
Definition term.h:48
MatchCoord path
Definition term.h:51
MatchCoord scheme
Scheme (http).
Definition term.h:49
VOLK_Term * linked_t
Linked term.
Definition term.c:49
VOLK_LinkType type
Link type.
Definition term.c:48
struct hashmap * links
Map of Link instances.
Definition term.c:50
RDF term.
Definition term.h:61
VOLK_Key bnode_id
BN ID for comparison & skolemization.
Definition term.h:66
void * metadata
Generic metadata pointer.
Definition term.h:67
char * data
URI, literal value, or BNode label.
Definition term.h:62
struct term_t * datatype
Data type IRI for VOLK_TERM_LITERAL.
Definition term.h:64
VOLK_TermType type
Term type.
Definition term.h:69
VOLK_LangTag lang
Lang tag for VOLK_TERM_LT_LITERAL.
Definition term.h:65
RDF triple.
Definition term.h:85
VOLK_Term * p
Predicate.
Definition term.h:87
VOLK_Term * s
Subject.
Definition term.h:86
VOLK_Term * o
Object.
Definition term.h:88