2
/*+-----------------------------------------------------------------**
4
**-----------------------------------------------------------------**
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
* '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
30
* Copyright (C) 2008 University Paris-Sud 11 and INRIA *
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 *
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. *
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. *
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> *
61
*****************************************************************************/
67
#include <osl/macros.h>
69
#include <osl/interface.h>
70
#include <osl/generic.h>
71
#include <osl/extensions/arrays.h>
74
/*+***************************************************************************
75
* Structure display function *
76
*****************************************************************************/
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
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) {
92
// Go to the right level.
93
for (j = 0; j < level; j++)
97
fprintf(file, "+-- osl_generic_t\n");
99
fprintf(file, "+-- NULL generic\n");
101
while (generic != NULL) {
103
// Go to the right level.
104
for (j = 0; j < level; j++)
105
fprintf(file, "|\t");
106
fprintf(file, "| osl_generic_t\n");
113
for(j = 0; j <= level + 1; j++)
114
fprintf(file, "|\t");
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;
125
if (generic != NULL) {
126
for (j = 0; j <= level; j++)
127
fprintf(file, "|\t");
128
fprintf(file, "V\n");
133
for (j = 0; j <= level; j++)
134
fprintf(file, "|\t");
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));
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);
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);
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) {
199
string = osl_generic_sprint(generic);
200
if (string != NULL) {
201
fprintf(file, "%s", string);
208
* osl_generic_print_options_scoplib function:
209
* this function prints the options sections (only arrays in the
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) {
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);
227
/*****************************************************************************
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);
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) {
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");
278
content = osl_util_read_uptoendtag(NULL, input, tag);
279
interface = osl_interface_lookup(registry, tag);
282
if (interface == NULL) {
283
OSL_warning("unsupported generic");
284
fprintf(stderr, "[osl] Warning: unknown URI \"%s\".\n", tag);
287
generic = osl_generic_malloc();
288
generic->interface = osl_interface_nclone(interface, 1);
289
generic->data = interface->sread(&temp);
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) {
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");
321
content = osl_util_read_uptoendtag(file, NULL, tag);
322
interface = osl_interface_lookup(registry, tag);
325
if (interface == NULL) {
326
OSL_warning("unsupported generic");
327
fprintf(stderr, "[osl] Warning: unknown URI \"%s\".\n", tag);
330
generic = osl_generic_malloc();
331
generic->interface = osl_interface_nclone(interface, 1);
332
generic->data = interface->sread(&temp);
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);
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.
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");
392
while (tmp->next != NULL)
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 = *list;
413
if (generic != NULL) {
416
//target is the first element of list
418
*list = generic->next;
419
generic->next=NULL; //free below removes the whole list!
420
osl_generic_free(generic);
424
while (tmp->next!=generic && tmp->next != NULL)
427
if(tmp->next==generic){
428
tmp->next = generic->next;
429
generic->next=NULL; //free below removes the whole list!
430
osl_generic_free(generic);
432
else //target not found
433
OSL_warning("generic not found in the list\n");
440
* osl_generic_remove function:
441
* given a URI, this function removes that generic from the list
442
* \param[in] list Address of a generic list
443
* \param[in] URI Pointer to the URI string
445
void osl_generic_remove(osl_generic_p *list, char * URI){
447
osl_generic_p tmp = *list;
450
if(osl_generic_has_URI(tmp, URI))
456
osl_generic_remove_node(list, tmp);
463
* osl_generic_malloc function:
464
* This function allocates the memory space for an osl_generic_t
465
* structure and sets its fields with default values. Then it returns a
466
* pointer to the allocated space.
467
* \return A pointer to an empty generic structure with fields set to
470
osl_generic_p osl_generic_malloc() {
471
osl_generic_p generic;
473
OSL_malloc(generic, osl_generic_p, sizeof(osl_generic_t));
474
generic->interface = NULL;
475
generic->data = NULL;
476
generic->next = NULL;
483
* osl_generic_free function:
484
* This function frees the allocated memory for a generic structure.
485
* \param[in] generic The pointer to the generic structure we want to free.
487
void osl_generic_free(osl_generic_p generic) {
490
while (generic != NULL) {
491
next = generic->next;
492
if (generic->interface != NULL) {
493
generic->interface->free(generic->data);
494
osl_interface_free(generic->interface);
497
if (generic->data != NULL) {
498
OSL_warning("unregistered interface, memory leaks are possible");
508
/*+***************************************************************************
509
* Processing functions *
510
*****************************************************************************/
514
* osl_generic_number function:
515
* this function returns the number of statements in the generic list
516
* provided as parameter.
517
* \param[in] generic The first element of the generic list.
518
* \return The number of statements in the generic list.
520
int osl_generic_number(osl_generic_p generic) {
523
while (generic != NULL) {
525
generic = generic->next;
532
* osl_generic_clone function:
533
* This function builds and returns a "hard copy" (not a pointer copy) of an
534
* osl_generic_t data structure.
535
* \param[in] generic The pointer to the generic structure we want to clone.
536
* \return A pointer to the clone of the input generic structure.
538
osl_generic_p osl_generic_clone(osl_generic_p generic) {
539
osl_generic_p clone = NULL, new;
540
osl_interface_p interface;
543
while (generic != NULL) {
544
if (generic->interface != NULL) {
545
x = generic->interface->clone(generic->data);
546
interface = osl_interface_clone(generic->interface);
547
new = osl_generic_malloc();
548
new->interface = interface;
550
osl_generic_add(&clone, new);
553
OSL_warning("unregistered interface, cloning ignored");
555
generic = generic->next;
563
* osl_generic_count function:
564
* this function counts the number of elements in the generic list provided
565
* as parameter (x) and returns this number.
566
* \param[in] x The list of generics.
567
* \return The number of elements in the list.
569
int osl_generic_count(osl_generic_p x) {
570
int generic_number = 0;
577
return generic_number;
582
* osl_generic_equal function:
583
* this function returns true if the two generic structures are the same,
584
* false otherwise. This functions considers two generic structures as equal
585
* independently of the order of the nodes.
586
* \param[in] x1 The first generic structure.
587
* \param[in] x2 The second generic structure.
588
* \return 1 if x1 and x2 are the same (content-wise), 0 otherwise.
590
int osl_generic_equal(osl_generic_p x1, osl_generic_p x2) {
591
int x1_generic_number, x2_generic_number;
593
osl_generic_p backup_x2 = x2;
598
// Check whether the number of generics is the same or not.
599
x1_generic_number = osl_generic_count(x1);
600
x2_generic_number = osl_generic_count(x2);
601
if (x1_generic_number != x2_generic_number)
604
// Check that for each generic in x1 a similar generic is in x2.
608
while ((x2 != NULL) && (found != 1)) {
609
if (osl_interface_equal(x1->interface, x2->interface)) {
610
if (x1->interface != NULL) {
611
equal = x1->interface->equal(x1->data, x2->data);
614
OSL_warning("unregistered generic, "
615
"cannot state generic equality");
639
* osl_generic_has_URI function:
640
* this function returns 1 if the generic provided as parameter has
641
* a given URI, 0 other wise.
642
* \param[in] x The generic structure to test.
643
* \param[in] URI The URI value to test.
644
* \return 1 if x has the provided URI, 0 otherwise.
646
int osl_generic_has_URI(osl_generic_p x, char * URI) {
649
(x->interface == NULL) ||
650
(x->interface->URI == NULL) ||
651
(strcmp(x->interface->URI, URI)))
659
* osl_generic_lookup function:
660
* this function returns the first generic with a given URI in the
661
* generic list provided as parameter and NULL if it doesn't find such
663
* \param[in] x The generic list where to search a given generic URI.
664
* \param[in] URI The URI of the generic we are looking for.
665
* \return The first generic of the requested URI in the list.
667
void * osl_generic_lookup(osl_generic_p x, char * URI) {
669
if (osl_generic_has_URI(x, URI))
680
* osl_generic_shell function:
681
* this function creates and returns a generic structure "shell" which
682
* embed the data and interface provided as parameters.
683
* \param[in] data Data to put in the generic shell.
684
* \param[in] interface Interface to put in the generic shell.
685
* \return A new generic structure containing the data and interface.
687
osl_generic_p osl_generic_shell(void * data, osl_interface_p interface) {
688
osl_generic_p generic = NULL;
690
if ((data == NULL) || (interface == NULL))
691
OSL_warning("shell created with some empty elements inside");
693
generic = osl_generic_malloc();
694
generic->data = data;
695
generic->interface = interface;