1 2 /*+-----------------------------------------------------------------** 3 ** OpenScop Library ** 4 **-----------------------------------------------------------------** 5 ** generic.c ** 6 **-----------------------------------------------------------------** 7 ** First version: 26/11/2010 ** 8 **-----------------------------------------------------------------** 9 10 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 *****************************************************************************/ 62 63#include <stdlib.h> 64#include <stdio.h> 65#include <string.h> 66 67#include <osl/macros.h> 68#include <osl/util.h> 69#include <osl/interface.h> 70#include <osl/generic.h> 71 72 73/*+*************************************************************************** 74 * Structure display function * 75 *****************************************************************************/ 76 77 78/** 79 * osl_generic_idump function: 80 * this function displays an osl_generic_t structure (*generic) into 81 * a file (file, possibly stdout) in a way that trends to be understandable. 82 * It includes an indentation level (level) in order to work with others 83 * idump functions. 84 * \param[in] file File where informations are printed. 85 * \param[in] generic The generic whose information has to be printed. 86 * \param[in] level Number of spaces before printing, for each line. 87 */ 88void osl_generic_idump(FILE * file, osl_generic_p generic, int level) { 89 int j, first = 1; 90 91 // Go to the right level. 92 for (j = 0; j < level; j++) 93 fprintf(file,"|\t"); 94 95 if (generic != NULL) 96 fprintf(file, "+-- osl_generic_t\n"); 97 else 98 fprintf(file, "+-- NULL generic\n"); 99 100 while (generic != NULL) { 101 if (!first) { 102 // Go to the right level. 103 for (j = 0; j < level; j++) 104 fprintf(file, "|\t"); 105 fprintf(file, "| osl_generic_t\n"); 106 } 107 else { 108 first = 0; 109 } 110 111 // A blank line 112 for(j = 0; j <= level + 1; j++) 113 fprintf(file, "|\t"); 114 fprintf(file, "\n"); 115 116 osl_interface_idump(file, generic->interface, level + 1); 117 118 if (generic->interface != NULL) 119 generic->interface->idump(file, generic->data, level + 1); 120 121 generic = generic->next; 122 123 // Next line. 124 if (generic != NULL) { 125 for (j = 0; j <= level; j++) 126 fprintf(file, "|\t"); 127 fprintf(file, "V\n"); 128 } 129 } 130 131 // The last line. 132 for (j = 0; j <= level; j++) 133 fprintf(file, "|\t"); 134 fprintf(file, "\n"); 135} 136 137 138/** 139 * osl_generic_dump function: 140 * this function prints the content of an osl_generic_t structure 141 * (*generic) into a file (file, possibly stdout). 142 * \param[in] file File where the information has to be printed. 143 * \param[in] generic The generic structure to print. 144 */ 145void osl_generic_dump(FILE * file, osl_generic_p generic) { 146 osl_generic_idump(file, generic, 0); 147} 148 149 150/** 151 * osl_generic_print function: 152 * this function prints the content of an osl_generic_t structure 153 * (*generic) into a string (returned) in the OpenScop format. 154 * \param[in] file File where the information has to be printed. 155 * \param[in] generic The generic structure to print. 156 */ 157void osl_generic_print(FILE * file, osl_generic_p generic) { 158 char * string; 159 160 if (generic == NULL) 161 return; 162 163 while (generic != NULL) { 164 if (generic->interface != NULL) { 165 string = generic->interface->sprint(generic->data); 166 if (string != NULL) { 167 fprintf(file, "<%s>\n", generic->interface->URI); 168 fprintf(file, "%s", string); 169 fprintf(file, "</%s>\n", generic->interface->URI); 170 free(string); 171 } 172 } 173 generic = generic->next; 174 if (generic != NULL) 175 fprintf(file, "\n"); 176 } 177} 178 179 180/***************************************************************************** 181 * Reading function * 182 *****************************************************************************/ 183 184 185/** 186 * osl_generic_sread function: 187 * this function reads a list of generics from a string complying to the 188 * OpenScop textual format and a list of known interfaces. It returns a 189 * pointer to the corresponding list of generic structures. 190 * \param[in] string The string where to read a list of data. 191 * \param[in] registry The list of known interfaces (others are ignored). 192 * \return A pointer to the generic information list that has been read. 193 */ 194osl_generic_p osl_generic_sread(char * string, osl_interface_p registry) { 195 osl_generic_p generic = NULL, new; 196 char * content, * start; 197 void * data; 198 199 while (registry != NULL) { 200 content = osl_util_tag_content(string, registry->URI); 201 if (content != NULL) { 202 start = content; 203 data = registry->sread(&content); 204 if (data != NULL) { 205 new = osl_generic_malloc(); 206 new->interface = osl_interface_nclone(registry, 1); 207 new->data = data; 208 osl_generic_add(&generic, new); 209 } 210 free(start); 211 } 212 registry = registry->next; 213 } 214 215 return generic; 216} 217 218 219/** 220 * osl_generic_read_one function: 221 * this function reads one generic from a file (possibly stdin) 222 * complying to the OpenScop textual format and a list of known interfaces. 223 * It returns a pointer to the corresponding generic structure. If no 224 * tag is found, an error is reported, in the case of an empty or closing tag 225 * name the function returns the NULL pointer. 226 * \param[in] file The input file where to read a list of data. 227 * \param[in] registry The list of known interfaces (others are ignored). 228 * \return A pointer to the generic that has been read. 229 */ 230osl_generic_p osl_generic_read_one(FILE * file, osl_interface_p registry) { 231 char * tag; 232 char * content, * temp; 233 osl_generic_p generic = NULL; 234 osl_interface_p interface; 235 236 tag = osl_util_read_tag(file, NULL); 237 if ((tag == NULL) || (strlen(tag) < 1) || (tag[0] == '/')) { 238 OSL_debug("empty tag name or closing tag instead of an opening one"); 239 return NULL; 240 } 241 242 content = osl_util_read_uptoendtag(file, tag); 243 interface = osl_interface_lookup(registry, tag); 244 245 temp = content; 246 if (interface == NULL) { 247 OSL_warning("unsupported generic"); 248 fprintf(stderr, "[osl] Warning: unknown URI \"%s\".\n", tag); 249 } 250 else { 251 generic = osl_generic_malloc(); 252 generic->interface = osl_interface_nclone(interface, 1); 253 generic->data = interface->sread(&temp); 254 } 255 256 free(content); 257 free(tag); 258 return generic; 259} 260 261 262/** 263 * osl_generic_read function: 264 * this function reads a list of generics from a file (possibly stdin) 265 * complying to the OpenScop textual format and a list of known interfaces. 266 * It returns a pointer to the list of corresponding generic structures. 267 * \param[in] file The input file where to read a list of data. 268 * \param[in] registry The list of known interfaces (others are ignored). 269 * \return A pointer to the generic information list that has been read. 270 */ 271osl_generic_p osl_generic_read(FILE * file, osl_interface_p registry) { 272 char * generic_string; 273 osl_generic_p generic_list; 274 275 generic_string = osl_util_read_uptotag(file, OSL_TAG_END_SCOP); 276 generic_list = osl_generic_sread(generic_string, registry); 277 free(generic_string); 278 return generic_list; 279} 280 281 282/*+*************************************************************************** 283 * Memory allocation/deallocation function * 284 *****************************************************************************/ 285 286 287/** 288 * osl_generic_add function: 289 * this function adds a generic node (it may be a list as well) to a list 290 * of generics provided as parameter (list). The new node is inserted at 291 * the end of the list. 292 * \param[in] list The list of generics to add a node (NULL if empty). 293 * \param[in] generic The generic list to add to the initial list. 294 */ 295void osl_generic_add(osl_generic_p * list, osl_generic_p generic) { 296 osl_generic_p tmp = *list, check; 297 298 if (generic != NULL) { 299 // First, check that the generic list is OK. 300 check = generic; 301 while (check != NULL) { 302 if ((check->interface == NULL) || (check->interface->URI == NULL)) 303 OSL_error("no interface or URI in a generic to add to a list"); 304 305 // TODO: move this to the integrity check. 306 if (osl_generic_lookup(*list, check->interface->URI) != NULL) 307 OSL_error("only one generic with a given URI is allowed"); 308 check = check->next; 309 } 310 311 if (*list != NULL) { 312 while (tmp->next != NULL) 313 tmp = tmp->next; 314 tmp->next = generic; 315 } 316 else { 317 *list = generic; 318 } 319 } 320} 321 322 323/** 324 * osl_generic_malloc function: 325 * This function allocates the memory space for an osl_generic_t 326 * structure and sets its fields with default values. Then it returns a 327 * pointer to the allocated space. 328 * \return A pointer to an empty generic structure with fields set to 329 * default values. 330 */ 331osl_generic_p osl_generic_malloc() { 332 osl_generic_p generic; 333 334 OSL_malloc(generic, osl_generic_p, sizeof(osl_generic_t)); 335 generic->interface = NULL; 336 generic->data = NULL; 337 generic->next = NULL; 338 339 return generic; 340} 341 342 343/** 344 * osl_generic_free function: 345 * This function frees the allocated memory for a generic structure. 346 * \param[in] generic The pointer to the generic structure we want to free. 347 */ 348void osl_generic_free(osl_generic_p generic) { 349 osl_generic_p next; 350 351 while (generic != NULL) { 352 next = generic->next; 353 if (generic->interface != NULL) { 354 generic->interface->free(generic->data); 355 osl_interface_free(generic->interface); 356 } 357 else { 358 if (generic->data != NULL) { 359 OSL_warning("unregistered interface, memory leaks are possible"); 360 free(generic->data); 361 } 362 } 363 free(generic); 364 generic = next; 365 } 366} 367 368 369/*+*************************************************************************** 370 * Processing functions * 371 *****************************************************************************/ 372 373 374/** 375 * osl_generic_clone function: 376 * This function builds and returns a "hard copy" (not a pointer copy) of an 377 * osl_generic_t data structure. 378 * \param[in] generic The pointer to the generic structure we want to clone. 379 * \return A pointer to the clone of the input generic structure. 380 */ 381osl_generic_p osl_generic_clone(osl_generic_p generic) { 382 osl_generic_p clone = NULL, new; 383 osl_interface_p interface; 384 void * x; 385 386 while (generic != NULL) { 387 if (generic->interface != NULL) { 388 x = generic->interface->clone(generic->data); 389 interface = osl_interface_clone(generic->interface); 390 new = osl_generic_malloc(); 391 new->interface = interface; 392 new->data = x; 393 osl_generic_add(&clone, new); 394 } 395 else { 396 OSL_warning("unregistered interface, cloning ignored"); 397 } 398 generic = generic->next; 399 } 400 401 return clone; 402} 403 404 405/** 406 * osl_generic_count function: 407 * this function counts the number of elements in the generic list provided 408 * as parameter (x) and returns this number. 409 * \param[in] x The list of generics. 410 * \return The number of elements in the list. 411 */ 412int osl_generic_count(osl_generic_p x) { 413 int generic_number = 0; 414 415 while (x != NULL) { 416 generic_number++; 417 x = x->next; 418 } 419 420 return generic_number; 421} 422 423 424/** 425 * osl_generic_equal function: 426 * this function returns true if the two generic structures are the same, 427 * false otherwise. This functions considers two generic structures as equal 428 * independently of the order of the nodes. 429 * \param[in] x1 The first generic structure. 430 * \param[in] x2 The second generic structure. 431 * \return 1 if x1 and x2 are the same (content-wise), 0 otherwise. 432 */ 433int osl_generic_equal(osl_generic_p x1, osl_generic_p x2) { 434 int x1_generic_number, x2_generic_number; 435 int found, equal; 436 osl_generic_p backup_x2 = x2; 437 438 if (x1 == x2) 439 return 1; 440 441 // Check whether the number of generics is the same or not. 442 x1_generic_number = osl_generic_count(x1); 443 x2_generic_number = osl_generic_count(x2); 444 if (x1_generic_number != x2_generic_number) 445 return 0; 446 447 // Check that for each generic in x1 a similar generic is in x2. 448 while (x1 != NULL) { 449 x2 = backup_x2; 450 found = 0; 451 while ((x2 != NULL) && (found != 1)) { 452 if (osl_interface_equal(x1->interface, x2->interface)) { 453 if (x1->interface != NULL) { 454 equal = x1->interface->equal(x1->data, x2->data); 455 } 456 else { 457 OSL_warning("unregistered generic, " 458 "cannot state generic equality"); 459 equal = 0; 460 } 461 462 if (equal == 0) 463 return 0; 464 else 465 found = 1; 466 } 467 468 x2 = x2->next; 469 } 470 471 if (found != 1) 472 return 0; 473 474 x1 = x1->next; 475 } 476 477 return 1; 478} 479 480 481/** 482 * osl_generic_has_URI function: 483 * this function returns 1 if the generic provided as parameter has 484 * a given URI, 0 other wise. 485 * \param[in] x The generic structure to test. 486 * \param[in] URI The URI value to test. 487 * \return 1 if x has the provided URI, 0 otherwise. 488 */ 489int osl_generic_has_URI(osl_generic_p x, char * URI) { 490 491 if ((x == NULL) || 492 (x->interface == NULL) || 493 (x->interface->URI == NULL) || 494 (strcmp(x->interface->URI, URI))) 495 return 0; 496 497 return 1; 498} 499 500 501/** 502 * osl_generic_lookup function: 503 * this function returns the first generic with a given URI in the 504 * generic list provided as parameter and NULL if it doesn't find such 505 * a generic. 506 * \param[in] x The generic list where to search a given generic URI. 507 * \param[in] URI The URI of the generic we are looking for. 508 * \return The first generic of the requested URI in the list. 509 */ 510void * osl_generic_lookup(osl_generic_p x, char * URI) { 511 while (x != NULL) { 512 if (osl_generic_has_URI(x, URI)) 513 return x->data; 514 515 x = x->next; 516 } 517 518 return NULL; 519} 520 521 522/** 523 * osl_generic_shell function: 524 * this function creates and returns a generic structure "shell" which 525 * embed the data and interface provided as parameters. 526 * \param[in] data Data to put in the generic shell. 527 * \param[in] interface Interface to put in the generic shell. 528 * \return A new generic structure containing the data and interface. 529 */ 530osl_generic_p osl_generic_shell(void * data, osl_interface_p interface) { 531 osl_generic_p generic = NULL; 532 533 if ((data == NULL) || (interface == NULL)) 534 OSL_warning("shell created with some empty elements inside"); 535 536 generic = osl_generic_malloc(); 537 generic->data = data; 538 generic->interface = interface; 539 return generic; 540} 541