~ubuntu-branches/ubuntu/trusty/cloog/trusty

« back to all changes in this revision

Viewing changes to osl/source/util.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2011-12-15 18:39:17 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20111215183917-uqggmujou8wna9js
Tags: 0.17.0-1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
    /*+-----------------------------------------------------------------**
 
3
     **                       OpenScop Library                          **
 
4
     **-----------------------------------------------------------------**
 
5
     **                            util.c                               **
 
6
     **-----------------------------------------------------------------**
 
7
     **                   First version: 08/10/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 <ctype.h>
 
66
#include <string.h>
 
67
 
 
68
#include <osl/macros.h>
 
69
#include <osl/util.h>
 
70
 
 
71
 
 
72
/*+***************************************************************************
 
73
 *                             Utility functions                             *
 
74
 *****************************************************************************/
 
75
 
 
76
 
 
77
/**
 
78
 * osl_util_skip_blank_and_comments "file skip" function:
 
79
 * this function reads the open file 'file' line by line and skips
 
80
 * blank/comment lines and spaces. The first line where there is some
 
81
 * useful information is stored at the address 'str' (the memory to
 
82
 * store the line must be allocated before the call to this function
 
83
 * and must be at least OSL_MAX_STRING * sizeof(char)). The pointer
 
84
 * to the first useful information in this line is returned by the
 
85
 * function.
 
86
 * \param[in] file The (opened) file to read.
 
87
 * \param[in] str  Address of an allocated space to store the first line
 
88
 *                 that contains useful information.
 
89
 * \return The address of the the first useful digit in str.
 
90
 */
 
91
char * osl_util_skip_blank_and_comments(FILE * file, char * str) {
 
92
  char * start;
 
93
 
 
94
  do {
 
95
    start = fgets(str, OSL_MAX_STRING, file);
 
96
    while ((start != NULL) && isspace(*start) && (*start != '\n'))
 
97
      start++;
 
98
  }
 
99
  while (start != NULL && (*start == '#' || *start == '\n'));
 
100
 
 
101
  return start;
 
102
}
 
103
 
 
104
 
 
105
/**
 
106
 * osl_util_sskip_blank_and_comments "string skip" function:
 
107
 * this function updates the str pointer, which initialy points to a string,
 
108
 * to the first character in this string which is not a space or a comment
 
109
 * (comments start at '#' and end at '\n'), or to the end of string.
 
110
 * \param[in,out] str Address of a string, updated to the address of
 
111
 *                    the first non-space or comment character.
 
112
 */
 
113
void osl_util_sskip_blank_and_comments(char ** str) {
 
114
  do {
 
115
    // Skip spaces/blanc lines.
 
116
    while (*str && **str && isspace(**str))
 
117
      (*str)++;
 
118
 
 
119
    // Skip the comment if any.
 
120
    if (*str && **str && **str == '#') {
 
121
      while (**str && **str != '\n') {
 
122
        (*str)++;
 
123
      }
 
124
    }
 
125
  }
 
126
  while (*str && **str && **str == '\n');
 
127
}
 
128
 
 
129
 
 
130
/**
 
131
 * osl_util_read_int function:
 
132
 * reads an int on the input 'file' or the input string 'str' depending on
 
133
 * which one is not NULL (exactly one of them must not be NULL).
 
134
 * \param[in]     file The file where to read an int (if not NULL).
 
135
 * \param[in,out] str  The string where to read an int (if not NULL). This
 
136
 *                     pointer is updated to reflect the read and points
 
137
 *                     after the int in the input string.
 
138
 * \return The int that has been read.
 
139
 */
 
140
int osl_util_read_int(FILE * file, char ** str) {
 
141
  char s[OSL_MAX_STRING], * start;
 
142
  int res;
 
143
  int i = 0;
 
144
 
 
145
  if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
 
146
    OSL_error("one and only one of the two parameters can be non-NULL");
 
147
 
 
148
  if (file != NULL) {
 
149
    // Parse from a file.
 
150
    start = osl_util_skip_blank_and_comments(file, s);
 
151
    if (sscanf(start, " %d", &res) != 1)
 
152
      OSL_error("an int was expected");
 
153
  }
 
154
  else {
 
155
    // Parse from a string.
 
156
    // Skip blank/commented lines.
 
157
    osl_util_sskip_blank_and_comments(str);
 
158
    
 
159
    // Build the chain to analyze.
 
160
    while (**str && !isspace(**str) && **str != '\n')
 
161
      s[i++] = *((*str)++);
 
162
    s[i] = '\0';
 
163
    if (sscanf(s, "%d", &res) != 1)
 
164
      OSL_error("an int was expected");
 
165
  }
 
166
 
 
167
  return res;
 
168
}
 
