Merge branch 'master' of github.com:periscop/openscop
[openscop.git] / source / generic.c
blob312c9cfe4d7fa3dc7be2c68ae723eceeffeb752d
2 /*+-----------------------------------------------------------------**
3 ** OpenScop Library **
4 **-----------------------------------------------------------------**
5 ** generic.c **
6 **-----------------------------------------------------------------**
7 ** First version: 26/11/2010 **
8 **-----------------------------------------------------------------**
11 *****************************************************************************
12 * OpenScop: Structures and formats for polyhedral tools to talk together *
13 *****************************************************************************
14 * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, *
15 * / / / // // // // / / / // // / / // / /|,_, *
16 * / / / // // // // / / / // // / / // / / / /\ *
17 * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ *
18 * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ *
19 * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ *
20 * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ *
21 * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ *
22 * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ *
23 * | I | | | | e | | | | | | | | | | | | | \ \ \ *
24 * | T | | | | | | | | | | | | | | | | | \ \ \ *
25 * | E | | | | | | | | | | | | | | | | | \ \ \ *
26 * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ *
27 * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / *
28 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
29 * *
30 * Copyright (C) 2008 University Paris-Sud 11 and INRIA *
31 * *
32 * (3-clause BSD license) *
33 * Redistribution and use in source and binary forms, with or without *
34 * modification, are permitted provided that the following conditions *
35 * are met: *
36 * *
37 * 1. Redistributions of source code must retain the above copyright notice, *
38 * this list of conditions and the following disclaimer. *
39 * 2. Redistributions in binary form must reproduce the above copyright *
40 * notice, this list of conditions and the following disclaimer in the *
41 * documentation and/or other materials provided with the distribution. *
42 * 3. The name of the author may not be used to endorse or promote products *
43 * derived from this software without specific prior written permission. *
44 * *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
55 * *
56 * OpenScop Library, a library to manipulate OpenScop formats and data *
57 * structures. Written by: *
58 * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and *
59 * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> *
60 * *
61 *****************************************************************************/
63 #include <stdlib.h>
64 #include <stdio.h>
65 #include <string.h>
67 #include <osl/macros.h>
68 #include <osl/util.h>
69 #include <osl/interface.h>
70 #include <osl/generic.h>
71 #include <osl/extensions/arrays.h>
74 /*+***************************************************************************
75 * Structure display function *
76 *****************************************************************************/
79 /**
80 * osl_generic_idump function:
81 * this function displays an osl_generic_t structure (*generic) into
82 * a file (file, possibly stdout) in a way that trends to be understandable.
83 * It includes an indentation level (level) in order to work with others
84 * idump functions.
85 * \param[in] file File where informations are printed.
86 * \param[in] generic The generic whose information has to be printed.
87 * \param[in] level Number of spaces before printing, for each line.
89 void osl_generic_idump(FILE * file, osl_generic_p generic, int level) {
90 int j, first = 1;
92 // Go to the right level.
93 for (j = 0; j < level; j++)
94 fprintf(file,"|\t");
96 if (generic != NULL)
97 fprintf(file, "+-- osl_generic_t\n");
98 else
99 fprintf(file, "+-- NULL generic\n");
101 while (generic != NULL) {
102 if (!first) {
103 // Go to the right level.
104 for (j = 0; j < level; j++)
105 fprintf(file, "|\t");
106 fprintf(file, "| osl_generic_t\n");
108 else {
109 first = 0;
112 // A blank line
113 for(j = 0; j <= level + 1; j++)
114 fprintf(file, "|\t");
115 fprintf(file, "\n");
117 osl_interface_idump(file, generic->interface, level + 1);
119 if (generic->interface != NULL)
120 generic->interface->idump(file, generic->data, level + 1);
122 generic = generic->next;
124 // Next line.
125 if (generic != NULL) {
126 for (j = 0; j <= level; j++)
127 fprintf(file, "|\t");
128 fprintf(file, "V\n");
132 // The last line.
133 for (j = 0; j <= level; j++)
134 fprintf(file, "|\t");
135 fprintf(file, "\n");
140 * osl_generic_dump function:
141 * this function prints the content of an osl_generic_t structure
142 * (*generic) into a file (file, possibly stdout).
143 * \param[in] file File where the information has to be printed.
144 * \param[in] generic The generic structure to print.
146 void osl_generic_dump(FILE * file, osl_generic_p generic) {
147 osl_generic_idump(file, generic, 0);
152 * osl_generic_sprint function:
153 * this function prints the content of an osl_generic_t structure
154 * (*strings) into a string (returned) in the OpenScop textual format.
155 * \param[in] generic The generic structure which has to be printed.
156 * \return A string containing the OpenScop dump of the generic structure.
158 char * osl_generic_sprint(osl_generic_p generic) {
159 int high_water_mark = OSL_MAX_STRING;
160 char * string = NULL, * content;
161 char buffer[OSL_MAX_STRING];
163 OSL_malloc(string, char *, high_water_mark * sizeof(char));
164 string[0] = '\0';
166 while (generic != NULL) {
167 if (generic->interface != NULL) {
168 content = generic->interface->sprint(generic->data);
169 if (content != NULL) {
170 sprintf(buffer, "<%s>\n", generic->interface->URI);
171 osl_util_safe_strcat(&string, buffer, &high_water_mark);
172 osl_util_safe_strcat(&string, content, &high_water_mark);
173 free(content);
174 sprintf(buffer, "</%s>\n", generic->interface->URI);
175 osl_util_safe_strcat(&string, buffer, &high_water_mark);
178 generic = generic->next;
179 if (generic != NULL) {
180 sprintf(buffer, "\n");
181 osl_util_safe_strcat(&string, buffer, &high_water_mark);
185 return string;
190 * osl_generic_print function:
191 * this function prints the content of an osl_generic_t structure
192 * (*generic) into a string (returned) in the OpenScop format.
193 * \param[in] file File where the information has to be printed.
194 * \param[in] generic The generic structure to print.
196 void osl_generic_print(FILE * file, osl_generic_p generic) {
197 char * string;
199 string = osl_generic_sprint(generic);
200 if (string != NULL) {
201 fprintf(file, "%s", string);
202 free(string);
208 * osl_generic_print_options_scoplib function:
209 * this function prints the options sections (only arrays in the
210 * SCoPLib format)
211 * \param[in] file File where the information has to be printed.
212 * \param[in] generic The generic structure to print.
214 void osl_generic_print_options_scoplib(FILE * file, osl_generic_p generic) {
215 char * string;
217 osl_generic_p arrays = osl_generic_lookup(generic, OSL_URI_ARRAYS);
219 string = osl_arrays_sprint((osl_arrays_p) arrays);
220 if (string != NULL) {
221 fprintf(file, "<arrays>\n%s</arrays>\n", string);
222 free(string);
227 /*****************************************************************************
228 * Reading function *
229 *****************************************************************************/
233 * osl_generic_sread function:
234 * this function reads a list of generic structure from a string complying to
235 * the OpenScop textual format and returns a pointer to this generic structure.
236 * The input parameter is updated to the position in the input string this
237 * function reach right after reading the generic structure.
238 * \param[in,out] input The input string where to find a list of generic.
239 * Updated to the position after what has been read.
240 * \param[in] registry The list of known interfaces (others are ignored).
241 * \return A pointer to the generic information list that has been read.
243 osl_generic_p osl_generic_sread(char ** input, osl_interface_p registry) {
244 osl_generic_p generic = NULL, new;
246 while (**input != '\0') {
247 new = osl_generic_sread_one(input, registry);
248 osl_generic_add(&generic, new);
251 return generic;
256 * osl_generic_sread_one function:
257 * this function reads one generic structure from a string complying to the
258 * OpenScop textual format and returns a pointer to this generic structure.
259 * The input parameter is updated to the position in the input string this
260 * function reach right after reading the generic structure.
261 * \param[in,out] input The input string where to find a generic.
262 * Updated to the position after what has been read.
263 * \param[in] registry The list of known interfaces (others are ignored).
264 * \return A pointer to the generic structure that has been read.
266 osl_generic_p osl_generic_sread_one(char ** input, osl_interface_p registry) {
267 char * tag;
268 char * content, * temp;
269 osl_generic_p generic = NULL;
270 osl_interface_p interface;
272 tag = osl_util_read_tag(NULL, input);
273 if ((tag == NULL) || (strlen(tag) < 1) || (tag[0] == '/')) {
274 OSL_debug("empty tag name or closing tag instead of an opening one");
275 return NULL;
278 content = osl_util_read_uptoendtag(NULL, input, tag);
279 interface = osl_interface_lookup(registry, tag);
281 temp = content;
282 if (interface == NULL) {
283 OSL_warning("unsupported generic");
284 fprintf(stderr, "[osl] Warning: unknown URI \"%s\".\n", tag);
286 else {
287 generic = osl_generic_malloc();
288 generic->interface = osl_interface_nclone(interface, 1);
289 generic->data = interface->sread(&temp);
292 free(content);
293 free(tag);
294 return generic;
299 * osl_generic_read_one function:
300 * this function reads one generic from a file (possibly stdin)
301 * complying to the OpenScop textual format and a list of known interfaces.
302 * It returns a pointer to the corresponding generic structure. If no
303 * tag is found, an error is reported, in the case of an empty or closing tag
304 * name the function returns the NULL pointer.
305 * \param[in] file The input file where to read a list of data.
306 * \param[in] registry The list of known interfaces (others are ignored).
307 * \return A pointer to the generic that has been read.
309 osl_generic_p osl_generic_read_one(FILE * file, osl_interface_p registry) {
310 char * tag;
311 char * content, * temp;
312 osl_generic_p generic = NULL;
313 osl_interface_p interface;
315 tag = osl_util_read_tag(file, NULL);
316 if ((tag == NULL) || (strlen(tag) < 1) || (tag[0] == '/')) {
317 OSL_debug("empty tag name or closing tag instead of an opening one");
318 return NULL;
321 content = osl_util_read_uptoendtag(file, NULL, tag);
322 interface = osl_interface_lookup(registry, tag);
324 temp = content;
325 if (interface == NULL) {
326 OSL_warning("unsupported generic");
327 fprintf(stderr, "[osl] Warning: unknown URI \"%s\".\n", tag);
329 else {
330 generic = osl_generic_malloc();
331 generic->interface = osl_interface_nclone(interface, 1);
332 generic->data = interface->sread(&temp);
335 free(content);
336 free(tag);
337 return generic;
342 * osl_generic_read function:
343 * this function reads a list of generics from a file (possibly stdin)
344 * complying to the OpenScop textual format and a list of known interfaces.
345 * It returns a pointer to the list of corresponding generic structures.
346 * \param[in] file The input file where to read a list of data.
347 * \param[in] registry The list of known interfaces (others are ignored).
348 * \return A pointer to the generic information list that has been read.
350 osl_generic_p osl_generic_read(FILE * file, osl_interface_p registry) {
351 char * generic_string, * temp;
352 osl_generic_p generic_list;
354 generic_string = osl_util_read_uptoendtag(file, NULL, OSL_URI_SCOP);
355 temp = generic_string;
356 generic_list = osl_generic_sread(&temp, registry);
357 free(generic_string);
358 return generic_list;
362 /*+***************************************************************************
363 * Memory allocation/deallocation function *
364 *****************************************************************************/
368 * osl_generic_add function:
369 * this function adds a generic node (it may be a list as well) to a list
370 * of generics provided as parameter (list). The new node is inserted at
371 * the end of the list.
372 * \param[in] list The list of generics to add a node (NULL if empty).
373 * \param[in] generic The generic list to add to the initial list.
375 void osl_generic_add(osl_generic_p * list, osl_generic_p generic) {
376 osl_generic_p tmp = *list, check;
378 if (generic != NULL) {
379 // First, check that the generic list is OK.
380 check = generic;
381 while (check != NULL) {
382 if ((check->interface == NULL) || (check->interface->URI == NULL))
383 OSL_error("no interface or URI in a generic to add to a list");
385 // TODO: move this to the integrity check.
386 if (osl_generic_lookup(*list, check->interface->URI) != NULL)
387 OSL_error("only one generic with a given URI is allowed");
388 check = check->next;
391 if (*list != NULL) {
392 while (tmp->next != NULL)
393 tmp = tmp->next;
394 tmp->next = generic;
396 else {
397 *list = generic;
403 * osl_generic_remove_node function:
404 * this functions removes a given generic from a generic list
405 * \param[in] list Address of a generic list
406 * \param[in] generic Pointer to the generic to be removed
407 * Assumes a single node is to be removed.
409 void osl_generic_remove_node(osl_generic_p * list, osl_generic_p generic) {
411 osl_generic_p tmp = NULL;
413 if (generic != NULL) {
415 if (*list != NULL) {
416 //target is the first element of list
417 if(*list==generic){
418 *list = generic->next;
419 generic->next=NULL; //free below removes the whole list!
420 osl_generic_free(generic);
421 return;
424 //find target
425 tmp = *list;
426 while (tmp->next!=generic && tmp->next != NULL)
427 tmp = tmp->next;
429 if(tmp->next==generic){
430 tmp->next = generic->next;
431 generic->next=NULL; //free below removes the whole list!
432 osl_generic_free(generic);
434 else //target not found
435 OSL_warning("generic not found in the list\n");
442 * osl_generic_remove function:
443 * given a URI, this function removes that generic from the list
444 * \param[in] list Address of a generic list
445 * \param[in] URI Pointer to the URI string
447 void osl_generic_remove(osl_generic_p *list, char * URI){
449 osl_generic_p tmp = *list;
451 while(tmp != NULL){
452 if(osl_generic_has_URI(tmp, URI))
453 break;
454 tmp = tmp->next;
457 if(tmp!=NULL){
458 osl_generic_remove_node(list, tmp);
465 * osl_generic_malloc function:
466 * This function allocates the memory space for an osl_generic_t
467 * structure and sets its fields with default values. Then it returns a
468 * pointer to the allocated space.
469 * \return A pointer to an empty generic structure with fields set to
470 * default values.
472 osl_generic_p osl_generic_malloc() {
473 osl_generic_p generic;
475 OSL_malloc(generic, osl_generic_p, sizeof(osl_generic_t));
476 generic->interface = NULL;
477 generic->data = NULL;
478 generic->next = NULL;
480 return generic;
485 * osl_generic_free function:
486 * This function frees the allocated memory for a generic structure.
487 * \param[in] generic The pointer to the generic structure we want to free.
489 void osl_generic_free(osl_generic_p generic) {
490 osl_generic_p next;
492 while (generic != NULL) {
493 next = generic->next;
494 if (generic->interface != NULL) {
495 generic->interface->free(generic->data);
496 osl_interface_free(generic->interface);
498 else {
499 if (generic->data != NULL) {
500 OSL_warning("unregistered interface, memory leaks are possible");
501 free(generic->data);
504 free(generic);
505 generic = next;
510 /*+***************************************************************************
511 * Processing functions *
512 *****************************************************************************/
516 * osl_generic_number function:
517 * this function returns the number of statements in the generic list
518 * provided as parameter.
519 * \param[in] generic The first element of the generic list.
520 * \return The number of statements in the generic list.
522 int osl_generic_number(osl_generic_p generic) {
523 int number = 0;
525 while (generic != NULL) {
526 number++;
527 generic = generic->next;
529 return number;
534 * osl_generic_clone function:
535 * This function builds and returns a "hard copy" (not a pointer copy) of an
536 * osl_generic_t data structure.
537 * \param[in] generic The pointer to the generic structure we want to clone.
538 * \return A pointer to the clone of the input generic structure.
540 osl_generic_p osl_generic_clone(osl_generic_p generic) {
541 return osl_generic_nclone(generic, -1);
546 * \brief This function builds and returns a "hard copy" (not a pointer copy)
547 * of the n first elements of an osl_generic_t list.
549 * \param generic The pointer to the generic structure we want to clone.
550 * \param n The number of nodes we want to copy (n<0 for infinity).
551 * \return The clone of the n first nodes of the generic list.
553 osl_generic_p osl_generic_nclone(osl_generic_p generic, int n)
555 osl_generic_p clone = NULL, new;
556 osl_interface_p interface;
557 void * x;
559 if (n < 0) {
560 n = osl_generic_count(generic);
563 while ((generic != NULL) && (n > 0)) {
564 if (generic->interface != NULL) {
565 x = generic->interface->clone(generic->data);
566 interface = osl_interface_clone(generic->interface);
567 new = osl_generic_malloc();
568 new->interface = interface;
569 new->data = x;
570 osl_generic_add(&clone, new);
571 } else {
572 OSL_warning("unregistered interface, cloning ignored");
574 generic = generic->next;
575 n--;
578 return clone;
583 * osl_generic_count function:
584 * this function counts the number of elements in the generic list provided
585 * as parameter (x) and returns this number.
586 * \param[in] x The list of generics.
587 * \return The number of elements in the list.
589 int osl_generic_count(osl_generic_p x) {
590 int generic_number = 0;
592 while (x != NULL) {
593 generic_number++;
594 x = x->next;
597 return generic_number;
602 * osl_generic_equal function:
603 * this function returns true if the two generic structures are the same,
604 * false otherwise. This functions considers two generic structures as equal
605 * independently of the order of the nodes.
606 * \param[in] x1 The first generic structure.
607 * \param[in] x2 The second generic structure.
608 * \return 1 if x1 and x2 are the same (content-wise), 0 otherwise.
610 int osl_generic_equal(osl_generic_p x1, osl_generic_p x2) {
611 int x1_generic_number, x2_generic_number;
612 int found, equal;
613 osl_generic_p backup_x2 = x2;
615 if (x1 == x2)
616 return 1;
618 // Check whether the number of generics is the same or not.
619 x1_generic_number = osl_generic_count(x1);
620 x2_generic_number = osl_generic_count(x2);
621 if (x1_generic_number != x2_generic_number)
622 return 0;
624 // Check that for each generic in x1 a similar generic is in x2.
625 while (x1 != NULL) {
626 x2 = backup_x2;
627 found = 0;
628 while ((x2 != NULL) && (found != 1)) {
629 if (osl_interface_equal(x1->interface, x2->interface)) {
630 if (x1->interface != NULL) {
631 equal = x1->interface->equal(x1->data, x2->data);
633 else {
634 OSL_warning("unregistered generic, "
635 "cannot state generic equality");
636 equal = 0;
639 if (equal == 0)
640 return 0;
641 else
642 found = 1;
645 x2 = x2->next;
648 if (found != 1)
649 return 0;
651 x1 = x1->next;
654 return 1;
659 * osl_generic_has_URI function:
660 * this function returns 1 if the generic provided as parameter has
661 * a given URI, 0 other wise.
662 * \param[in] x The generic structure to test.
663 * \param[in] URI The URI value to test.
664 * \return 1 if x has the provided URI, 0 otherwise.
666 int osl_generic_has_URI(osl_const_generic_const_p x, char const * const URI) {
668 if ((x == NULL) ||
669 (x->interface == NULL) ||
670 (x->interface->URI == NULL) ||
671 (strcmp(x->interface->URI, URI)))
672 return 0;
674 return 1;
679 * osl_generic_lookup function:
680 * this function returns the first generic with a given URI in the
681 * generic list provided as parameter and NULL if it doesn't find such
682 * a generic.
683 * \param[in] x The generic list where to search a given generic URI.
684 * \param[in] URI The URI of the generic we are looking for.
685 * \return The first generic of the requested URI in the list.
687 void * osl_generic_lookup(osl_generic_p x, char const * const URI) {
688 while (x != NULL) {
689 if (osl_generic_has_URI(x, URI))
690 return x->data;
692 x = x->next;
695 return NULL;
700 * osl_generic_shell function:
701 * this function creates and returns a generic structure "shell" which
702 * embed the data and interface provided as parameters.
703 * \param[in] data Data to put in the generic shell.
704 * \param[in] interface Interface to put in the generic shell.
705 * \return A new generic structure containing the data and interface.
707 osl_generic_p osl_generic_shell(void * data, osl_interface_p interface) {
708 osl_generic_p generic = NULL;
710 if ((data == NULL) || (interface == NULL))
711 OSL_warning("shell created with some empty elements inside");
713 generic = osl_generic_malloc();
714 generic->data = data;
715 generic->interface = interface;
716 return generic;