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