1
2    /*+-----------------------------------------------------------------**
3     **                       OpenScop Library                          **
4     **-----------------------------------------------------------------**
5     **                           strings.c                             **
6     **-----------------------------------------------------------------**
7     **                   First version: 13/07/2011                     **
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 <ctype.h>
66# include <string.h>
67
68# include <osl/macros.h>
69# include <osl/util.h>
70# include <osl/interface.h>
71# include <osl/strings.h>
72
73
74/*+***************************************************************************
75 *                          Structure display function                       *
76 *****************************************************************************/
77
78
79/**
80 * osl_strings_idump function:
81 * this function displays an array of strings into a file (file, possibly
82 * stdout) in a way that trends to be understandable. It includes an
83 * indentation level (level) in order to work with others
84 * idump functions.
85 * \param[in] file    The file where the information has to be printed.
86 * \param[in] strings The array of strings that has to be printed.
87 * \param[in] level   Number of spaces before printing, for each line.
88 */
89void osl_strings_idump(FILE * file, osl_strings_p strings, int level) {
90  int i, nb_strings;
91
92  for (i = 0; i < level; i++)
93    fprintf(file, "|\t");
94
95  if (strings != NULL) {
96    nb_strings = osl_strings_size(strings);
97    fprintf(file, "+-- osl_strings_t:");
98    for (i = 0; i < nb_strings; i++)
99      fprintf(file, " %s", strings->string[i]);
100    fprintf(file, "\n");
101  }
102  else
103    fprintf(file, "+-- NULL strings\n");
104
105  // A blank line.
106  for (i = 0; i <= level; i++)
107    fprintf(file, "|\t");
108  fprintf(file, "\n");
109}
110
111
112/**
113 * osl_strings_dump function:
114 * this function prints the content of an osl_strings_t structure
115 * (*strings) into a file (file, possibly stdout).
116 * \param[in] file    The file where the information has to be printed.
117 * \param[in] strings The strings structure which has to be printed.
118 */
119void osl_strings_dump(FILE * file, osl_strings_p strings) {
120  osl_strings_idump(file, strings, 0);
121}
122
123
124/**
125 * osl_strings_sprint function:
126 * this function prints the content of an osl_strings_t structure
127 * (*strings) into a string (returned) in the OpenScop textual format.
128 * \param[in] strings The strings structure which has to be printed.
129 * \return A string containing the OpenScop dump of the strings structure.
130 */
131char * osl_strings_sprint(osl_strings_p strings) {
132  int i;
133  int high_water_mark = OSL_MAX_STRING;
134  char * string = NULL;
135  char buffer[OSL_MAX_STRING];
136
137  OSL_malloc(string, char *, high_water_mark * sizeof(char));
138  string[0] = '\0';
139
140  if (strings != NULL) {
141    for (i = 0; i < osl_strings_size(strings); i++) {
142      sprintf(buffer, "%s", strings->string[i]);
143      osl_util_safe_strcat(&string, buffer, &high_water_mark);
144      if (i < osl_strings_size(strings) - 1)
145        osl_util_safe_strcat(&string, " ", &high_water_mark);
146    }
147    sprintf(buffer, "\n");
148    osl_util_safe_strcat(&string, buffer, &high_water_mark);
149  }
150  else {
151    sprintf(buffer, "# NULL strings\n");
152    osl_util_safe_strcat(&string, buffer, &high_water_mark);
153  }
154
155  return string;
156}
157
158
159/**
160 * osl_strings_print function:
161 * this function prints the content of an osl_strings_t structure
162 * (*body) into a file (file, possibly stdout) in the OpenScop format.
163 * \param[in] file    File where informations are printed.
164 * \param[in] strings The strings whose information has to be printed.
165 */
166void osl_strings_print(FILE * file, osl_strings_p strings) {
167  char * string;
168
169  string = osl_strings_sprint(strings);
170  if (string != NULL) {
171    fprintf(file, "%s", string);
172    free(string);
173  }
174}
175
176
177/*+***************************************************************************
178 *                          Structure display function                       *
179 *****************************************************************************/
180
181
182/**
183 * osl_strings_sread function:
184 * this function reads a strings structure from a string complying to the
185 * OpenScop textual format and returns a pointer to this strings structure.
186 * The input string should only contain the list of strings this function
187 * has to read (comments at the end of the line are accepted). The input
188 * parameter is updated to the position in the input string this function
189 * reach right after reading the strings structure.
190 * \param[in,out] input The input string where to find a strings structure.
191 *                      Updated to the position after what has been read.
192 * \return A pointer to the strings structure that has been read.
193 */
194osl_strings_p osl_strings_sread(char ** input) {
195  char tmp[OSL_MAX_STRING];
196  char * s;
197  char ** string = NULL;
198  int nb_strings;
199  int i, count;
200  osl_strings_p strings = NULL;
201
202  // Skip blank/commented lines and spaces before the strings.
203  osl_util_sskip_blank_and_comments(input);
204
205  // Count the actual number of strings.
206  nb_strings = 0;
207  s = *input;
208  while (1) {
209    for (count = 0; *s && !isspace(*s) && *s != '#'; count++)
210      s++;
211
212    if (count != 0)
213      nb_strings++;
214
215    if ((!*s) || (*s == '#') || (*s == '\n'))
216      break;
217    else
218      s++;
219  }
220
221  if (nb_strings > 0) {
222    // Allocate the array of strings. Make it NULL-terminated.
223    OSL_malloc(string, char **, sizeof(char *) * (nb_strings + 1));
224    string[nb_strings] = NULL;
225
226    // Read the desired number of strings.
227    s = *input;
228    for (i = 0; i < nb_strings; i++) {
229      for (count = 0; *s && !isspace(*s) && *s != '#'; count++)
230	tmp[count] = *(s++);
231      tmp[count] = '\0';
232      OSL_strdup(string[i], tmp);
233      if (*s != '#')
234	s++;
235    }
236
237    // Update the input pointer to the end of the strings structure.
238    *input = s;
239
240    // Build the strings structure
241    strings = osl_strings_malloc();
242    strings->string = string;
243  }
244
245  return strings;
246}
247
248
249/**
250 * osl_strings_read function.
251 * this function reads a strings structure from a file (possibly stdin)
252 * complying to the OpenScop textual format and returns a pointer to this
253 * structure.
254 * parameter nb_strings).
255 * \param[in] file The file where to read the strings structure.
256 * \return The strings structure that has been read.
257 */
258osl_strings_p osl_strings_read(FILE * file) {
259  char buffer[OSL_MAX_STRING], * start;
260  osl_strings_p strings;
261
262  start = osl_util_skip_blank_and_comments(file, buffer);
263  strings = osl_strings_sread(&start);
264
265  return strings;
266}
267
268
269/*+***************************************************************************
270 *                    Memory allocation/deallocation function                *
271 *****************************************************************************/
272
273
274/**
275 * osl_strings_malloc function:
276 * This function allocates the memory space for an osl_strings_t
277 * structure and sets its fields with default values. Then it returns a
278 * pointer to the allocated space.
279 * \return A pointer to an empty strings structure with fields set to
280 *         default values.
281 */
282osl_strings_p osl_strings_malloc() {
283  osl_strings_p strings;
284
285  OSL_malloc(strings, osl_strings_p, sizeof(osl_strings_t));
286  strings->string = NULL;
287
288  return strings;
289}
290
291
292/**
293 * osl_strings_free function:
294 * this function frees the allocated memory for a strings data structure.
295 * \param[in] strings The strings structure we want to free.
296 */
297void osl_strings_free(osl_strings_p strings) {
298  int i;
299
300  if (strings != NULL) {
301    if (strings->string != NULL) {
302      i = 0;
303      while (strings->string[i] != NULL) {
304        free(strings->string[i]);
305        i++;
306      }
307      free(strings->string);
308    }
309    free(strings);
310  }
311}
312
313
314/*+***************************************************************************
315 *                            Processing functions                           *
316 *****************************************************************************/
317
318
319/**
320 * osl_strings_clone function.
321 * this function builds and return a "hard copy" (not a pointer copy) of an
322 * strings structure provided as parameter.
323 * \param[in] strings The strings structure to clone.
324 * \return The clone of the strings structure.
325 */
326osl_strings_p osl_strings_clone(osl_strings_p strings) {
327  int i, nb_strings;
328  osl_strings_p clone = NULL;
329
330  if (strings == NULL)
331    return NULL;
332
333  clone = osl_strings_malloc();
334  if ((nb_strings = osl_strings_size(strings)) == 0)
335    return clone;
336
337  OSL_malloc(clone->string, char **, (nb_strings + 1) * sizeof(char *));
338  clone->string[nb_strings] = NULL;
339  for (i = 0; i < nb_strings; i++)
340    OSL_strdup(clone->string[i], strings->string[i]);
341
342  return clone;
343}
344
345
346/**
347 * osl_strings_equal function:
348 * this function returns true if the two strings structures are the same
349 * (content-wise), false otherwise.
350 * \param[in] s1 The first strings structure.
351 * \param[in] s2 The second strings structure.
352 * \return 1 if s1 and s2 are the same (content-wise), 0 otherwise.
353 */
354int osl_strings_equal(osl_strings_p s1, osl_strings_p s2) {
355  int i, nb_s1;
356
357  if (s1 == s2)
358    return 1;
359
360  if (((s1 == NULL) && (s2 != NULL)) ||
361      ((s1 != NULL) && (s2 == NULL)) ||
362      ((nb_s1 = osl_strings_size(s1)) != osl_strings_size(s2)))
363    return 0;
364
365  for (i = 0; i < nb_s1; i++)
366    if (strcmp(s1->string[i], s2->string[i]) != 0)
367      return 0;
368
369  return 1;
370}
371
372
373/**
374 * osl_strings_size function:
375 * this function returns the number of elements in the NULL-terminated
376 * strings array of the strings structure.
377 * \param[in] strings The strings structure we need to know the size.
378 * \return The number of strings in the strings structure.
379 */
380int osl_strings_size(osl_strings_p strings) {
381  int size = 0;
382
383  if ((strings != NULL) && (strings->string != NULL)) {
384    while (strings->string[size] != NULL) {
385      size++;
386    }
387  }
388
389  return size;
390}
391
392
393/**
394 * osl_strings_encapsulate function:
395 * this function builds a new strings structure to encapsulate the string
396 * provided as a parameter (the reference to this string is used directly).
397 * \param[in] string The string to encapsulate in a strings structure.
398 * \return A new strings structure containing only the provided string.
399 */
400osl_strings_p osl_strings_encapsulate(char * string) {
401  osl_strings_p capsule = osl_strings_malloc();
402
403  OSL_malloc(capsule->string, char **, 2 * sizeof(char *));
404  capsule->string[0] = string;
405  capsule->string[1] = NULL;
406
407  return capsule;
408}
409
410
411/**
412 * osl_strings_interface function:
413 * this function creates an interface structure corresponding to the strings
414 * structure and returns it).
415 * \return An interface structure for the strings structure.
416 */
417osl_interface_p osl_strings_interface() {
418  osl_interface_p interface = osl_interface_malloc();
419
420  interface->URI    = strdup(OSL_URI_STRINGS);
421  interface->idump  = (osl_idump_f)osl_strings_idump;
422  interface->sprint = (osl_sprint_f)osl_strings_sprint;
423  interface->sread  = (osl_sread_f)osl_strings_sread;
424  interface->malloc = (osl_malloc_f)osl_strings_malloc;
425  interface->free   = (osl_free_f)osl_strings_free;
426  interface->clone  = (osl_clone_f)osl_strings_clone;
427  interface->equal  = (osl_equal_f)osl_strings_equal;
428
429  return interface;
430}
431
432
433/**
434 * osl_strings_generate function:
435 * this function generates a new strings structure containing
436 * 'nb_strings' strings of the form "prefixXX" where XX goes from 1 to
437 * nb_strings.
438 * \param[in] prefix     The prefix of the generated strings.
439 * \param[in] nb_strings The number of strings to generate.
440 * \return A new strings structure containing generated strings.
441 */
442osl_strings_p osl_strings_generate(char * prefix, int nb_strings) {
443  char ** strings = NULL;
444  char buff[strlen(prefix) + 16]; // TODO: better (log10(INT_MAX) ?) :-D.
445  int i;
446  osl_strings_p generated;
447
448  if (nb_strings) {
449    OSL_malloc(strings, char **, sizeof(char *) * (nb_strings + 1));
450    strings[nb_strings] = NULL;
451    for (i = 0; i < nb_strings; i++) {
452      sprintf(buff, "%s%d", prefix, i + 1);
453      strings[i] = strdup(buff);
454      if (strings[i] == NULL)
455        OSL_error("memory overflow");
456    }
457  }
458
459  generated = osl_strings_malloc();
460  generated->string = strings;
461  return generated;
462}
463