169
 
 
170
 
 
171
/**
 
172
 * osl_util_read_int internal function:
 
173
 * reads a tag (the form of a tag with name "name" is \<name\>) on the input
 
174
 * 'file' or the input string 'str' depending on which one is not NULL (exactly
 
175
 * one of them must not be NULL). It returns the name of the tag (thus without
 
176
 * the < and > as a string. Note that in the case of an ending tag, e.g.,
 
177
 * \</foo\>, the slash is returned as a part of the name, e.g., /foo.
 
178
 * \param[in]     file The file where to read a tag (if not NULL).
 
179
 * \param[in,out] str  The string where to read a tag (if not NULL). This
 
180
 *                     pointer is updated to reflect the read and points
 
181
 *                     after the tag in the input string.
 
182
 * \return The tag name that has been read.
 
183
 */
 
184
char * osl_util_read_tag(FILE * file, char ** str) {
 
185
  char s[OSL_MAX_STRING], * start;
 
186
  char * res;
 
187
  int i = 0;
 
188
 
 
189
  if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
 
190
    OSL_error("one and only one of the two parameters can be non-NULL");
 
191
 
 
192
  // Skip blank/commented lines.
 
193
  if (file != NULL) {
 
194
    start = osl_util_skip_blank_and_comments(file, s);
 
195
    str = &start;
 
196
  }
 
197
  else {
 
198
    osl_util_sskip_blank_and_comments(str);
 
199
  }
 
200
 
 
201
  // Pass the starting '<'.
 
202
  if (**str != '<')
 
203
    OSL_error("a \"<\" to start a tag was expected");
 
204
  (*str)++;
 
205
 
 
206
  // Read the tag.
 
207
  OSL_malloc(res, char *, (OSL_MAX_STRING + 1) * sizeof(char));
 
208
  res[OSL_MAX_STRING] = '\0';
 
209
  
 
210
  while (**str && **str != '>') {
 
211
    if (((**str >= 'A') && (**str <= 'Z')) ||
 
212
        ((**str >= 'a') && (**str <= 'z')) ||
 
213
        ((**str == '/') && (i == 0))       ||
 
214
        (**str == '_')) {
 
215
      res[i++] = *((*str)++);
 
216
      res[i] = '\0';
 
217
    }
 
218
    else {
 
219
      OSL_error("illegal character in the tag name");
 
220
    }
 
221
  }
 
222
 
 
223
  // Check we actually end up with a '>' and pass it.
 
224
  if (**str != '>')
 
225
    OSL_error("a \">\" to end a tag was expected");
 
226
  (*str)++;
 
227
 
 
228
  return res;
 
229
}
 
230
 
 
231
 
 
232
/**
 
233
 * osl_util_read_uptotag function:
 
234
 * this function reads a file up to a given tag (the tag is read) or the
 
235
 * end of file. It puts everything it reads, except the tag, in a string 
 
236
 * which is returned. However ot returns NULL is the tag is not found.
 
237
 * \param[in] file The file where to read the tail.
 
238
 * \param[in] tag  The tag which, when reached, stops the file reading.
 
239
 * \return The string that has been read from the file.
 
240
 */
 
241
char * osl_util_read_uptotag(FILE * file, char * tag) {
 
242
  int high_water_mark = OSL_MAX_STRING;
 
243
  int nb_chars = 0;
 
244
  int lentag = strlen(tag);
 
245
  int tag_found = 0;
 
246
  char * res;
 
247
 
 
248
  OSL_malloc(res, char *, high_water_mark * sizeof(char));
 
249
 
 
250
  // - Copy everything to the res string.
 
251
  while (!feof(file)) {
 
252
    res[nb_chars] = fgetc(file); 
 
253
    nb_chars++;
 
254
 
 
255
    if ((nb_chars >= lentag) &&
 
256
        (!strncmp(&res[nb_chars - lentag], tag, lentag))) {
 
257
      tag_found = 1;
 
258
      break;
 
259
    }
 
260
 
 
261
    if (nb_chars >= high_water_mark) {
 
262
      high_water_mark += high_water_mark;
 
263
      OSL_realloc(res, char *, high_water_mark * sizeof(char));
 
264
    }
 
265
  }
 
266
 
 
267
  if (!tag_found) {
 
268
    OSL_debug("tag was not found, end of file reached");
 
269
    free(res);
 
270
    return NULL;
 
271
  }
 
272
 
 
273
  // - 0-terminate the string.
 
274
  OSL_realloc(res, char *, (nb_chars - strlen(tag) + 1) * sizeof(char));
 
275
  res[nb_chars - strlen(tag)] = '\0';
 
276
 
 
277
  return res;
 
278
}
 
