Switch from matrix to relation data structure
[openscop.git] / source / util.c
blobb2ce00ec061a68ba1620c6cf3afbed741c42c79b
2 /*+-----------------------------------------------------------------**
3 ** OpenScop Library **
4 **-----------------------------------------------------------------**
5 ** util.c **
6 **-----------------------------------------------------------------**
7 ** First version: 08/10/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 <ctype.h>
66 # include <string.h>
67 # include <openscop/util.h>
70 /**
71 * openscop_util_copy_strings internal function.
72 * This function builds and return a "hard copy" (not a pointer copy) of an
73 * array of strings.
74 * \param strings The array of strings to copy.
75 * \param nb_strings The number of strings in the array to copy.
76 * \return A pointer to the copy of the array of strings.
78 char **
79 openscop_util_copy_strings(char ** strings, int nb_strings)
81 int i;
82 char ** copy;
84 if ((strings == NULL) || (nb_strings == 0))
85 return NULL;
87 copy = (char **)malloc(nb_strings * sizeof(char *));
89 for (i = 0; i < nb_strings; i++)
90 copy[i] = strdup(strings[i]);
92 return copy;
96 /**
97 * openscop_util_skip_blank_and_comments internal function.
98 * This function reads the open file 'file' line by line and skips
99 * blank/comment lines and spaces. The first line where there is some
100 * useful information is stored at the address 'str' (the memory to
101 * store the line must be allocated before the call to this function
102 * and must be at least OPENSCOP_MAX_STRING*sizeof(char)). The pointer
103 * to the first useful information in this line is returned by the
104 * function.
105 * \param file The (opened) file to read.
106 * \param str Address of an allocated space to store the first line
107 * that contains useful information.
108 * \return The address of the the first useful digit in str.
110 char * openscop_util_skip_blank_and_comments(FILE * file, char * str)
112 char * start;
116 start = fgets(str, OPENSCOP_MAX_STRING, file);
117 while ((start != NULL) && isspace(*start) && (*start != '\n'))
118 start++;
120 while (start != NULL && (*start == '#' || *start == '\n'));
122 return start;
127 * openscop_util_read_strings internal function.
128 * Read a line in the input 'file' and extract the first 'nb_strings' strings
129 * from it. nb_strings is a maximum number (the special value -1 corresponds
130 * to infinity). If *max is not NULL, it is updated with the maximum number
131 * of strings that could have been read. It returns the NULL-terminated array
132 * of strings that have been read.
133 * \param file The file where to read some strings.
134 * \param nb_strings Maximum number of strings to read (-1: infinity).
135 * \param max Address to store the maximum number of strings that could
136 * have been read (stored if the address is not NULL).
137 * \return An array of strings.
139 char **
140 openscop_util_read_strings(FILE * file, int nb_strings, int * max)
142 char str[OPENSCOP_MAX_STRING];
143 char tmp[OPENSCOP_MAX_STRING];
144 char * s, * start;
145 char ** res = NULL;
146 int i, count, actual_nb_strings = 0;
148 // Skip blank/commented lines and spaces.
149 start = openscop_util_skip_blank_and_comments(file, str);
151 // Count the actual number of strings.
152 s = start;
153 while (1)
155 for (count = 0; *s && ! isspace(*s) && *s != '#'; ++count)
156 s++;
158 if (count != 0)
159 actual_nb_strings++;
161 if ((*s == '#') || (*s == '\n'))
162 break;
163 else
164 ++s;
167 // Update the number of strings if necessary.
168 if ((nb_strings == -1) || (actual_nb_strings < nb_strings))
169 nb_strings = actual_nb_strings;
171 if (max != NULL)
172 *max = actual_nb_strings;
174 // Allocate the array of strings. Make it NULL-terminated.
175 res = (char **) malloc(sizeof(char *) * (nb_strings + 1));
176 res[nb_strings] = NULL;
178 // Read the desired number of strings.
179 s = start;
180 for (i = 0; i < nb_strings; ++i)
182 for (count = 0; *s && ! isspace(*s) && *s != '#'; ++count)
183 tmp[count] = *(s++);
184 tmp[count] = '\0';
185 res[i] = strdup(tmp);
186 if (*s != '#')
187 ++s;
190 return res;
195 * openscop_util_read_int internal function.
196 * Read an int on the input 'file' or the input string 'str' depending on
197 * which one is not NULL.
198 * \param file The file where to read an int (if not NULL).
199 * \param str The string where to read an int (if not NULL). This pointer
200 * is updated to reflect the read and points after the int.
201 * \return The int that have been read.
204 openscop_util_read_int(FILE * file, char ** str)
206 char s[OPENSCOP_MAX_STRING], * start;
207 int res;
208 int i = 0;
209 int read_int = 0;
211 if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
213 fprintf(stderr, "[OpenScop] Error: one and only one of the two parameters"
214 " of util_read_int can be non-NULL\n");
215 exit (1);
218 if (file != NULL)
220 // Parse from a file.
221 start = openscop_util_skip_blank_and_comments(file, s);
222 sscanf(start, " %d", &res);
224 if (str != NULL)
226 // Parse from a string.
227 // Skip blank/commented lines.
230 while (*str && **str && isspace(**str))
231 ++(*str);
232 if (**str == '#')
234 while (**str && **str != '\n')
235 ++(*str);
237 else
239 // Build the chain to analyze.
240 while (**str && !isspace(**str) && **str != '\n')
241 s[i++] = *((*str)++);
242 s[i] = '\0';
243 sscanf(s, "%d", &res);
244 read_int = 1;
247 while (! read_int);
250 return res;
254 void
255 openscop_util_free_name_array(char ** name_array, int nb_names)
257 int i;
259 for (i = 0; i < nb_names; i++)
260 free(name_array[i]);
261 free(name_array);
266 * openscop_util_generate_names internal function:
267 * This function generates an array of size 'nb' of chars of the form
268 * "seedXX" where XX goes from 1 to nb.
269 * \param seed The prefix for the created names.
270 * \param nb The number of names to generate.
271 * \return An array of 'nb' generated strings.
273 char **
274 openscop_util_generate_names(char * seed, int nb)
276 char ** res = NULL;
277 char buff[strlen(seed) + 16];
278 int i;
280 if (nb)
282 res = (char **)malloc(sizeof(char *) * nb);
283 if (res == NULL)
285 fprintf(stderr, "[OpenScop] Error: memory overflow.\n");
286 exit(1);
288 for (i = 0; i < nb; ++i)
290 sprintf(buff, "%s%d", seed, i + 1);
291 res[i] = strdup(buff);
295 return res;
300 * openscop_util_tag_content function:
301 * This function returns a freshly allocated string containing the
302 * content, in the given string 'str', between the tag 'tag' and
303 * the tag 'endtag'. If the tag 'tag' is not found, returns NULL.
304 * \param str The string where to find a given content.
305 * \param tag The string that marks the beginning of the content.
306 * \param endtag The string that marks the end of the content.
307 * \return The string between 'tag' and 'endtag' in 'str'.
309 char *
310 openscop_util_tag_content(char * str, char * tag, char * endtag)
312 int i;
313 char * start;
314 char * stop;
315 int size = 0;
316 int lentag;
317 char * res = NULL;
319 if (str)
321 start = str;
322 lentag = strlen(tag);
323 for (; start && *start && strncmp(start, tag, lentag); ++start)
325 // The tag 'tag' was not found.
326 if (! *start)
327 return NULL;
328 start += lentag;
329 stop = start;
330 lentag = strlen(endtag);
331 for (size = 0; *stop && strncmp(stop, endtag, lentag); ++stop, ++size)
333 // the tag 'endtag' was not found.
334 if (! *stop)
335 return NULL;
336 res = (char *)malloc((size + 1) * sizeof(char));
337 if (res == NULL)
339 fprintf(stderr, "[OpenScop] Error: memory overflow.\n");
340 exit(1);
342 // Copy the chain between the two tags.
343 for (++start, i = 0; start != stop; ++start, ++i)
344 res[i] = *start;
345 res[i] = '\0';
348 return res;
352 char **
353 openscop_util_read_tag_arrays(char * str, int * nb_arrays)
355 int i, k, nb_names, array_index, max_index = 0;
356 int high_water_mark = OPENSCOP_MAX_ARRAYS;
357 char ** arrays;
358 char ** tmpnames;
359 char * content, * content_backup;
360 char buff[OPENSCOP_MAX_STRING];
362 content = openscop_util_tag_content(str, OPENSCOP_TAG_ARRAY_START,
363 OPENSCOP_TAG_ARRAY_STOP);
365 if (content == NULL)
367 fprintf(stderr, "[OpenScop] Info: no array optional tag.\n");
368 *nb_arrays = 0;
369 return NULL;
371 content_backup = content;
373 // Allocate the array of names.
374 arrays = (char **)malloc(high_water_mark * sizeof(char *));
375 for (i = 0; i < high_water_mark; i++)
376 arrays[i] = NULL;
378 // Find the number of names provided.
379 nb_names = openscop_util_read_int(NULL, &content);
381 // Get each array name.
382 for (k = 0; k < nb_names; k++)
384 // Skip blank or commented lines.
385 while (*content == '#' || *content == '\n')
387 for (; *content != '\n'; ++content)
389 ++content;
392 // Get the array name index.
393 for (i = 0; *content && ! isspace(*content); ++i, ++content)
394 buff[i] = *content;
395 buff[i] = '\0';
396 sscanf(buff, "%d", &array_index);
397 max_index = (max_index > array_index) ? max_index : array_index;
398 if (array_index > high_water_mark)
400 fprintf(stderr, "[OpenScop] Info: array name indices sound high.\n");
401 high_water_mark += OPENSCOP_MAX_ARRAYS;
402 arrays = (char **)realloc(arrays, high_water_mark * sizeof(char *));
403 if (arrays == NULL)
405 fprintf(stderr, "[OpenScop] Error: memory overflow.\n");
406 exit(1);
408 for (i = high_water_mark - OPENSCOP_MAX_ARRAYS; i < high_water_mark; i++)
409 arrays[i] = NULL;
411 if (array_index <= 0)
413 fprintf(stderr, "[OpenScop] Error: array index must be > 0.\n");
414 exit(1);
417 // Get the array name in buff.
418 while (*content && isspace(*content))
419 ++content;
420 for (i = 0; *content && ! isspace(*content); ++i, ++content)
421 buff[i] = *content;
422 buff[i] = '\0';
424 // Array index is in 0-basis.
425 if (arrays[array_index - 1] != NULL)
427 fprintf(stderr, "[OpenScop] Warning: two array names have the "
428 "same index.\n");
429 free(arrays[array_index - 1]);
431 arrays[array_index - 1] = strdup(buff);
433 // Go to the end of line.
434 while (*content && *content != '\n')
435 ++content;
437 free(content_backup);
439 // Free unused memory.
440 arrays = (char **)realloc(arrays, max_index * sizeof(char *));
442 // Fill the missing names (and let's hope there is no need for higher index).
443 tmpnames = openscop_util_generate_names("var", max_index);
444 for (i = 0; i < max_index; i++)
446 if (arrays[i] == NULL || arrays[i][0] == '\0')
447 arrays[i] = tmpnames[i]; // Use a generated name.
448 else
449 free(tmpnames[i]); // Use a read name.
451 free(tmpnames);
453 if (OPENSCOP_DEBUG == 1)
455 printf("max_index: %d\n", max_index);
456 for (i = 0; i < max_index; i++)
457 printf("%s ", arrays[i]);
458 printf("\n");
461 *nb_arrays = max_index;
462 return arrays;