1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rdf_init.c - Redland library initialisation / termination and memory
4 * management
5 *
6 * Copyright (C) 2000-2012, David Beckett http://www.dajobe.org/
7 * Copyright (C) 2000-2005, University of Bristol, UK http://www.bristol.ac.uk/
8 *
9 * This package is Free Software and part of Redland http://librdf.org/
10 *
11 * It is licensed under the following three licenses as alternatives:
12 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
13 * 2. GNU General Public License (GPL) V2 or any newer version
14 * 3. Apache License, V2.0 or any newer version
15 *
16 * You may not use this file except in compliance with at least one of
17 * the above three licenses.
18 *
19 * See LICENSE.html or LICENSE.txt at the top of this package for the
20 * complete terms and further detail along with the license texts for
21 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
22 *
23 *
24 */
25
26
27 #ifdef HAVE_CONFIG_H
28 #include <rdf_config.h>
29 #endif
30
31 #ifdef WIN32
32 #include <win32_rdf_config.h>
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef WITH_THREADS
38 #include <pthread.h>
39 #endif
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h> /* for getpid() */
45 #endif
46
47 /* for gettimeofday */
48 #if TIME_WITH_SYS_TIME
49 #include <sys/time.h>
50 #include <time.h>
51 #else
52 #if HAVE_SYS_TIME_H
53 #include <sys/time.h>
54 #else
55 #include <time.h>
56 #endif
57 #endif
58
59 #include <redland.h>
60 /* for getpid */
61 #include <sys/types.h>
62 #ifdef HAVE_UNISTD
63 #include <unistd.h>
64 #endif
65
66 #ifdef MODULAR_LIBRDF
67 #include <ltdl.h>
68 #endif
69
70 #ifndef STANDALONE
71
72 const char * const librdf_short_copyright_string = "Copyright 2000-2012 David Beckett. Copyright 2000-2005 University of Bristol";
73
74 const char * const librdf_copyright_string = "Copyright (C) 2000-2012 David Beckett - http://www.dajobe.org/\nCopyright (C) 2000-2005 University of Bristol - http://www.bristol.ac.uk/";
75
76 const char * const librdf_license_string = "LGPL 2.1 or newer, GPL 2 or newer, Apache 2.0 or newer.\nSee http://librdf.org/LICENSE.html for full terms.";
77
78 const char * const librdf_home_url_string = "http://librdf.org/";
79
80
81 /**
82 * librdf_version_string:
83 *
84 * Library full version as a string.
85 *
86 * See also #librdf_version_decimal.
87 */
88 const char * const librdf_version_string = VERSION;
89
90 /**
91 * librdf_version_major:
92 *
93 * Library major version number as a decimal integer.
94 */
95 const unsigned int librdf_version_major = LIBRDF_VERSION_MAJOR;
96
97 /**
98 * librdf_version_minor:
99 *
100 * Library minor version number as a decimal integer.
101 */
102 const unsigned int librdf_version_minor = LIBRDF_VERSION_MINOR;
103
104 /**
105 * librdf_version_release:
106 *
107 * Library release version number as a decimal integer.
108 */
109 const unsigned int librdf_version_release = LIBRDF_VERSION_RELEASE;
110
111 /**
112 * librdf_version_decimal:
113 *
114 * Library full version as a decimal integer.
115 *
116 * See also #librdf_version_string.
117 */
118 const unsigned int librdf_version_decimal = LIBRDF_VERSION_DECIMAL;
119
120
121
122
123 /**
124 * librdf_new_world:
125 *
126 * Create a new Redland execution environment.
127 *
128 * Once this constructor is called to build a #librdf_world object
129 * several functions may be called to set some parameters such as
130 * librdf_world_set_error(), librdf_world_set_warning(),
131 * librdf_world_set_logger(), librdf_world_set_digest(),
132 * librdf_world_set_feature().
133 *
134 * The world object needs initializing using librdf_world_open()
135 * whether or not the above functions are called. It will be
136 * automatically called by all object constructors in Redland 1.0.6
137 * or later, but for earlier versions it MUST be called before using
138 * any other part of Redland.
139 *
140 * Returns: a new #librdf_world or NULL on failure
141 */
142 librdf_world*
librdf_new_world(void)143 librdf_new_world(void)
144 {
145 librdf_world *world;
146 #ifdef HAVE_GETTIMEOFDAY
147 struct timeval tv;
148 struct timezone tz;
149 #endif
150
151 world = LIBRDF_CALLOC(librdf_world*, 1, sizeof(*world));
152
153 if(!world)
154 return NULL;
155
156 #ifdef HAVE_GETTIMEOFDAY
157 if(!gettimeofday(&tv, &tz)) {
158 world->genid_base = LIBRDF_GOOD_CAST(unsigned long, tv.tv_sec);
159 } else
160 world->genid_base = 1;
161 #else
162 world->genid_base = 1;
163 #endif
164 world->genid_counter = 1;
165
166 #ifdef MODULAR_LIBRDF
167 world->ltdl_opened = !(lt_dlinit());
168 if (world->ltdl_opened)
169 lt_dlsetsearchpath(REDLAND_MODULE_PATH);
170 #ifdef LIBRDF_DEBUG
171 else
172 LIBRDF_DEBUG1("lt_dlinit() failed\n");
173 #endif
174 #endif
175
176 return world;
177
178 }
179
180
181 /**
182 * librdf_free_world:
183 * @world: redland world object
184 *
185 * Terminate the library and frees all allocated resources.
186 **/
187 void
librdf_free_world(librdf_world * world)188 librdf_free_world(librdf_world *world)
189 {
190 if(!world)
191 return;
192
193 librdf_finish_serializer(world);
194 librdf_finish_parser(world);
195
196 librdf_finish_storage(world);
197 librdf_finish_query(world);
198 librdf_finish_model(world);
199 librdf_finish_statement(world);
200
201 librdf_finish_concepts(world);
202
203 librdf_finish_node(world);
204 librdf_finish_uri(world);
205
206 /* Uses rdf_hash so free before destroying hashes */
207 librdf_finish_raptor(world);
208
209 librdf_finish_hash(world);
210
211 librdf_finish_digest(world);
212
213 #ifdef WITH_THREADS
214
215 if(world->hash_datums_mutex) {
216 pthread_mutex_destroy(world->hash_datums_mutex);
217 SYSTEM_FREE(world->hash_datums_mutex);
218 world->hash_datums_mutex = NULL;
219 }
220
221 if(world->statements_mutex) {
222 pthread_mutex_destroy(world->statements_mutex);
223 SYSTEM_FREE(world->statements_mutex);
224 world->statements_mutex = NULL;
225 }
226
227 if(world->nodes_mutex) {
228 pthread_mutex_destroy(world->nodes_mutex);
229 SYSTEM_FREE(world->nodes_mutex);
230 world->nodes_mutex = NULL;
231 }
232
233 if(world->mutex) {
234 pthread_mutex_destroy(world->mutex);
235 SYSTEM_FREE(world->mutex);
236 world->mutex = NULL;
237 }
238
239
240 #endif
241
242 #ifdef MODULAR_LIBRDF
243 if (world->ltdl_opened)
244 lt_dlexit();
245 #endif
246
247 LIBRDF_FREE(librdf_world, world);
248 }
249
250
251 /**
252 * librdf_world_init_mutex:
253 * @world: redland world object
254 *
255 * INTERNAL - Create the world mutex.
256 */
257 void
librdf_world_init_mutex(librdf_world * world)258 librdf_world_init_mutex(librdf_world* world)
259 {
260 #ifdef WITH_THREADS
261 world->mutex = (pthread_mutex_t *) SYSTEM_MALLOC(sizeof(pthread_mutex_t));
262 pthread_mutex_init(world->mutex, NULL);
263
264 world->nodes_mutex = (pthread_mutex_t *) SYSTEM_MALLOC(sizeof(pthread_mutex_t));
265 pthread_mutex_init(world->nodes_mutex, NULL);
266
267 world->statements_mutex = (pthread_mutex_t *) SYSTEM_MALLOC(sizeof(pthread_mutex_t));
268 pthread_mutex_init(world->statements_mutex, NULL);
269
270 world->hash_datums_mutex = (pthread_mutex_t *) SYSTEM_MALLOC(sizeof(pthread_mutex_t));
271 pthread_mutex_init(world->hash_datums_mutex, NULL);
272
273 #else
274 #endif
275 }
276
277
278 /**
279 * librdf_world_open:
280 * @world: redland world object
281 *
282 * Open a created redland world environment.
283 **/
284 void
librdf_world_open(librdf_world * world)285 librdf_world_open(librdf_world *world)
286 {
287 int rc = 0;
288
289 if(world->opened++)
290 return;
291
292 librdf_world_init_mutex(world);
293
294 /* Digests second, lots of things use these */
295 librdf_init_digest(world);
296
297 /* Hash next, needed for URIs */
298 librdf_init_hash(world);
299
300 /* Initialize raptor; uses rdf_hash for bnode mapping */
301 librdf_init_raptor(world);
302
303 librdf_init_uri(world);
304 librdf_init_node(world);
305
306 librdf_init_concepts(world);
307
308 librdf_init_statement(world);
309 librdf_init_model(world);
310 librdf_init_storage(world);
311
312 librdf_init_parser(world);
313 librdf_init_serializer(world);
314
315 rc = librdf_init_query(world);
316 if(rc)
317 goto failed;
318
319 return;
320
321 failed:
322 /* should return an error state */
323 return;
324 }
325
326
327 /**
328 * librdf_world_set_rasqal:
329 * @world: librdf_world object
330 * @rasqal_world_ptr: rasqal_world object
331 *
332 * Set the #rasqal_world instance to be used with this #librdf_world.
333 *
334 * If no rasqal_world instance is set with this function,
335 * librdf_world_open() creates a new instance.
336 *
337 * Ownership of the rasqal_world is not taken. If the rasqal library
338 * instance is set with this function, librdf_free_world() will not
339 * free it.
340 *
341 **/
342 void
librdf_world_set_rasqal(librdf_world * world,rasqal_world * rasqal_world_ptr)343 librdf_world_set_rasqal(librdf_world* world, rasqal_world* rasqal_world_ptr)
344 {
345 LIBRDF_ASSERT_OBJECT_POINTER_RETURN(world, librdf_world);
346 world->rasqal_world_ptr = rasqal_world_ptr;
347 world->rasqal_world_allocated_here = 0;
348 }
349
350
351 /**
352 * librdf_world_get_rasqal:
353 * @world: librdf_world object
354 *
355 * Get the #rasqal_world instance used by this #librdf_world.
356 *
357 * Return value: rasqal_world object or NULL on failure (e.g. not initialized)
358 **/
359 rasqal_world*
librdf_world_get_rasqal(librdf_world * world)360 librdf_world_get_rasqal(librdf_world* world)
361 {
362 LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(world, librdf_world, NULL);
363 return world->rasqal_world_ptr;
364 }
365
366
367 /**
368 * librdf_world_set_error:
369 * @world: redland world object
370 * @user_data: user data to pass to function
371 * @error_handler: pointer to the function
372 *
373 * Set the world error handling function.
374 *
375 * The function will receive callbacks when the world fails.
376 * librdf_world_set_logger() provides richer access to all log messages
377 * and should be used in preference.
378 **/
379 void
librdf_world_set_error(librdf_world * world,void * user_data,librdf_log_level_func error_handler)380 librdf_world_set_error(librdf_world* world, void *user_data,
381 librdf_log_level_func error_handler)
382 {
383 world->error_user_data = user_data;
384 world->error_handler = error_handler;
385 }
386
387
388 /**
389 * librdf_world_set_warning:
390 * @world: redland world object
391 * @user_data: user data to pass to function
392 * @warning_handler: pointer to the function
393 *
394 * Set the world warning handling function.
395 *
396 * The function will receive callbacks when the world gives a warning.
397 * librdf_world_set_logger() provides richer access to all log messages
398 * and should be used in preference.
399 **/
400 void
librdf_world_set_warning(librdf_world * world,void * user_data,librdf_log_level_func warning_handler)401 librdf_world_set_warning(librdf_world* world, void *user_data,
402 librdf_log_level_func warning_handler)
403 {
404 world->warning_user_data = user_data;
405 world->warning_handler = warning_handler;
406 }
407
408
409
410 /**
411 * librdf_world_set_logger:
412 * @world: redland world object
413 * @user_data: user data to pass to function
414 * @log_handler: pointer to the function
415 *
416 * Set the world log handling function.
417 *
418 * The function will receive callbacks when redland generates a log message
419 **/
420 void
librdf_world_set_logger(librdf_world * world,void * user_data,librdf_log_func log_handler)421 librdf_world_set_logger(librdf_world* world, void *user_data,
422 librdf_log_func log_handler)
423 {
424 world->log_user_data = user_data;
425 world->log_handler = log_handler;
426 }
427
428
429
430 /**
431 * librdf_world_set_digest:
432 * @world: redland world object
433 * @name: Digest factory name
434 *
435 * Set the default content digest name.
436 *
437 * Sets the digest factory for various modules that need to make
438 * digests of their objects.
439 */
440 void
librdf_world_set_digest(librdf_world * world,const char * name)441 librdf_world_set_digest(librdf_world* world, const char *name)
442 {
443 world->digest_factory_name = (char*)name;
444 }
445
446
447 /**
448 * librdf_world_get_feature:
449 * @world: #librdf_world object
450 * @feature: #librdf_uri feature property
451 *
452 * Get the value of a world feature.
453 *
454 * Return value: new #librdf_node feature value or NULL if no such feature
455 * exists or the value is empty.
456 **/
457 librdf_node*
librdf_world_get_feature(librdf_world * world,librdf_uri * feature)458 librdf_world_get_feature(librdf_world* world, librdf_uri *feature)
459 {
460 return NULL; /* none retrievable */
461 }
462
463
464 /**
465 * librdf_world_set_feature:
466 * @world: #librdf_world object
467 * @feature: #librdf_uri feature property
468 * @value: #librdf_node feature property value
469 *
470 * Set the value of a world feature.
471 *
472 * Return value: non 0 on failure (negative if no such feature)
473 **/
474 int
librdf_world_set_feature(librdf_world * world,librdf_uri * feature,librdf_node * value)475 librdf_world_set_feature(librdf_world* world, librdf_uri* feature,
476 librdf_node* value)
477 {
478 librdf_uri* genid_base;
479 librdf_uri* genid_counter;
480 int rc= -1;
481
482 genid_counter = librdf_new_uri(world,
483 (const unsigned char*)LIBRDF_WORLD_FEATURE_GENID_COUNTER);
484 genid_base = librdf_new_uri(world,
485 (const unsigned char*)LIBRDF_WORLD_FEATURE_GENID_BASE);
486
487 if(librdf_uri_equals(feature, genid_base)) {
488 if(!librdf_node_is_resource(value))
489 rc=1;
490 else {
491 long lid = atol((const char*)librdf_node_get_literal_value(value));
492 if(lid < 1)
493 lid = 1;
494
495 #ifdef WITH_THREADS
496 pthread_mutex_lock(world->mutex);
497 #endif
498 world->genid_base = LIBRDF_GOOD_CAST(unsigned long, lid);
499 #ifdef WITH_THREADS
500 pthread_mutex_unlock(world->mutex);
501 #endif
502 rc = 0;
503 }
504 } else if(librdf_uri_equals(feature, genid_counter)) {
505 if(!librdf_node_is_resource(value))
506 rc = 1;
507 else {
508 long lid = atol((const char*)librdf_node_get_literal_value(value));
509 if(lid < 1)
510 lid = 1;
511
512 #ifdef WITH_THREADS
513 pthread_mutex_lock(world->mutex);
514 #endif
515 world->genid_counter = LIBRDF_GOOD_CAST(unsigned long, lid);
516 #ifdef WITH_THREADS
517 pthread_mutex_unlock(world->mutex);
518 #endif
519 rc = 0;
520 }
521 }
522
523 librdf_free_uri(genid_base);
524 librdf_free_uri(genid_counter);
525
526 return rc;
527 }
528
529
530 /* Internal */
531 unsigned char*
librdf_world_get_genid(librdf_world * world)532 librdf_world_get_genid(librdf_world* world)
533 {
534 unsigned long id, tmpid, counter, tmpcounter, pid, tmppid;
535 size_t length;
536 unsigned char *buffer;
537
538 /* This is read-only and thread safe */
539 tmpid = (id = world->genid_base);
540
541 #ifdef WITH_THREADS
542 pthread_mutex_lock(world->mutex);
543 #endif
544 tmpcounter = (counter = world->genid_counter++);
545 #ifdef WITH_THREADS
546 pthread_mutex_unlock(world->mutex);
547 #endif
548
549 /* Add the process ID to the seed to differentiate between
550 * simultaneously executed child processes.
551 */
552 pid = LIBRDF_GOOD_CAST(unsigned long, getpid());
553 if(!pid)
554 pid = 1;
555 tmppid = pid;
556
557
558 /* min length 1 + "r" + min length 1 + "r" + min length 1 + "r" \0 */
559 length = 7;
560
561 while(tmpid /= 10)
562 length++;
563 while(tmpcounter /= 10)
564 length++;
565 while(tmppid /= 10)
566 length++;
567
568 buffer = LIBRDF_MALLOC(unsigned char*, length);
569 if(!buffer)
570 return NULL;
571
572 sprintf((char*)buffer, "r%lur%lur%lu", id, pid, counter);
573 return buffer;
574 }
575
576
577
578 /* OLD INTERFACES BELOW HERE */
579
580 /* For old interfaces below ONLY */
581 #ifndef NO_STATIC_DATA
582 static librdf_world* RDF_World;
583 #endif
584
585 #ifndef REDLAND_DISABLE_DEPRECATED
586 /**
587 * librdf_init_world:
588 * @digest_factory_name: Name of digest factory to use
589 * @not_used2: Not used
590 *
591 * Initialise the library
592 * @deprecated: Do not use.
593 *
594 * Use librdf_new_world() and librdf_world_open() on #librdf_world object
595 *
596 * See librdf_world_set_digest() for documentation on arguments.
597 **/
598 void
librdf_init_world(char * digest_factory_name,void * not_used2)599 librdf_init_world(char *digest_factory_name, void* not_used2)
600 {
601 #ifndef NO_STATIC_DATA
602 RDF_World = librdf_new_world();
603 if(!RDF_World)
604 return;
605
606 if(digest_factory_name)
607 librdf_world_set_digest(RDF_World, digest_factory_name);
608 librdf_world_open(RDF_World);
609 #else
610 /* fail if NO_STATIC_DATA is defined */
611 abort();
612 #endif
613 }
614
615
616 /**
617 * librdf_destroy_world:
618 *
619 * Terminate the library
620 * @deprecated: Do not use.
621 *
622 * Use librdf_free_world() on #librdf_world object
623 *
624 * Terminates and frees the resources.
625 **/
626 void
librdf_destroy_world(void)627 librdf_destroy_world(void)
628 {
629 #ifndef NO_STATIC_DATA
630 librdf_free_world(RDF_World);
631 #else
632 /* fail if NO_STATIC_DATA is defined */
633 abort();
634 #endif
635 }
636 #endif
637
638 /**
639 * librdf_basename:
640 * @name: path
641 *
642 * Get the basename of a path
643 *
644 * Return value: filename part of a pathname
645 **/
646 const char*
librdf_basename(const char * name)647 librdf_basename(const char *name)
648 {
649 const char *p;
650 if((p = strrchr(name, '/')))
651 name = p+1;
652 else if((p = strrchr(name, '\\')))
653 name = p+1;
654
655 return name;
656 }
657
658
659 /**
660 * librdf_free_memory:
661 * @ptr: pointer to free
662 *
663 * Free memory allocated in the library.
664 *
665 * Required for some runtimes where memory must be freed within the same
666 * shared object it was allocated in.
667 **/
668 void
librdf_free_memory(void * ptr)669 librdf_free_memory(void *ptr)
670 {
671 raptor_free_memory(ptr);
672 }
673
674
675 /**
676 * librdf_alloc_memory:
677 * @size: alloc size
678 *
679 * Allocate memory inside the library similar to malloc().
680 *
681 * Required for some runtimes where memory must be freed within the same
682 * shared object it was allocated in.
683 *
684 * Return value: pointer to memory or NULL on failure
685 **/
686 void*
librdf_alloc_memory(size_t size)687 librdf_alloc_memory(size_t size)
688 {
689 return raptor_alloc_memory(size);
690 }
691
692 /**
693 * librdf_calloc_memory:
694 * @nmemb: number of members
695 * @size: size of member
696 *
697 * Allocate zeroed array of items inside the library similar to calloc().
698 *
699 * Required for some runtimes where memory must be freed within the same
700 * shared object it was allocated in.
701 *
702 * Return value: pointer to memory or NULL on failure
703 **/
704 void*
librdf_calloc_memory(size_t nmemb,size_t size)705 librdf_calloc_memory(size_t nmemb, size_t size)
706 {
707 return raptor_calloc_memory(nmemb, size);
708 }
709
710
711 #endif /* STANDALONE */
712
713
714 /* TEST CODE */
715
716
717 #ifdef STANDALONE
718
719 /* one more prototype */
720 int main(int argc, char *argv[]);
721
722
723 int
main(int argc,char * argv[])724 main(int argc, char *argv[])
725 {
726 librdf_world *world;
727 rasqal_world *rasqal_world;
728 unsigned char* id;
729 const char *program=librdf_basename((const char*)argv[0]);
730
731 /* Minimal setup-cleanup test without opening the world */
732 fprintf(stdout, "%s: Creating new world\n", program);
733 world = librdf_new_world();
734 if(!world) {
735 fprintf(stderr, "%s: librdf_new_world failed\n", program);
736 return 1;
737 }
738 fprintf(stdout, "%s: Deleting world\n", program);
739 librdf_free_world(world);
740
741
742 /* Test setting and getting a the rasqal world */
743 fprintf(stdout, "%s: Setting and getting rasqal_world\n", program);
744 world = librdf_new_world();
745 if(!world) {
746 fprintf(stderr, "%s: librdf_new_world failed\n", program);
747 return 1;
748 }
749
750 rasqal_world = rasqal_new_world();
751 if(!rasqal_world) {
752 fprintf(stderr, "%s: rasqal_new_world failed\n", program);
753 return 1;
754 }
755
756 librdf_world_set_rasqal(world, rasqal_world);
757 if (librdf_world_get_rasqal(world) != rasqal_world) {
758 fprintf(stderr, "%s: librdf_world_set_rasqal/librdf_world_get_rasqal failed\n", program);
759 return 1;
760 }
761 rasqal_free_world(rasqal_world);
762 librdf_free_world(world);
763
764
765 /* Test id generation */
766 fprintf(stdout, "%s: Creating new world\n", program);
767 world = librdf_new_world();
768 if(!world) {
769 fprintf(stderr, "%s: librdf_new_world failed\n", program);
770 return 1;
771 }
772
773 fprintf(stdout, "%s: Generating an identifier\n", program);
774 id = librdf_world_get_genid(world);
775 if(id == NULL || strlen((const char*)id) < 6) {
776 fprintf(stderr, "%s: librdf_world_get_genid failed\n", program);
777 return 1;
778 }
779 fprintf(stdout, "%s: New identifier is: '%s'\n", program, id);
780 LIBRDF_FREE(char*, id);
781
782 fprintf(stdout, "%s: Deleting world\n", program);
783 librdf_free_world(world);
784
785 /* keep gcc -Wall happy */
786 return(0);
787 }
788
789 #endif
790