279
 
 
280
 
 
281
/**
 
282
 * osl_util_read_uptoendtag function:
 
283
 * this function reads a file up to a given end tag (this end tag is read)
 
284
 * or the end of file. The name of the tag is provided as parameter (hence
 
285
 * without the starting "</" end the closing ">"). It puts everything it reads
 
286
 * in a string which is returned.
 
287
 * \param[in] file The file where to read the tail.
 
288
 * \param[in] name The name of the end tag to the file reading.
 
289
 * \return The string that has been read from the file.
 
290
 */
 
291
char * osl_util_read_uptoendtag(FILE * file, char * name) {
 
292
  char tag[strlen(name) + 4];
 
293
  
 
294
  sprintf(tag, "</%s>", name);
 
295
  return osl_util_read_uptotag(file, tag);
 
296
}
 
297
 
 
298
 
 
299
/**
 
300
 * osl_util_tag_content function:
 
301
 * this function returns a freshly allocated string containing the
 
302
 * content, in the given string 'str', between the tag '\<name\>' and
 
303
 * the tag '\</name\>'. If the tag '\<name\>' is not found, it returns NULL.
 
304
 * \param[in] str    The string where to find a given content.
 
305
 * \param[in] name   The name of the tag we are looking for.
 
306
 * \return The string between '\<name\>' and '\</name\>' in 'str'.
 
307
 */
 
308
char * osl_util_tag_content(char * str, char * name) {
 
309
  int i;
 
310
  char * start;
 
311
  char * stop;
 
312
  char tag[strlen(name) + 3];
 
313
  char endtag[strlen(name) + 4];
 
314
  int size = 0;
 
315
  int lentag;
 
316
  char * res = NULL;
 
317
 
 
318
  sprintf(tag, "<%s>", name);
 
319
  sprintf(endtag, "</%s>", name);
 
320
  
 
321
  if (str) {
 
322
    start = str;
 
323
    lentag = strlen(tag);
 
324
    for (; start && *start && strncmp(start, tag, lentag); ++start)
 
325
      continue;
 
326
    
 
327
    // The tag 'tag' was not found.
 
328
    if (! *start)
 
329
      return NULL;
 
330
    start += lentag;
 
331
    stop = start;
 
332
    lentag = strlen(endtag);
 
333
    for (size = 0; *stop && strncmp(stop, endtag, lentag); ++stop, ++size)
 
334
      continue;
 
335
    
 
336
    // the tag 'endtag' was not found.
 
337
    if (! *stop)
 
338
      return NULL;
 
339
    OSL_malloc(res, char *, (size + 1) * sizeof(char));
 
340
    
 
341
    // Copy the chain between the two tags.
 
342
    for (++start, i = 0; start != stop; ++start, ++i)
 
343
      res[i] = *start;
 
344
    res[i] = '\0';
 
345
  }
 
346
 
 
347
  return res;
 
348
}
 
349
 
 
350
 
 
351
/**
 
352
 * osl_util_safe_strcat function:
 
353
 * this function concatenates the string src to the string *dst
 
354
 * and reallocates *dst if necessary. The current size of the
 
355
 * *dst buffer must be *hwm (high water mark), if there is some
 
356
 * reallocation, this value is updated.
 
357
 * \param[in,out] dst pointer to the destination string (may be reallocated).
 
358
 * \param[in]     src string to concatenate to dst.
 
359
 * \param[in,out] hwm pointer to the size of the *dst buffer (may be updated).
 
360
 */
 
361
void osl_util_safe_strcat(char ** dst, char * src, int * hwm) {
 
362
 
 
363
  while (strlen(*dst) + strlen(src) >= *hwm) {
 
364
    *hwm += OSL_MAX_STRING;
 
365
    OSL_realloc(*dst, char *, *hwm * sizeof(char));
 
366
  }
 
367
 
 
368
  strcat(*dst, src);
 
369
}
 
