1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rdf_stream.c - RDF Statement Stream Implementation
4 *
5 * Copyright (C) 2000-2008, David Beckett http://www.dajobe.org/
6 * Copyright (C) 2000-2004, University of Bristol, UK http://www.bristol.ac.uk/
7 *
8 * This package is Free Software and part of Redland http://librdf.org/
9 *
10 * It is licensed under the following three licenses as alternatives:
11 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12 * 2. GNU General Public License (GPL) V2 or any newer version
13 * 3. Apache License, V2.0 or any newer version
14 *
15 * You may not use this file except in compliance with at least one of
16 * the above three licenses.
17 *
18 * See LICENSE.html or LICENSE.txt at the top of this package for the
19 * complete terms and further detail along with the license texts for
20 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
21 *
22 *
23 */
24
25
26 #ifdef HAVE_CONFIG_H
27 #include <rdf_config.h>
28 #endif
29
30 #ifdef WIN32
31 #include <win32_rdf_config.h>
32 #endif
33
34 #include <stdio.h>
35 #include <sys/types.h>
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39
40 #include <redland.h>
41
42
43 #ifndef STANDALONE
44
45 /* prototypes of local helper functions */
46 static librdf_statement* librdf_stream_update_current_statement(librdf_stream* stream);
47
48
49 /**
50 * librdf_new_stream:
51 * @world: redland world object
52 * @context: context to pass to the stream implementing objects
53 * @is_end_method: pointer to function to test for end of stream
54 * @next_method: pointer to function to move to the next statement in stream
55 * @get_method: pointer to function to get the current statement
56 * @finished_method: pointer to function to finish the stream.
57 *
58 * Constructor - create a new #librdf_stream.
59 *
60 * Creates a new stream with an implementation based on the passed in
61 * functions. The functions next_statement and end_of_stream will be called
62 * multiple times until either of them signify the end of stream by
63 * returning NULL or non 0 respectively. The finished function is called
64 * once only when the stream object is destroyed with librdf_free_stream()
65 *
66 * A mapping function can be set for the stream using librdf_stream_add_map()
67 * function which allows the statements generated by the stream to be
68 * filtered and/or altered as they are generated before passing back
69 * to the user.
70 *
71 * Return value: a new #librdf_stream object or NULL on failure
72 **/
73 REDLAND_EXTERN_C
74 librdf_stream*
librdf_new_stream(librdf_world * world,void * context,int (* is_end_method)(void *),int (* next_method)(void *),void * (* get_method)(void *,int),void (* finished_method)(void *))75 librdf_new_stream(librdf_world *world,
76 void* context,
77 int (*is_end_method)(void*),
78 int (*next_method)(void*),
79 void* (*get_method)(void*, int),
80 void (*finished_method)(void*))
81 {
82 librdf_stream* new_stream;
83
84 librdf_world_open(world);
85
86 new_stream = LIBRDF_CALLOC(librdf_stream*, 1, sizeof(*new_stream));
87 if(!new_stream)
88 return NULL;
89
90 new_stream->world=world;
91 new_stream->context=context;
92
93 new_stream->is_end_method=is_end_method;
94 new_stream->next_method=next_method;
95 new_stream->get_method=get_method;
96 new_stream->finished_method=finished_method;
97
98 new_stream->is_finished=0;
99 new_stream->current=NULL;
100
101 return new_stream;
102 }
103
104
105 /* helper function for deleting list map */
106 static void
librdf_stream_free_stream_map(void * list_data,void * user_data)107 librdf_stream_free_stream_map(void *list_data, void *user_data)
108 {
109 librdf_stream_map* map=(librdf_stream_map*)list_data;
110 if(map->free_context)
111 map->free_context(map->context);
112 LIBRDF_FREE(librdf_stream_map, map);
113 }
114
115
116
117 /**
118 * librdf_free_stream:
119 * @stream: #librdf_stream object
120 *
121 * Destructor - destroy an #libdf_stream object.
122 *
123 **/
124 void
librdf_free_stream(librdf_stream * stream)125 librdf_free_stream(librdf_stream* stream)
126 {
127 if(!stream)
128 return;
129
130 if(stream->finished_method)
131 stream->finished_method(stream->context);
132
133 if(stream->map_list) {
134 librdf_list_foreach(stream->map_list,
135 librdf_stream_free_stream_map, NULL);
136 librdf_free_list(stream->map_list);
137 }
138
139 LIBRDF_FREE(librdf_stream, stream);
140 }
141
142
143 /*
144 * librdf_stream_update_current_statement - helper function to get the next element with map applied
145 * @stream: #librdf_stream object
146 *
147 * A helper function that gets the next element subject to the user
148 * defined map function, if set by librdf_stream_add_map(),
149 *
150 * Return value: the next statement or NULL at end of stream
151 */
152 static librdf_statement*
librdf_stream_update_current_statement(librdf_stream * stream)153 librdf_stream_update_current_statement(librdf_stream* stream)
154 {
155 librdf_statement* statement=NULL;
156
157 if(stream->is_updated)
158 return stream->current;
159
160 stream->is_updating=1;
161
162 /* find next statement subject to map */
163 while(!stream->is_end_method(stream->context)) {
164 librdf_iterator* map_iterator; /* Iterator over stream->map_list librdf_list */
165 statement=(librdf_statement*)stream->get_method(stream->context,
166 LIBRDF_STREAM_GET_METHOD_GET_OBJECT);
167 if(!statement)
168 break;
169
170 if(!stream->map_list || !librdf_list_size(stream->map_list))
171 break;
172
173 map_iterator=librdf_list_get_iterator(stream->map_list);
174 if(!map_iterator) {
175 statement=NULL;
176 break;
177 }
178
179 while(!librdf_iterator_end(map_iterator)) {
180 librdf_stream_map *map=(librdf_stream_map*)librdf_iterator_get_object(map_iterator);
181 if(!map)
182 break;
183
184 /* apply the map to the element */
185 statement=map->fn(stream, map->context, statement);
186 if(!statement)
187 break;
188
189 librdf_iterator_next(map_iterator);
190 }
191 librdf_free_iterator(map_iterator);
192
193
194 /* found something, return it */
195 if(statement)
196 break;
197
198 stream->next_method(stream->context);
199 }
200
201 stream->current=statement;
202 if(!stream->current)
203 stream->is_finished=1;
204
205 stream->is_updated=1;
206 stream->is_updating=0;
207
208 return statement;
209 }
210
211
212 /**
213 * librdf_stream_end:
214 * @stream: #librdf_stream object
215 *
216 * Test if the stream has ended.
217 *
218 * Return value: non 0 at end of stream.
219 **/
220 int
librdf_stream_end(librdf_stream * stream)221 librdf_stream_end(librdf_stream* stream)
222 {
223 /* always end of NULL stream */
224 if(!stream || stream->is_finished)
225 return 1;
226
227 librdf_stream_update_current_statement(stream);
228
229 return stream->is_finished;
230 }
231
232
233 /**
234 * librdf_stream_next:
235 * @stream: #librdf_stream object
236 *
237 * Move to the next librdf_statement in the stream.
238 *
239 * Return value: non 0 if the stream has finished
240 **/
241 int
librdf_stream_next(librdf_stream * stream)242 librdf_stream_next(librdf_stream* stream)
243 {
244 if(!stream || stream->is_finished)
245 return 1;
246
247 if(stream->next_method(stream->context)) {
248 stream->is_finished=1;
249 return 1;
250 }
251
252 stream->is_updated=0;
253 librdf_stream_update_current_statement(stream);
254
255 return stream->is_finished;
256 }
257
258
259 /**
260 * librdf_stream_get_object:
261 * @stream: #librdf_stream object
262 *
263 * Get the current librdf_statement in the stream.
264 *
265 * This method returns a SHARED pointer to the current statement object
266 * which should be copied by the caller to preserve it if the stream
267 * is moved on librdf_stream_next() or if it should last after the
268 * stream is closed. librdf_new_statement_from_statement() can be used
269 * for copying the statement.
270 *
271 * Return value: the current #librdf_statement object or NULL at end of stream.
272 **/
273 librdf_statement*
librdf_stream_get_object(librdf_stream * stream)274 librdf_stream_get_object(librdf_stream* stream)
275 {
276 if(stream->is_finished)
277 return NULL;
278
279 return librdf_stream_update_current_statement(stream);
280 }
281
282
283 /**
284 * librdf_stream_get_context2:
285 * @stream: the #librdf_stream object
286 *
287 * Get the context of the current object on the stream.
288 *
289 * This method returns a SHARED pointer to the current context node object
290 * which should be copied by the caller to preserve it if the stream
291 * is moved on librdf_stream_next or if it should last after the
292 * stream is closed.
293 *
294 * Return value: The context node (can be NULL) or NULL if the stream has finished.
295 **/
296 librdf_node*
librdf_stream_get_context2(librdf_stream * stream)297 librdf_stream_get_context2(librdf_stream* stream)
298 {
299 if(stream->is_finished)
300 return NULL;
301
302 /* Update current statement only if we are not already in the middle of the
303 statement update process.
304 Allows inspection of context nodes in stream map callbacks. */
305 if(!stream->is_updating && !librdf_stream_update_current_statement(stream))
306 return NULL;
307
308 return (librdf_node*)stream->get_method(stream->context,
309 LIBRDF_STREAM_GET_METHOD_GET_CONTEXT);
310 }
311
312
313 /**
314 * librdf_stream_get_context:
315 * @stream: the #librdf_stream object
316 *
317 * Get the context of the current object on the stream.
318 *
319 * This method returns a SHARED pointer to the current context node object
320 * which should be copied by the caller to preserve it if the stream
321 * is moved on librdf_stream_next or if it should last after the
322 * stream is closed.
323 *
324 * @Deprecated: Use librdf_stream_get_context2() which returns a #librdf_node
325 *
326 * Return value: The context node (can be NULL) or NULL if the stream has finished.
327 **/
328 void*
librdf_stream_get_context(librdf_stream * stream)329 librdf_stream_get_context(librdf_stream* stream)
330 {
331 return librdf_stream_get_context2(stream);
332 }
333
334
335 /**
336 * librdf_stream_add_map:
337 * @stream: the stream
338 * @map_function: the function to perform the mapping
339 * @free_context: the function to use to free the context (or NULL)
340 * @map_context: the context to pass to the map function
341 *
342 * Add a librdf_stream mapping function.
343 *
344 * Adds an stream mapping function which operates over the stream to
345 * select which elements are returned; it will be applied as soon as
346 * this method is called.
347 *
348 * Several mapping functions can be added and they are applied in
349 * the order given.
350 *
351 * The mapping function should return the statement to return, or NULL
352 * to remove it from the stream.
353 *
354 * Return value: Non 0 on failure
355 **/
356 int
librdf_stream_add_map(librdf_stream * stream,librdf_stream_map_handler map_function,librdf_stream_map_free_context_handler free_context,void * map_context)357 librdf_stream_add_map(librdf_stream* stream,
358 librdf_stream_map_handler map_function,
359 librdf_stream_map_free_context_handler free_context,
360 void *map_context)
361 {
362 librdf_stream_map *map;
363
364 if(!stream->map_list) {
365 stream->map_list=librdf_new_list(stream->world);
366 if(!stream->map_list) {
367 if(free_context && map_context)
368 (*free_context)(map_context);
369 return 1;
370 }
371 }
372
373 map = LIBRDF_CALLOC(librdf_stream_map*, 1, sizeof(*map));
374 if(!map) {
375 if(free_context && map_context)
376 (*free_context)(map_context);
377 return 1;
378 }
379
380 map->fn=map_function;
381 map->free_context=free_context;
382 map->context=map_context;
383
384 if(librdf_list_add(stream->map_list, map)) {
385 LIBRDF_FREE(librdf_stream_map, map);
386 if(free_context && map_context)
387 (*free_context)(map_context);
388 return 1;
389 }
390
391 return 0;
392 }
393
394
395
396 static int librdf_stream_from_node_iterator_end_of_stream(void* context);
397 static int librdf_stream_from_node_iterator_next_statement(void* context);
398 static void* librdf_stream_from_node_iterator_get_statement(void* context, int flags);
399 static void librdf_stream_from_node_iterator_finished(void* context);
400
401 typedef struct {
402 librdf_iterator *iterator;
403 librdf_statement *current; /* shared statement */
404 librdf_statement_part field;
405 } librdf_stream_from_node_iterator_stream_context;
406
407
408
409 /**
410 * librdf_new_stream_from_node_iterator:
411 * @iterator: #librdf_iterator of #librdf_node objects
412 * @statement: #librdf_statement prototype with one NULL node space
413 * @field: node part of statement
414 *
415 * Constructor - create a new #librdf_stream from an iterator of nodes.
416 *
417 * Creates a new #librdf_stream using the passed in #librdf_iterator
418 * which generates a series of #librdf_node objects. The resulting
419 * nodes are then inserted into the given statement and returned.
420 * The field attribute indicates which statement node is being generated.
421 *
422 * Return value: a new #librdf_stream object or NULL on failure
423 **/
424 librdf_stream*
librdf_new_stream_from_node_iterator(librdf_iterator * iterator,librdf_statement * statement,librdf_statement_part field)425 librdf_new_stream_from_node_iterator(librdf_iterator* iterator,
426 librdf_statement* statement,
427 librdf_statement_part field)
428 {
429 librdf_stream_from_node_iterator_stream_context *scontext;
430 librdf_stream *stream;
431
432 scontext = LIBRDF_CALLOC(librdf_stream_from_node_iterator_stream_context*, 1,
433 sizeof(*scontext));
434 if(!scontext)
435 return NULL;
436
437 /* copy the prototype statement */
438 statement=librdf_new_statement_from_statement(statement);
439 if(!statement) {
440 LIBRDF_FREE(librdf_stream_from_node_iterator_stream_context, scontext);
441 return NULL;
442 }
443
444 scontext->iterator=iterator;
445 scontext->current=statement;
446 scontext->field=field;
447
448 stream=librdf_new_stream(iterator->world,
449 (void*)scontext,
450 &librdf_stream_from_node_iterator_end_of_stream,
451 &librdf_stream_from_node_iterator_next_statement,
452 &librdf_stream_from_node_iterator_get_statement,
453 &librdf_stream_from_node_iterator_finished);
454 if(!stream) {
455 librdf_stream_from_node_iterator_finished((void*)scontext);
456 return NULL;
457 }
458
459 return stream;
460 }
461
462
463 static int
librdf_stream_from_node_iterator_end_of_stream(void * context)464 librdf_stream_from_node_iterator_end_of_stream(void* context)
465 {
466 librdf_stream_from_node_iterator_stream_context* scontext=(librdf_stream_from_node_iterator_stream_context*)context;
467
468 return librdf_iterator_end(scontext->iterator);
469 }
470
471
472 static int
librdf_stream_from_node_iterator_next_statement(void * context)473 librdf_stream_from_node_iterator_next_statement(void* context)
474 {
475 librdf_stream_from_node_iterator_stream_context* scontext=(librdf_stream_from_node_iterator_stream_context*)context;
476
477 return librdf_iterator_next(scontext->iterator);
478 }
479
480
481 static void*
librdf_stream_from_node_iterator_get_statement(void * context,int flags)482 librdf_stream_from_node_iterator_get_statement(void* context, int flags)
483 {
484 librdf_stream_from_node_iterator_stream_context* scontext=(librdf_stream_from_node_iterator_stream_context*)context;
485 librdf_node* node;
486
487 switch(flags) {
488 case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT:
489
490 if(!(node=(librdf_node*)librdf_iterator_get_object(scontext->iterator)))
491 return NULL;
492
493 /* The node object above is shared, no need to free it before
494 * assigning to the statement, which is also shared, and
495 * return to the user.
496 */
497 switch(scontext->field) {
498 case LIBRDF_STATEMENT_SUBJECT:
499 librdf_statement_set_subject(scontext->current, node);
500 break;
501 case LIBRDF_STATEMENT_PREDICATE:
502 librdf_statement_set_predicate(scontext->current, node);
503 break;
504 case LIBRDF_STATEMENT_OBJECT:
505 librdf_statement_set_object(scontext->current, node);
506 break;
507
508 case LIBRDF_STATEMENT_ALL:
509 default:
510 librdf_log(scontext->iterator->world,
511 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STREAM, NULL,
512 "Illegal statement field %d seen", scontext->field);
513 return NULL;
514 }
515
516 return scontext->current;
517
518 case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT:
519 return librdf_iterator_get_context(scontext->iterator);
520 default:
521 librdf_log(scontext->iterator->world,
522 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STREAM, NULL,
523 "Unknown iterator method flag %d", flags);
524 return NULL;
525 }
526
527 }
528
529
530 static void
librdf_stream_from_node_iterator_finished(void * context)531 librdf_stream_from_node_iterator_finished(void* context)
532 {
533 librdf_stream_from_node_iterator_stream_context* scontext=(librdf_stream_from_node_iterator_stream_context*)context;
534 librdf_world* world = scontext->iterator ? scontext->iterator->world : NULL;
535
536 if(scontext->iterator)
537 librdf_free_iterator(scontext->iterator);
538
539 if(scontext->current) {
540 switch(scontext->field) {
541 case LIBRDF_STATEMENT_SUBJECT:
542 librdf_statement_set_subject(scontext->current, NULL);
543 break;
544 case LIBRDF_STATEMENT_PREDICATE:
545 librdf_statement_set_predicate(scontext->current, NULL);
546 break;
547 case LIBRDF_STATEMENT_OBJECT:
548 librdf_statement_set_object(scontext->current, NULL);
549 break;
550
551 case LIBRDF_STATEMENT_ALL:
552 default:
553 librdf_log(world,
554 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STREAM, NULL,
555 "Illegal statement field %d seen", scontext->field);
556 }
557 librdf_free_statement(scontext->current);
558 }
559
560 LIBRDF_FREE(librdf_stream_from_node_iterator_stream_context, scontext);
561 }
562
563
564 #ifndef REDLAND_DISABLE_DEPRECATED
565 /**
566 * librdf_stream_print:
567 * @stream: the stream object
568 * @fh: the FILE stream to print to
569 *
570 * Print the stream.
571 *
572 * This prints the remaining statements of the stream to the given
573 * file handle. Note that after this method is called the stream
574 * will be empty so that librdf_stream_end() will always be true
575 * and librdf_stream_next() will always return NULL. The only
576 * useful operation is to dispose of the stream with the
577 * librdf_free_stream() destructor.
578 *
579 * This method is for debugging and the format of the output should
580 * not be relied on.
581 *
582 * @Deprecated: Use librdf_stream_write() to write to
583 * #raptor_iostream which can be made to write to a string. Use a
584 * #librdf_serializer to write proper syntax formats.
585 *
586 **/
587 void
librdf_stream_print(librdf_stream * stream,FILE * fh)588 librdf_stream_print(librdf_stream *stream, FILE *fh)
589 {
590 raptor_iostream *iostr;
591
592 if(!stream)
593 return;
594
595 iostr = raptor_new_iostream_to_file_handle(stream->world->raptor_world_ptr, fh);
596 if(!iostr)
597 return;
598
599 while(!librdf_stream_end(stream)) {
600 librdf_statement* statement = librdf_stream_get_object(stream);
601 librdf_node* context_node = librdf_stream_get_context2(stream);
602 if(!statement)
603 break;
604
605 fputs(" ", fh);
606 librdf_statement_write(statement, iostr);
607 if(context_node) {
608 fputs(" with context ", fh);
609 librdf_node_print(context_node, fh);
610 }
611 fputs("\n", fh);
612
613 librdf_stream_next(stream);
614 }
615
616 raptor_free_iostream(iostr);
617 }
618 #endif
619
620
621 /**
622 * librdf_stream_write:
623 * @stream: the stream object
624 * @iostr: the iostream to write to
625 *
626 * Write a stream of triples to an iostream in a debug format.
627 *
628 * This prints the remaining statements of the stream to the given
629 * #raptor_iostream in a debug format.
630 *
631 * Note that after this method is called the stream will be empty so
632 * that librdf_stream_end() will always be true and
633 * librdf_stream_next() will always return NULL. The only useful
634 * operation is to dispose of the stream with the
635 * librdf_free_stream() destructor.
636 *
637 * This method is for debugging and the format of the output should
638 * not be relied on. In particular, when contexts are used the
639 * result may be 4 nodes.
640 *
641 * Return value: non-0 on failure
642 **/
643 int
librdf_stream_write(librdf_stream * stream,raptor_iostream * iostr)644 librdf_stream_write(librdf_stream *stream, raptor_iostream *iostr)
645 {
646 LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(stream, librdf_stream, 1);
647 LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(iostr, raptor_iostream, 1);
648
649 while(!librdf_stream_end(stream)) {
650 librdf_statement* statement;
651 librdf_node* context_node;
652
653 statement = librdf_stream_get_object(stream);
654 if(!statement)
655 break;
656
657 raptor_iostream_counted_string_write(" ", 2, iostr);
658 if(librdf_statement_write(statement, iostr))
659 return 1;
660
661 context_node = librdf_stream_get_context2(stream);
662 if(context_node) {
663 raptor_iostream_counted_string_write(" with context ", 14, iostr);
664 librdf_node_write(context_node, iostr);
665 }
666 raptor_iostream_counted_string_write(". \n", 3, iostr);
667
668 librdf_stream_next(stream);
669 }
670
671 return 0;
672 }
673
674
675 librdf_statement*
librdf_stream_statement_find_map(librdf_stream * stream,void * context,librdf_statement * statement)676 librdf_stream_statement_find_map(librdf_stream *stream,
677 void* context, librdf_statement* statement)
678 {
679 librdf_statement* partial_statement=(librdf_statement*)context;
680
681 /* any statement matches when no partial statement is given */
682 if(!partial_statement)
683 return statement;
684
685 if (librdf_statement_match(statement, partial_statement)) {
686 return statement;
687 }
688
689 /* not suitable */
690 return NULL;
691 }
692
693
694 /**
695 * librdf_new_empty_stream:
696 * @world: redland world object
697 *
698 * Constructor - create a new #librdf_stream with no content.
699 *
700 * Return value: a new #librdf_stream object or NULL on failure
701 **/
702 librdf_stream*
librdf_new_empty_stream(librdf_world * world)703 librdf_new_empty_stream(librdf_world *world)
704 {
705 librdf_stream* new_stream;
706
707 librdf_world_open(world);
708
709 new_stream = LIBRDF_CALLOC(librdf_stream*, 1, sizeof(*new_stream));
710 if(!new_stream)
711 return NULL;
712
713 new_stream->world=world;
714
715 /* This ensures end, next, get_object, get_context factory methods
716 * never get called and the methods always return finished.
717 */
718 new_stream->is_finished=1;
719
720 return new_stream;
721 }
722
723
724 #endif
725
726
727 /* TEST CODE */
728
729
730 #ifdef STANDALONE
731
732 /* one more prototype */
733 int main(int argc, char *argv[]);
734
735 #define STREAM_NODES_COUNT 6
736 #define NODE_URI_PREFIX "http://example.org/node"
737
738 int
main(int argc,char * argv[])739 main(int argc, char *argv[])
740 {
741 librdf_statement *statement;
742 librdf_stream* stream;
743 const char *program=librdf_basename((const char*)argv[0]);
744 librdf_world *world;
745 librdf_uri* prefix_uri;
746 librdf_node* nodes[STREAM_NODES_COUNT];
747 int i;
748 librdf_iterator* iterator;
749 int count;
750
751 world=librdf_new_world();
752 librdf_world_open(world);
753
754 prefix_uri=librdf_new_uri(world, (const unsigned char*)NODE_URI_PREFIX);
755 if(!prefix_uri) {
756 fprintf(stderr, "%s: Failed to create prefix URI\n", program);
757 return(1);
758 }
759
760 for(i=0; i < STREAM_NODES_COUNT; i++) {
761 unsigned char buf[2];
762 buf[0]='a'+i;
763 buf[1]='\0';
764 nodes[i]=librdf_new_node_from_uri_local_name(world, prefix_uri, buf);
765 if(!nodes[i]) {
766 fprintf(stderr, "%s: Failed to create node %i (%s)\n", program, i, buf);
767 return(1);
768 }
769 }
770
771 fprintf(stdout, "%s: Creating static node iterator\n", program);
772 iterator = librdf_node_new_static_node_iterator(world, nodes, STREAM_NODES_COUNT);
773 if(!iterator) {
774 fprintf(stderr, "%s: Failed to create static node iterator\n", program);
775 return(1);
776 }
777
778 statement=librdf_new_statement_from_nodes(world,
779 librdf_new_node_from_uri_string(world, (const unsigned char*)"http://example.org/resource"),
780 librdf_new_node_from_uri_string(world, (const unsigned char*)"http://example.org/property"),
781 NULL);
782 if(!statement) {
783 fprintf(stderr, "%s: Failed to create statement\n", program);
784 return(1);
785 }
786
787 fprintf(stdout, "%s: Creating stream from node iterator\n", program);
788 stream=librdf_new_stream_from_node_iterator(iterator, statement, LIBRDF_STATEMENT_OBJECT);
789 if(!stream) {
790 fprintf(stderr, "%s: Failed to createstatic node stream\n", program);
791 return(1);
792 }
793
794
795 /* This is to check that the stream_from_node_iterator code
796 * *really* takes a copy of what it needs from statement
797 */
798 fprintf(stdout, "%s: Freeing statement\n", program);
799 librdf_free_statement(statement);
800
801
802 fprintf(stdout, "%s: Listing static node stream\n", program);
803 count=0;
804 while(!librdf_stream_end(stream)) {
805 librdf_statement* s_statement=librdf_stream_get_object(stream);
806 if(!s_statement) {
807 fprintf(stderr, "%s: librdf_stream_current returned NULL when not end of stream\n", program);
808 return(1);
809 }
810
811 fprintf(stdout, "%s: statement %d is: ", program, count);
812 librdf_statement_print(s_statement, stdout);
813 fputc('\n', stdout);
814
815 librdf_stream_next(stream);
816 count++;
817 }
818
819 if(count != STREAM_NODES_COUNT) {
820 fprintf(stderr, "%s: Stream returned %d statements, expected %d\n", program,
821 count, STREAM_NODES_COUNT);
822 return(1);
823 }
824
825 fprintf(stdout, "%s: stream from node iterator worked ok\n", program);
826
827
828 fprintf(stdout, "%s: Freeing stream\n", program);
829 librdf_free_stream(stream);
830
831
832 fprintf(stdout, "%s: Freeing nodes\n", program);
833 for (i=0; i<STREAM_NODES_COUNT; i++) {
834 librdf_free_node(nodes[i]);
835 }
836
837 librdf_free_uri(prefix_uri);
838
839 librdf_free_world(world);
840
841 /* keep gcc -Wall happy */
842 return(0);
843 }
844
845 #endif
846