1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * rasqal_variable.c - Rasqal variable support
4  *
5  * Copyright (C) 2003-2010, David Beckett http://www.dajobe.org/
6  * Copyright (C) 2003-2005, 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 #ifdef HAVE_CONFIG_H
26 #include <rasqal_config.h>
27 #endif
28 
29 #ifdef WIN32
30 #include <win32_rasqal_config.h>
31 #endif
32 
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 #include <stdarg.h>
40 
41 #include "rasqal.h"
42 #include "rasqal_internal.h"
43 
44 #if 0
45 #define RASQAL_DEBUG_VARIABLE_USAGE
46 #endif
47 
48 #ifndef STANDALONE
49 
50 
51 /**
52  * rasqal_new_variable_from_variable:
53  * @v: #rasqal_variable to copy
54  *
55  * Copy Constructor - Create a new Rasqal variable from an existing one
56  *
57  * This adds a new reference to the variable, it does not do a deep copy
58  *
59  * Return value: a new #rasqal_variable or NULL on failure.
60  **/
61 rasqal_variable*
rasqal_new_variable_from_variable(rasqal_variable * v)62 rasqal_new_variable_from_variable(rasqal_variable* v)
63 {
64   if(!v)
65     return NULL;
66 
67   v->usage++;
68 
69 #ifdef RASQAL_DEBUG_VARIABLE_USAGE
70   RASQAL_DEBUG3("Variable %s usage increased to %d\n", v->name, v->usage);
71 #endif
72 
73   return v;
74 }
75 
76 /**
77  * rasqal_free_variable:
78  * @v: #rasqal_variable object
79  *
80  * Destructor - Destroy a Rasqal variable object.
81  *
82  **/
83 void
rasqal_free_variable(rasqal_variable * v)84 rasqal_free_variable(rasqal_variable* v)
85 {
86   if(!v)
87     return;
88 
89 #ifdef RASQAL_DEBUG_VARIABLE_USAGE
90   v->usage--;
91   RASQAL_DEBUG3("Variable %s usage decreased to %d\n", v->name, v->usage);
92   if(v->usage)
93     return;
94 #else
95   if(--v->usage)
96     return;
97 #endif
98 
99   if(v->name)
100     RASQAL_FREE(char*, v->name);
101 
102   if(v->value)
103     rasqal_free_literal(v->value);
104 
105   if(v->expression)
106     rasqal_free_expression(v->expression);
107 
108   RASQAL_FREE(rasqal_variable, v);
109 }
110 
111 
112 /**
113  * rasqal_variable_write:
114  * @v: the #rasqal_variable object
115  * @iostr: the #raptor_iostream handle to write to
116  *
117  * Write a Rasqal variable to an iostream in a debug format.
118  *
119  * The write debug format may change in any release.
120  *
121  **/
122 void
rasqal_variable_write(rasqal_variable * v,raptor_iostream * iostr)123 rasqal_variable_write(rasqal_variable* v, raptor_iostream* iostr)
124 {
125   if(!v || !iostr)
126     return;
127 
128   if(v->type == RASQAL_VARIABLE_TYPE_ANONYMOUS)
129     raptor_iostream_counted_string_write("anon-variable(", 14, iostr);
130   else
131     raptor_iostream_counted_string_write("variable(", 9, iostr);
132 
133   raptor_iostream_string_write(v->name, iostr);
134 
135   if(v->expression) {
136     raptor_iostream_write_byte('=', iostr);
137     rasqal_expression_write(v->expression, iostr);
138   }
139 
140   if(v->value) {
141     raptor_iostream_write_byte('=', iostr);
142     rasqal_literal_write(v->value, iostr);
143   }
144 
145 #ifdef RASQAL_DEBUG_VARIABLE_USAGE
146   raptor_iostream_write_byte('[', iostr);
147   raptor_iostream_decimal_write(v->usage, iostr);
148   raptor_iostream_write_byte(']', iostr);
149 #endif
150 
151   raptor_iostream_write_byte(')', iostr);
152 }
153 
154 
155 /*
156  * rasqal_variables_write:
157  * @seq: sequence of #rasqal_variable to write
158  * @iostr: the #raptor_iostream handle to write to
159  *
160  * INTERNAL - Write a sequence of Rasqal variable to an iostream in a debug format.
161  *
162  * The write debug format may change in any release.
163  *
164  **/
165 int
rasqal_variables_write(raptor_sequence * seq,raptor_iostream * iostr)166 rasqal_variables_write(raptor_sequence* seq, raptor_iostream* iostr)
167 {
168   int vars_size;
169   int i;
170 
171   if(!seq || !iostr)
172     return 1;
173 
174   vars_size = raptor_sequence_size(seq);
175   for(i = 0; i < vars_size; i++) {
176     rasqal_variable* v;
177 
178     v = (rasqal_variable*)raptor_sequence_get_at(seq, i);
179     if(i > 0)
180       raptor_iostream_counted_string_write(", ", 2, iostr);
181 
182     rasqal_variable_write(v, iostr);
183   }
184 
185   return 0;
186 }
187 
188 
189 /**
190  * rasqal_variable_print:
191  * @v: the #rasqal_variable object
192  * @fh: the FILE* handle to print to
193  *
194  * Print a Rasqal variable in a debug format.
195  *
196  * The print debug format may change in any release.
197  *
198  * Return value: non-0 on failure
199  **/
200 int
rasqal_variable_print(rasqal_variable * v,FILE * fh)201 rasqal_variable_print(rasqal_variable* v, FILE* fh)
202 {
203   if(v->type == RASQAL_VARIABLE_TYPE_ANONYMOUS)
204     fprintf(fh, "anon-variable(%s", v->name);
205   else
206     fprintf(fh, "variable(%s", v->name);
207 
208   if(v->expression) {
209     fputc('=', fh);
210     rasqal_expression_print(v->expression, fh);
211   }
212 
213   if(v->value) {
214     fputc('=', fh);
215     rasqal_literal_print(v->value, fh);
216   }
217 
218 #ifdef RASQAL_DEBUG_VARIABLE_USAGE
219   fprintf(fh, "[%d]", v->usage);
220 #endif
221 
222   fputc(')', fh);
223 
224   return 0;
225 }
226 
227 
228 /**
229  * rasqal_variable_set_value:
230  * @v: the #rasqal_variable object
231  * @l: the #rasqal_literal value to set (or NULL)
232  *
233  * Set the value of a Rasqal variable.
234  *
235  * The variable value is an input parameter and is copied in, not shared.
236  * If the variable value is NULL, any existing value is deleted.
237  *
238  **/
239 void
rasqal_variable_set_value(rasqal_variable * v,rasqal_literal * l)240 rasqal_variable_set_value(rasqal_variable* v, rasqal_literal* l)
241 {
242   if(v->value)
243     rasqal_free_literal(v->value);
244 
245   v->value = l;
246 
247 #ifdef RASQAL_DEBUG
248   if(!v->name)
249     RASQAL_FATAL1("variable has no name");
250 
251   RASQAL_DEBUG2("setting variable %s to value ", v->name);
252   rasqal_literal_print(v->value, stderr);
253   fputc('\n', stderr);
254 #endif
255 }
256 
257 
258 
259 /*
260  * A table of variables with optional binding values
261  *
262  * variables are named or anonymous (cannot be selected).
263  */
264 struct rasqal_variables_table_s {
265   rasqal_world* world;
266 
267   /* usage/reference count */
268   int usage;
269 
270   /* The variables of size @variables_count + @anon_variables_count
271    * shared pointers into @variables_sequence and @anon_variables_sequence
272    */
273   rasqal_variable** variables;
274 
275   /* Named variables (owner) */
276   raptor_sequence* variables_sequence;
277   int variables_count;
278 
279   /* Anonymous variables (owner) */
280   raptor_sequence* anon_variables_sequence;
281   int anon_variables_count;
282 
283   /* array of variable names.  The array is allocated here but the
284    * pointers are into the #variables_sequence above.  It is only
285    * allocated if rasqal_variables_table_get_names() is called
286    * on demand, otherwise is NULL.
287    */
288   const unsigned char** variable_names;
289 };
290 
291 
292 
293 /**
294  * rasqal_new_variables_table:
295  * @world: rasqal world
296  *
297  * Constructor - create a new variables table
298  *
299  * Return value: new variables table or NULL On failure
300  */
301 rasqal_variables_table*
rasqal_new_variables_table(rasqal_world * world)302 rasqal_new_variables_table(rasqal_world* world)
303 {
304   rasqal_variables_table* vt;
305 
306   vt = RASQAL_CALLOC(rasqal_variables_table*, 1, sizeof(*vt));
307   if(!vt)
308     return NULL;
309 
310   vt->usage = 1;
311   vt->world = world;
312 
313   vt->variables_sequence = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
314                                                (raptor_data_print_handler)rasqal_variable_print);
315   if(!vt->variables_sequence)
316     goto tidy;
317 
318   vt->anon_variables_sequence = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
319                                                     (raptor_data_print_handler)rasqal_variable_print);
320   if(!vt->anon_variables_sequence)
321     goto tidy;
322 
323   vt->variable_names = NULL;
324 
325   return vt;
326 
327   tidy:
328   rasqal_free_variables_table(vt);
329   vt = NULL;
330 
331   return vt;
332 }
333 
334 
335 rasqal_variables_table*
rasqal_new_variables_table_from_variables_table(rasqal_variables_table * vt)336 rasqal_new_variables_table_from_variables_table(rasqal_variables_table* vt)
337 {
338   vt->usage++;
339   return vt;
340 }
341 
342 
343 /**
344  * rasqal_free_variables_table:
345  * @vt: rasqal variables table
346  *
347  * Destructor - destroy a new variables table
348  */
349 void
rasqal_free_variables_table(rasqal_variables_table * vt)350 rasqal_free_variables_table(rasqal_variables_table* vt)
351 {
352   if(!vt)
353     return;
354 
355   if(--vt->usage)
356     return;
357 
358   if(vt->variables)
359     RASQAL_FREE(vararray, vt->variables);
360 
361   if(vt->anon_variables_sequence)
362     raptor_free_sequence(vt->anon_variables_sequence);
363 
364   if(vt->variables_sequence)
365     raptor_free_sequence(vt->variables_sequence);
366 
367   if(vt->variable_names)
368     RASQAL_FREE(cstrings, vt->variable_names);
369 
370   RASQAL_FREE(rasqal_variables_table, vt);
371 }
372 
373 
374 /**
375  * rasqal_variables_table_add_variable:
376  * @vt: #rasqal_variables_table to associate the variable with
377  * @variable: existing variable to add
378  *
379  * Constructor - Add an existing variable to the variables table
380  *
381  * The variables table @vt takes a reference to @variable.  This
382  * function will fail if the variable is already in the table.  Use
383  * rasqal_variables_table_contains() to check before calling.
384  *
385  * Return value: non-0 on failure (such as name already exists)
386  **/
387 int
rasqal_variables_table_add_variable(rasqal_variables_table * vt,rasqal_variable * variable)388 rasqal_variables_table_add_variable(rasqal_variables_table* vt,
389                                     rasqal_variable* variable)
390 {
391   raptor_sequence* seq = NULL;
392   int* count_p = NULL;
393 
394   if(!vt)
395     return 1;
396 
397   switch(variable->type) {
398     case RASQAL_VARIABLE_TYPE_ANONYMOUS:
399       seq = vt->anon_variables_sequence;
400       count_p = &vt->anon_variables_count;
401       break;
402     case RASQAL_VARIABLE_TYPE_NORMAL:
403       seq = vt->variables_sequence;
404       count_p = &vt->variables_count;
405       break;
406 
407     case RASQAL_VARIABLE_TYPE_UNKNOWN:
408     default:
409       RASQAL_DEBUG2("Unknown variable type %u", variable->type);
410       return 1;
411   }
412 
413   if(rasqal_variables_table_contains(vt, variable->type, variable->name))
414     /* variable with this name already present - error */
415     return 1;
416 
417   /* add a new v reference for the variables table's sequence */
418   variable = rasqal_new_variable_from_variable(variable);
419   if(raptor_sequence_push(seq, variable))
420     return 1;
421 
422   variable->offset = (*count_p);
423 
424   (*count_p)++;
425 
426   if(variable->type == RASQAL_VARIABLE_TYPE_ANONYMOUS) {
427     /* new anon variable: add base offset */
428     variable->offset += vt->variables_count;
429   } else {
430     int i;
431 
432     /* new normal variable: move all anon variable offsets up 1 */
433     for(i = 0; i < vt->anon_variables_count; i++) {
434       rasqal_variable* anon_v;
435       anon_v = (rasqal_variable*)raptor_sequence_get_at(vt->anon_variables_sequence, i);
436       anon_v->offset++;
437     }
438   }
439 
440   if(vt->variable_names) {
441     RASQAL_FREE(cstrings, vt->variable_names);
442     vt->variable_names = NULL;
443   }
444 
445   return 0;
446 }
447 
448 
449 /**
450  * rasqal_variables_table_add2:
451  * @vt: #rasqal_variables_table to associate the variable with
452  * @type: variable type defined by enumeration rasqal_variable_type
453  * @name: variable name
454  * @name_len: length of @name (or 0)
455  * @value: variable #rasqal_literal value (or NULL)
456  *
457  * Constructor - Create a new variable and add it to the variables table
458  *
459  * The @name and @value fields are copied.  If a variable with the
460  * name already exists, that is returned and the new @value is
461  * ignored.
462  *
463  * Return value: a new #rasqal_variable or NULL on failure.
464  **/
465 rasqal_variable*
rasqal_variables_table_add2(rasqal_variables_table * vt,rasqal_variable_type type,const unsigned char * name,size_t name_len,rasqal_literal * value)466 rasqal_variables_table_add2(rasqal_variables_table* vt,
467                             rasqal_variable_type type,
468                             const unsigned char *name, size_t name_len,
469                             rasqal_literal *value)
470 {
471   rasqal_variable* v = NULL;
472 
473   if(!vt || !name)
474     goto failed;
475 
476   if(!name_len)
477     name_len = strlen(RASQAL_GOOD_CAST(const char*, name));
478 
479   if(!name_len)
480     goto failed;
481 
482   /* If already present, just return a new reference to it */
483   v = rasqal_variables_table_get_by_name(vt, type, name);
484   if(v)
485     return rasqal_new_variable_from_variable(v);
486 
487   v = RASQAL_CALLOC(rasqal_variable*, 1, sizeof(*v));
488   if(!v)
489     goto failed;
490 
491   v->offset = -1;
492   v->usage = 1;
493   v->vars_table = vt;
494   v->type = type;
495   v->name = RASQAL_MALLOC(unsigned char*, name_len + 1);
496   memcpy(RASQAL_GOOD_CAST(char*, v->name), name, name_len + 1);
497   v->value = rasqal_new_literal_from_literal(value);
498 
499   if(rasqal_variables_table_add_variable(vt, v))
500     goto failed;
501 
502   return v;
503 
504 
505   failed:
506   if(v)
507     RASQAL_FREE(rasqal_variable*, v);
508 
509   return NULL;
510 }
511 
512 
513 /**
514  * rasqal_variables_table_add:
515  * @vt: #rasqal_variables_table to associate the variable with
516  * @type: variable type defined by enumeration rasqal_variable_type
517  * @name: variable name
518  * @value: variable #rasqal_literal value (or NULL)
519  *
520  * Constructor - Create a new variable and add it to the variables table
521  *
522  * @Deprecated: for rasqal_variables_table_add2() which copies the @name
523  * and @value
524  *
525  * The @name and @value become owned by the rasqal_variable
526  * structure.  If a variable with the name already exists, that is
527  * returned and the new @value is ignored.
528  *
529  * Return value: a new #rasqal_variable or NULL on failure.
530  **/
531 rasqal_variable*
rasqal_variables_table_add(rasqal_variables_table * vt,rasqal_variable_type type,const unsigned char * name,rasqal_literal * value)532 rasqal_variables_table_add(rasqal_variables_table* vt,
533                            rasqal_variable_type type,
534                            const unsigned char *name, rasqal_literal *value)
535 {
536   rasqal_variable* v;
537 
538   if(!vt || !name)
539     return NULL;
540 
541   v = rasqal_variables_table_add2(vt, type, name, 0, value);
542   RASQAL_FREE(char*, name);
543   if(value)
544     rasqal_free_literal(value);
545   return v;
546 }
547 
548 
549 rasqal_variable*
rasqal_variables_table_get(rasqal_variables_table * vt,int idx)550 rasqal_variables_table_get(rasqal_variables_table* vt, int idx)
551 {
552   raptor_sequence* seq = NULL;
553 
554   if(idx < 0)
555     return NULL;
556 
557   if(idx < vt->variables_count)
558     seq = vt->variables_sequence;
559   else {
560     idx -= vt->variables_count;
561     seq = vt->anon_variables_sequence;
562   }
563 
564   return (rasqal_variable*)raptor_sequence_get_at(seq, idx);
565 }
566 
567 
568 rasqal_literal*
rasqal_variables_table_get_value(rasqal_variables_table * vt,int idx)569 rasqal_variables_table_get_value(rasqal_variables_table* vt, int idx)
570 {
571   rasqal_variable* v;
572 
573   v = rasqal_variables_table_get(vt, idx);
574   if(!v)
575     return NULL;
576 
577   return v->value;
578 }
579 
580 
581 /**
582  * rasqal_variables_table_get_by_name:
583  * @vt: the variables table
584  * @type: the variable type to match or #RASQAL_VARIABLE_TYPE_UNKNOWN for any.
585  * @name: the variable type
586  *
587  * Lookup a variable by type and name in the variables table.
588  *
589  * Note that looking up for any type #RASQAL_VARIABLE_TYPE_UNKNOWN
590  * may a name match but for any type so in cases where the query has
591  * both a named and anonymous (extensional) variable, an arbitrary one
592  * will be returned.
593  *
594  * Return value: a shared pointer to the #rasqal_variable or NULL if not found
595  **/
596 rasqal_variable*
rasqal_variables_table_get_by_name(rasqal_variables_table * vt,rasqal_variable_type type,const unsigned char * name)597 rasqal_variables_table_get_by_name(rasqal_variables_table* vt,
598                                    rasqal_variable_type type,
599                                    const unsigned char *name)
600 {
601   int i;
602   rasqal_variable* v;
603 
604   for(i = 0; (v = rasqal_variables_table_get(vt, i)); i++) {
605     if(((type != RASQAL_VARIABLE_TYPE_UNKNOWN) && v->type == type) &&
606        !strcmp(RASQAL_GOOD_CAST(const char*, v->name),
607                RASQAL_GOOD_CAST(const char*, name)))
608       return v;
609   }
610   return NULL;
611 }
612 
613 
614 /**
615  * rasqal_variables_table_contains:
616  * @vt: #rasqal_variables_table to lookup
617  * @type: variable type
618  * @name: variable name
619  *
620  * Check if there is a variable with the given type and name in the variables table
621  *
622  * Return value: non-0 if the variable is present
623  */
624 int
rasqal_variables_table_contains(rasqal_variables_table * vt,rasqal_variable_type type,const unsigned char * name)625 rasqal_variables_table_contains(rasqal_variables_table* vt,
626                                 rasqal_variable_type type,
627                                 const unsigned char *name)
628 {
629   return (rasqal_variables_table_get_by_name(vt, type, name) != NULL);
630 }
631 
632 
633 int
rasqal_variables_table_set(rasqal_variables_table * vt,rasqal_variable_type type,const unsigned char * name,rasqal_literal * value)634 rasqal_variables_table_set(rasqal_variables_table* vt,
635                            rasqal_variable_type type,
636                            const unsigned char *name, rasqal_literal* value)
637 {
638   rasqal_variable* v;
639 
640   v = rasqal_variables_table_get_by_name(vt, type, name);
641   if(!v)
642     return 1;
643 
644   rasqal_variable_set_value(v, value);
645   return 0;
646 }
647 
648 
649 int
rasqal_variables_table_get_named_variables_count(rasqal_variables_table * vt)650 rasqal_variables_table_get_named_variables_count(rasqal_variables_table* vt)
651 {
652   return vt->variables_count;
653 }
654 
655 
656 int
rasqal_variables_table_get_anonymous_variables_count(rasqal_variables_table * vt)657 rasqal_variables_table_get_anonymous_variables_count(rasqal_variables_table* vt)
658 {
659   return vt->anon_variables_count;
660 }
661 
662 
663 int
rasqal_variables_table_get_total_variables_count(rasqal_variables_table * vt)664 rasqal_variables_table_get_total_variables_count(rasqal_variables_table* vt)
665 {
666   return vt->variables_count + vt->anon_variables_count;
667 }
668 
669 
670 raptor_sequence*
rasqal_variables_table_get_named_variables_sequence(rasqal_variables_table * vt)671 rasqal_variables_table_get_named_variables_sequence(rasqal_variables_table* vt)
672 {
673   return vt->variables_sequence;
674 }
675 
676 
677 raptor_sequence*
rasqal_variables_table_get_anonymous_variables_sequence(rasqal_variables_table * vt)678 rasqal_variables_table_get_anonymous_variables_sequence(rasqal_variables_table* vt)
679 {
680   return vt->anon_variables_sequence;
681 }
682 
683 
684 const unsigned char**
rasqal_variables_table_get_names(rasqal_variables_table * vt)685 rasqal_variables_table_get_names(rasqal_variables_table* vt)
686 {
687   int size = vt->variables_count;
688 
689   if(!vt->variable_names && size) {
690     int i;
691 
692     vt->variable_names = RASQAL_CALLOC(const unsigned char**, RASQAL_GOOD_CAST(size_t, (size + 1)),
693                                        sizeof(unsigned char*));
694     if(!vt->variable_names)
695       return NULL;
696 
697     for(i = 0; i < size; i++) {
698       rasqal_variable* v;
699 
700       v = (rasqal_variable*)raptor_sequence_get_at(vt->variables_sequence, i);
701       vt->variable_names[i] = v->name;
702     }
703   }
704 
705   return vt->variable_names;
706 }
707 
708 
709 /*
710  * Deep copy a sequence of rasqal_variable to a new one.
711  */
712 raptor_sequence*
rasqal_variable_copy_variable_sequence(raptor_sequence * vars_seq)713 rasqal_variable_copy_variable_sequence(raptor_sequence* vars_seq)
714 {
715   raptor_sequence* nvars_seq = NULL;
716   int size;
717   int i;
718 
719   if(!vars_seq)
720     return NULL;
721 
722   nvars_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
723                                   (raptor_data_print_handler)rasqal_variable_print);
724   if(!nvars_seq)
725     return NULL;
726 
727   size = raptor_sequence_size(vars_seq);
728   for(i = 0; i < size; i++) {
729     rasqal_variable* v;
730 
731     v = (rasqal_variable*)raptor_sequence_get_at(vars_seq, i);
732     v = rasqal_new_variable_from_variable(v);
733     raptor_sequence_set_at(nvars_seq, i, v);
734   }
735 
736   return nvars_seq;
737 }
738 
739 
740 
741 #if RAPTOR_VERSION < 20015
742 /* pointers are rasqal_variable** */
743 static int
rasqal_variable_compare_by_name_arg(const void * a,const void * b,void * arg)744 rasqal_variable_compare_by_name_arg(const void *a, const void *b, void *arg)
745 {
746   rasqal_variable *var_a;
747   rasqal_variable *var_b;
748 
749   var_a = *(rasqal_variable**)a;
750   var_b = *(rasqal_variable**)b;
751 
752   return strcmp(RASQAL_GOOD_CAST(const char*, var_a->name),
753                 RASQAL_GOOD_CAST(const char*, var_b->name));
754 }
755 
756 #else
757 /* pointers are int* */
758 static int
rasqal_order_compare_by_name_arg(const void * a,const void * b,void * arg)759 rasqal_order_compare_by_name_arg(const void *a, const void *b, void *arg)
760 {
761   int offset_a;
762   int offset_b;
763   rasqal_variables_table* vt;
764   const unsigned char* name_a;
765   const unsigned char* name_b;
766 
767   offset_a = *(int*)a;
768   offset_b = *(int*)b;
769   vt = (rasqal_variables_table*)arg;
770 
771   name_a = rasqal_variables_table_get(vt, offset_a)->name;
772   name_b = rasqal_variables_table_get(vt, offset_b)->name;
773 
774   return strcmp(RASQAL_GOOD_CAST(const char*, name_a),
775                 RASQAL_GOOD_CAST(const char*, name_b));
776 }
777 #endif
778 
779 
780 /*
781  * rasqal_variables_table_get_order:
782  * @vt: variables table
783  *
784  * INTERNAL - Get the order of the variables in sort order
785  *
786  * Return value: array of integers of order variables (terminated by integer < 0) or NULL on failure
787 */
788 int*
rasqal_variables_table_get_order(rasqal_variables_table * vt)789 rasqal_variables_table_get_order(rasqal_variables_table* vt)
790 {
791   raptor_sequence* seq;
792   int size;
793   int* order;
794   int i;
795 #if RAPTOR_VERSION < 20015
796   void** array;
797 #endif
798 
799   seq = rasqal_variables_table_get_named_variables_sequence(vt);
800   if(!seq)
801     return NULL;
802 
803   size = raptor_sequence_size(seq);
804   if(!size)
805     return NULL;
806 
807   order = RASQAL_CALLOC(int*, RASQAL_GOOD_CAST(size_t, size + 1), sizeof(int));
808   if(!order)
809     return NULL;
810 
811 #if RAPTOR_VERSION < 20015
812   array = rasqal_sequence_as_sorted(seq, rasqal_variable_compare_by_name_arg,
813                                     vt);
814   if(!array)
815     return NULL;
816 
817   for(i = 0; i < size; i++)
818     order[i] = (RASQAL_GOOD_CAST(rasqal_variable*, array[i]))->offset;
819   RASQAL_FREE(void*, array);
820 #else
821   for(i = 0; i < size; i++)
822     order[i] = i;
823 
824   raptor_sort_r(order, size, sizeof(int), rasqal_order_compare_by_name_arg, vt);
825 #endif
826   order[size] = -1;
827 
828   return order;
829 }
830 
831 
832 #endif /* not STANDALONE */
833 
834 
835 
836 #ifdef STANDALONE
837 #include <stdio.h>
838 
839 int main(int argc, char *argv[]);
840 
841 
842 int
main(int argc,char * argv[])843 main(int argc, char *argv[])
844 {
845   const char *program = rasqal_basename(argv[0]);
846   rasqal_world* world = NULL;
847   rasqal_variables_table* vt = NULL;
848 #define NUM_VARS 3
849   const char* var_names[NUM_VARS] = {"normal-null", "normal-value", "anon"};
850   rasqal_variable* vars[NUM_VARS];
851   rasqal_literal *value = NULL;
852   int i;
853   int rc = 0;
854 
855   world = rasqal_new_world();
856   if(!world || rasqal_world_open(world)) {
857     fprintf(stderr, "%s: rasqal_world init failed\n", program);
858     rc = 1;
859     goto tidy;
860   }
861 
862   vt = rasqal_new_variables_table(world);
863   if(!vt) {
864     fprintf(stderr, "%s: Failed to make variables table\n", program);
865     rc = 1;
866     goto tidy;
867   }
868 
869   vars[0] = rasqal_variables_table_add2(vt, RASQAL_VARIABLE_TYPE_NORMAL,
870                                         RASQAL_GOOD_CAST(const unsigned char*, var_names[0]),
871                                         0, NULL);
872   if(!vars[0]) {
873     fprintf(stderr, "%s: Failed to make normal variable with NULL value\n",
874             program);
875     rc = 1;
876     goto tidy;
877   }
878   /* vars[0] now owned by vt */
879 
880   value = rasqal_new_double_literal(world, 42.0);
881   if(!value) {
882     fprintf(stderr, "%s: Failed to make double literal\n", program);
883     rc = 1;
884     goto tidy;
885   }
886   vars[1] = rasqal_variables_table_add2(vt, RASQAL_VARIABLE_TYPE_NORMAL,
887                                         RASQAL_GOOD_CAST(const unsigned char*, var_names[1]),
888                                         0, value);
889   if(!vars[1]) {
890     fprintf(stderr, "%s: Failed to make normal variable with literal value\n",
891             program);
892     rc = 1;
893     goto tidy;
894   }
895   /* vars[1] now owned by vt */
896 
897   vars[2] = rasqal_variables_table_add2(vt, RASQAL_VARIABLE_TYPE_ANONYMOUS,
898                                         RASQAL_GOOD_CAST(const unsigned char*, var_names[2]),
899                                         0, NULL);
900   if(!vars[2]) {
901     fprintf(stderr, "%s: Failed to make anonymous variable with NULL value\n",
902             program);
903     rc = 1;
904     goto tidy;
905   }
906   /* vars[2] now owned by vt */
907 
908   tidy:
909   for(i = 0; i < NUM_VARS; i++) {
910     if(vars[i])
911       rasqal_free_variable(vars[i]);
912   }
913 
914   if(value)
915     rasqal_free_literal(value);
916   if(vt)
917     rasqal_free_variables_table(vt);
918 
919   if(world)
920     rasqal_free_world(world);
921 
922   return rc;
923 }
924 #endif /* STANDALONE */
925