370
 
 
371
 
 
372
/**
 
373
 * osl_util_get_precision function:
 
374
 * this function returns the precision defined by the precision environment
 
375
 * variable or the highest available precision if it is not defined.
 
376
 * \return environment precision if defined or highest available precision.
 
377
 */
 
378
int osl_util_get_precision() {
 
379
  int precision = OSL_PRECISION_DP;
 
380
  char * precision_env;
 
381
 
 
382
#ifdef OSL_GMP_IS_HERE
 
383
  precision = OSL_PRECISION_MP;
 
384
#endif
 
385
 
 
386
  precision_env = getenv(OSL_PRECISION_ENV);
 
387
  if (precision_env != NULL) {
 
388
    if (!strcmp(precision_env, OSL_PRECISION_ENV_SP))
 
389
      precision = OSL_PRECISION_SP;
 
390
    else if (!strcmp(precision_env, OSL_PRECISION_ENV_DP))
 
391
      precision = OSL_PRECISION_DP;
 
392
    else if (!strcmp(precision_env, OSL_PRECISION_ENV_MP))
 
393
      precision = OSL_PRECISION_MP;
 
394
    else
 
395
      OSL_warning("bad precision environment value");
 
396
  }
 
397
 
 
398
  return precision;
 
399
}
 
400
 
 
401
 
 
402
/**
 
403
 * osl_util_print_provided function:
 
404
 * this function prints a "provided" boolean in a file (file, possibly stdout),
 
405
 * with a comment title according to the OpenScop specification.
 
406
 * \param[in] file     File where the information has to be printed.
 
407
 * \param[in] provided The provided boolean to print.
 
408
 * \param[in] title    A string to use as a title for the provided booblean.
 
409
 */
 
410
void osl_util_print_provided(FILE * file, int provided, char * title) {
 
411
  if (provided) {
 
412
    fprintf(file, "# %s provided\n", title);
 
413
    fprintf(file, "1\n");
 
414
  }
 
415
  else {
 
416
    fprintf(file, "# %s not provided\n", title);
 
417
    fprintf(file, "0\n\n");
 
418
  }
 
419
}
 
420
 
 
421
 
 
422
/**
 
423
 * osl_util_identifier_is_here function:
 
424
 * this function returns 1 if the input "identifier" is found at the
 
425
 * "index" position in the "expression" input string, 0 otherwise.
 
426
 * \param[in] expression The input expression.
 
427
 * \param[in] identifier The identifier to look for.
 
428
 * \param[in] index      The position in the expression where to look.
 
429
 * \return 1 if the identifier is found at the position in the expression.
 
430
 */
 
431
static
 
432
int osl_util_identifier_is_here(char * expression, char * identifier,
 
433
                                int index) {
 
434
  // If there is no space enough to find the identifier: no.
 
435
  if (strlen(identifier) + index > strlen(expression))
 
436
    return 0;
 
437
  
 
438
  // If there is a character before and it is in [A-Za-z0-9]: no.
 
439
  if ((index > 0) &&
 
440
      (((expression[index - 1] >= 'A') && (expression[index - 1] <= 'Z')) || 
 
441
       ((expression[index - 1] >= 'a') && (expression[index - 1] <= 'z')) || 
 
442
       ((expression[index - 1] >= '0') && (expression[index - 1] <= '9'))))
 
443
    return 0;
 
444
 
 
445
  // If there is a character after and it is in [A-Za-z0-9]: no.
 
446
  if ((strlen(identifier) + index < strlen(expression)) &&
 
447
      (((expression[strlen(identifier) + index] >= 'A') &&
 
448
        (expression[strlen(identifier) + index] <= 'Z'))   || 
 
449
       ((expression[strlen(identifier) + index] >= 'a') &&
 
450
        (expression[strlen(identifier) + index] <= 'z'))   || 
 
451
       ((expression[strlen(identifier) + index] >= '0') &&
 
452
        (expression[strlen(identifier) + index] <= '9'))))
 
453
    return 0;
 
454
 
 
455
  // If the identifier string is not here: no.
 
456
  if (strncmp(expression + index, identifier, strlen(identifier)))
 
457
    return 0;
 
458
 
 
459
  return 1;
 
460
}
 
461
 
 
462
 
 
463
/**
 
464
 * osl_util_lazy_isolated_identifier function:
 
465
 * this function returns 1 if the identifier at the "index" position in the
 
466
 * "expression" is guaranteed not to need parenthesis around is we
 
467
 * substitute it with anything. For instance the identifier "i" can be
 
468
 * always substituted in "A[i]" with no need of parenthesis but not in
 
469
 * "A[2*i]". This function is lazy in the sense that it just check obvious
 
470
 * cases, not all of them. The identifier must already be at the indicated
 
471
 * position, this function does not check that.
 
472
 * \param[in] expression The input expression.
 
473
 * \param[in] identifier The identifier to check.
 
474
 * \param[in] index      The position of the identifier in the expression.
 
475
 * \return 1 if the identifier is isolated, 0 if unsure.
 
476
 */
 
477
static
 
478
int osl_util_lazy_isolated_identifier(char * expression, char * identifier,
 
479
                                      int index) {
 
480
  int look;
 
481
 
 
482
  // If the first non-space character before is not in [\[(,\+=]: no. 
 
483
  look = index - 1;
 
484
  while (look >= 0) {
 
485
    if (isspace(expression[look]))
 
486
      look--;
 
487
    else
 
488
      break;
 
489
  }
 
490
 
 
491
  if ((look >= 0) &&
 
492
      (expression[look] != '[') &&
 
493
      (expression[look] != '(') &&
 
494
      (expression[look] != '+') &&
 
495
      (expression[look] != '=') &&
 
496
      (expression[look] != ','))
 
497
    return 0;
 
498
        
 
499
  // If the first non-space character after is not in [\]),;\+]: no. 
 
500
  look = index + strlen(identifier);
 
501
  while (look < strlen(expression)) {
 
502
    if (isspace(expression[look]))
 
503
      look++;
 
504
    else
 
505
      break;
 
506
  }
 
507
 
 
508
  if ((look < strlen(expression)) &&
 
509
      (expression[look] != ']')   &&
 
510
      (expression[look] != ')')   &&
 
511
      (expression[look] != '+')   &&
 
512
      (expression[look] != ',')   &&
 
513
      (expression[look] != ';'))
 
514
    return 0;
 
515
 
 
516
  return 1;
 
517
}
 
518
 
 
519
 
 
520
/**
 
521
 * osl_util_identifier_substitution function:
 
522
 * this function replaces some identifiers in an input expression string and
 
523
 * returns the final string. The list of identifiers to replace are provided
 
524
 * as an array of strings. They are replaced from the input string with the
 
525
 * new substring "@i@" or "(@i@)" where i is the rank of the identifier in the
 
526
 * array of identifiers. The parentheses are added when it is not obvious that
 
527
 * the identifier can be replaced with an arbitrary expression without the
 
528
 * need of parentheses. For instance, let us consider the input expression
 
529
 * "C[i+j]+=A[2*i]*B[j];" and the array of strings {"i", "j"}: the resulting
 
530
 * string would be "C[@0@+@1@]+=A[2*(@0@)]*B[@1@];".
 
531
 * \param[in] expression The original expression.
 
532
 * \param[in] identifiers NULL-terminated array of identifiers.
 
533
 * \return A new string where the ith identifier is replaced by \@i\@.
 
534
 */
 
535
char * osl_util_identifier_substitution(char * expression,
 
536
                                        char ** identifiers) {
 
537
  int index, j, found;
 
538
  int high_water_mark = OSL_MAX_STRING;
 
539
  char buffer[OSL_MAX_STRING];
 
540
  char * string;
 
541
 
 
542
  OSL_malloc(string, char *, high_water_mark * sizeof(char));
 
543
  string[0] = '\0';
 
544
 
 
545
  index = 0;
 
546
  while (index < strlen(expression)) {
 
547
    j = 0;
 
548
    found = 0;
 
549
    while (identifiers[j] != NULL) {
 
550
      if (osl_util_identifier_is_here(expression, identifiers[j], index)) {
 
551
        if (osl_util_lazy_isolated_identifier(expression,identifiers[j],index))
 
552
          sprintf(buffer, "@%d@", j);
 
553
        else
 
554
          sprintf(buffer, "(@%d@)", j);
 
555
        osl_util_safe_strcat(&string, buffer, &high_water_mark);
 
556
        index += strlen(identifiers[j]);
 
557
        found = 1;
 
558
        break;
 
559
      }
 
560
      j++;
 
561
    }
 
562
    if (!found) {
 
563
      sprintf(buffer, "%c", expression[index]);
 
564
      osl_util_safe_strcat(&string, buffer, &high_water_mark);
 
565
      index++;
 
566
    }
 
567
  }
 
568
 
 
569
  return string;
 
570
}
 
571
 
 
572
 
 
573