mirror of
https://review.haiku-os.org/buildtools
synced 2025-02-12 08:47:41 +01:00
* these are dependencies for gcc 4 Graphite engine build. * CLooG 0.18.0 includes ISL 0.11.1 which is the backend that the build script enables. * PPL is needed by GCC build even if it isn't the chosen backend.
664 lines
24 KiB
C
664 lines
24 KiB
C
|
|
/*+-----------------------------------------------------------------**
|
|
** OpenScop Library **
|
|
**-----------------------------------------------------------------**
|
|
** util.c **
|
|
**-----------------------------------------------------------------**
|
|
** First version: 08/10/2010 **
|
|
**-----------------------------------------------------------------**
|
|
|
|
|
|
*****************************************************************************
|
|
* OpenScop: Structures and formats for polyhedral tools to talk together *
|
|
*****************************************************************************
|
|
* ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, *
|
|
* / / / // // // // / / / // // / / // / /|,_, *
|
|
* / / / // // // // / / / // // / / // / / / /\ *
|
|
* |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ *
|
|
* | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ *
|
|
* | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ *
|
|
* | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ *
|
|
* | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ *
|
|
* | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ *
|
|
* | I | | | | e | | | | | | | | | | | | | \ \ \ *
|
|
* | T | | | | | | | | | | | | | | | | | \ \ \ *
|
|
* | E | | | | | | | | | | | | | | | | | \ \ \ *
|
|
* | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ *
|
|
* | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / *
|
|
* '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
|
|
* *
|
|
* Copyright (C) 2008 University Paris-Sud 11 and INRIA *
|
|
* *
|
|
* (3-clause BSD license) *
|
|
* Redistribution and use in source and binary forms, with or without *
|
|
* modification, are permitted provided that the following conditions *
|
|
* are met: *
|
|
* *
|
|
* 1. Redistributions of source code must retain the above copyright notice, *
|
|
* this list of conditions and the following disclaimer. *
|
|
* 2. Redistributions in binary form must reproduce the above copyright *
|
|
* notice, this list of conditions and the following disclaimer in the *
|
|
* documentation and/or other materials provided with the distribution. *
|
|
* 3. The name of the author may not be used to endorse or promote products *
|
|
* derived from this software without specific prior written permission. *
|
|
* *
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
|
* *
|
|
* OpenScop Library, a library to manipulate OpenScop formats and data *
|
|
* structures. Written by: *
|
|
* Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and *
|
|
* Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> *
|
|
* *
|
|
*****************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include <osl/macros.h>
|
|
#include <osl/util.h>
|
|
|
|
|
|
/*+***************************************************************************
|
|
* Utility functions *
|
|
*****************************************************************************/
|
|
|
|
|
|
/**
|
|
* osl_util_skip_blank_and_comments "file skip" function:
|
|
* this function reads the open file 'file' line by line and skips
|
|
* blank/comment lines and spaces. The first line where there is some
|
|
* useful information is stored at the address 'str' (the memory to
|
|
* store the line must be allocated before the call to this function
|
|
* and must be at least OSL_MAX_STRING * sizeof(char)). The pointer
|
|
* to the first useful information in this line is returned by the
|
|
* function.
|
|
* \param[in] file The (opened) file to read.
|
|
* \param[in] str Address of an allocated space to store the first line
|
|
* that contains useful information.
|
|
* \return The address of the first useful digit in str.
|
|
*/
|
|
char * osl_util_skip_blank_and_comments(FILE * file, char * str) {
|
|
char * start;
|
|
|
|
do {
|
|
start = fgets(str, OSL_MAX_STRING, file);
|
|
while ((start != NULL) && isspace(*start) && (*start != '\n'))
|
|
start++;
|
|
}
|
|
while (start != NULL && (*start == '#' || *start == '\n'));
|
|
|
|
return start;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_sskip_blank_and_comments "string skip" function:
|
|
* this function updates the str pointer, which initialy points to a string,
|
|
* to the first character in this string which is not a space or a comment
|
|
* (comments start at '#' and end at '\n'), or to the end of string.
|
|
* \param[in,out] str Address of a string, updated to the address of
|
|
* the first non-space or comment character.
|
|
*/
|
|
void osl_util_sskip_blank_and_comments(char ** str) {
|
|
do {
|
|
// Skip spaces/blanc lines.
|
|
while (*str && **str && isspace(**str))
|
|
(*str)++;
|
|
|
|
// Skip the comment if any.
|
|
if (*str && **str && **str == '#') {
|
|
while (**str && **str != '\n') {
|
|
(*str)++;
|
|
}
|
|
}
|
|
}
|
|
while (*str && **str && **str == '\n');
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_read_int function:
|
|
* reads an int on the input 'file' or the input string 'str' depending on
|
|
* which one is not NULL (exactly one of them must not be NULL).
|
|
* \param[in] file The file where to read an int (if not NULL).
|
|
* \param[in,out] str The string where to read an int (if not NULL). This
|
|
* pointer is updated to reflect the read and points
|
|
* after the int in the input string.
|
|
* \return The int that has been read.
|
|
*/
|
|
int osl_util_read_int(FILE * file, char ** str) {
|
|
char s[OSL_MAX_STRING], * start;
|
|
int res;
|
|
int i = 0;
|
|
|
|
if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
|
|
OSL_error("one and only one of the two parameters can be non-NULL");
|
|
|
|
if (file != NULL) {
|
|
// Parse from a file.
|
|
start = osl_util_skip_blank_and_comments(file, s);
|
|
if (sscanf(start, " %d", &res) != 1)
|
|
OSL_error("an int was expected");
|
|
}
|
|
else {
|
|
// Parse from a string.
|
|
// Skip blank/commented lines.
|
|
osl_util_sskip_blank_and_comments(str);
|
|
|
|
// Build the chain to analyze.
|
|
while (**str && !isspace(**str) && **str != '\n' && **str != '#')
|
|
s[i++] = *((*str)++);
|
|
s[i] = '\0';
|
|
if (sscanf(s, "%d", &res) != 1)
|
|
OSL_error("an int was expected");
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_read_string function:
|
|
* reads a string on the input 'file' or the input string 'str' depending on
|
|
* which one is not NULL (exactly one of them must not be NULL).
|
|
* \param[in] file The file where to read a string (if not NULL).
|
|
* \param[in,out] str The string where to read a string (if not NULL). This
|
|
* pointer is updated to reflect the read and points
|
|
* after the string in the input string.
|
|
* \return The string that has been read.
|
|
*/
|
|
char * osl_util_read_string(FILE * file, char ** str) {
|
|
char s[OSL_MAX_STRING], * start;
|
|
char * res;
|
|
int i = 0;
|
|
|
|
if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
|
|
OSL_error("one and only one of the two parameters can be non-NULL");
|
|
|
|
OSL_malloc(res, char *, OSL_MAX_STRING * sizeof(char));
|
|
if (file != NULL) {
|
|
// Parse from a file.
|
|
start = osl_util_skip_blank_and_comments(file, s);
|
|
if (sscanf(start, " %s", res) != 1)
|
|
OSL_error("a string was expected");
|
|
}
|
|
else {
|
|
// Parse from a string.
|
|
// Skip blank/commented lines.
|
|
osl_util_sskip_blank_and_comments(str);
|
|
|
|
// Build the chain to analyze.
|
|
while (**str && !isspace(**str) && **str != '\n' && **str != '#')
|
|
s[i++] = *((*str)++);
|
|
s[i] = '\0';
|
|
if (sscanf(s, "%s", res) != 1)
|
|
OSL_error("a string was expected");
|
|
}
|
|
|
|
OSL_realloc(res, char *, strlen(res) + 1);
|
|
return res;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_read_line function:
|
|
* reads a line on the input 'file' or the input string 'str' depending on
|
|
* which one is not NULL (exactly one of them must not be NULL). A line
|
|
* is defined as the array of characters before the comment tag or the end of
|
|
* line (it may include spaces).
|
|
* \param[in] file The file where to read a line (if not NULL).
|
|
* \param[in,out] str The string where to read a line (if not NULL). This
|
|
* pointer is updated to reflect the read and points
|
|
* after the line in the input string.
|
|
* \return The line that has been read.
|
|
*/
|
|
char * osl_util_read_line(FILE * file, char ** str) {
|
|
char s[OSL_MAX_STRING], * start;
|
|
char * res;
|
|
int i = 0;
|
|
|
|
if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
|
|
OSL_error("one and only one of the two parameters can be non-NULL");
|
|
|
|
OSL_malloc(res, char *, OSL_MAX_STRING * sizeof(char));
|
|
if (file != NULL) {
|
|
// Parse from a file.
|
|
start = osl_util_skip_blank_and_comments(file, s);
|
|
while (*start && *start != '\n' && *start != '#' && i < OSL_MAX_STRING)
|
|
res[i++] = (*start)++;
|
|
}
|
|
else {
|
|
// Parse from a string.
|
|
osl_util_sskip_blank_and_comments(str);
|
|
while (**str && **str != '\n' && **str != '#' && i < OSL_MAX_STRING)
|
|
res[i++] = *((*str)++);
|
|
}
|
|
|
|
res[i] = '\0';
|
|
OSL_realloc(res, char *, strlen(res) + 1);
|
|
return res;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_read_int internal function:
|
|
* reads a tag (the form of a tag with name "name" is \<name\>) on the input
|
|
* 'file' or the input string 'str' depending on which one is not NULL (exactly
|
|
* one of them must not be NULL). It returns the name of the tag (thus without
|
|
* the < and > as a string. Note that in the case of an ending tag, e.g.,
|
|
* \</foo\>, the slash is returned as a part of the name, e.g., /foo.
|
|
* \param[in] file The file where to read a tag (if not NULL).
|
|
* \param[in,out] str The string where to read a tag (if not NULL). This
|
|
* pointer is updated to reflect the read and points
|
|
* after the tag in the input string.
|
|
* \return The tag name that has been read.
|
|
*/
|
|
char * osl_util_read_tag(FILE * file, char ** str) {
|
|
char s[OSL_MAX_STRING], * start;
|
|
char * res;
|
|
int i = 0;
|
|
|
|
if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
|
|
OSL_error("one and only one of the two parameters can be non-NULL");
|
|
|
|
// Skip blank/commented lines.
|
|
if (file != NULL) {
|
|
start = osl_util_skip_blank_and_comments(file, s);
|
|
str = &start;
|
|
}
|
|
else {
|
|
osl_util_sskip_blank_and_comments(str);
|
|
}
|
|
|
|
// Pass the starting '<'.
|
|
if (**str != '<')
|
|
OSL_error("a \"<\" to start a tag was expected");
|
|
(*str)++;
|
|
|
|
// Read the tag.
|
|
OSL_malloc(res, char *, (OSL_MAX_STRING + 1) * sizeof(char));
|
|
res[OSL_MAX_STRING] = '\0';
|
|
|
|
while (**str && **str != '>') {
|
|
if (((**str >= 'A') && (**str <= 'Z')) ||
|
|
((**str >= 'a') && (**str <= 'z')) ||
|
|
((**str == '/') && (i == 0)) ||
|
|
(**str == '_')) {
|
|
res[i++] = *((*str)++);
|
|
res[i] = '\0';
|
|
}
|
|
else {
|
|
OSL_error("illegal character in the tag name");
|
|
}
|
|
}
|
|
|
|
// Check we actually end up with a '>' and pass it.
|
|
if (**str != '>')
|
|
OSL_error("a \">\" to end a tag was expected");
|
|
(*str)++;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_read_uptotag function:
|
|
* this function reads a file up to a given tag (the tag is read) or the
|
|
* end of file. It puts everything it reads, except the tag, in a string
|
|
* which is returned. However ot returns NULL is the tag is not found.
|
|
* \param[in] file The file where to read the tail.
|
|
* \param[in] tag The tag which, when reached, stops the file reading.
|
|
* \return The string that has been read from the file.
|
|
*/
|
|
char * osl_util_read_uptotag(FILE * file, char * tag) {
|
|
int high_water_mark = OSL_MAX_STRING;
|
|
int nb_chars = 0;
|
|
int lentag = strlen(tag);
|
|
int tag_found = 0;
|
|
char * res;
|
|
|
|
OSL_malloc(res, char *, high_water_mark * sizeof(char));
|
|
|
|
// - Copy everything to the res string.
|
|
while (!feof(file)) {
|
|
res[nb_chars] = fgetc(file);
|
|
nb_chars++;
|
|
|
|
if ((nb_chars >= lentag) &&
|
|
(!strncmp(&res[nb_chars - lentag], tag, lentag))) {
|
|
tag_found = 1;
|
|
break;
|
|
}
|
|
|
|
if (nb_chars >= high_water_mark) {
|
|
high_water_mark += high_water_mark;
|
|
OSL_realloc(res, char *, high_water_mark * sizeof(char));
|
|
}
|
|
}
|
|
|
|
if (!tag_found) {
|
|
OSL_debug("tag was not found, end of file reached");
|
|
free(res);
|
|
return NULL;
|
|
}
|
|
|
|
// - 0-terminate the string.
|
|
OSL_realloc(res, char *, (nb_chars - strlen(tag) + 1) * sizeof(char));
|
|
res[nb_chars - strlen(tag)] = '\0';
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_read_uptoendtag function:
|
|
* this function reads a file up to a given end tag (this end tag is read)
|
|
* or the end of file. The name of the tag is provided as parameter (hence
|
|
* without the starting "</" end the closing ">"). It puts everything it reads
|
|
* in a string which is returned.
|
|
* \param[in] file The file where to read the tail.
|
|
* \param[in] name The name of the end tag to the file reading.
|
|
* \return The string that has been read from the file.
|
|
*/
|
|
char * osl_util_read_uptoendtag(FILE * file, char * name) {
|
|
char tag[strlen(name) + 4];
|
|
|
|
sprintf(tag, "</%s>", name);
|
|
return osl_util_read_uptotag(file, tag);
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_tag_content function:
|
|
* this function returns a freshly allocated string containing the
|
|
* content, in the given string 'str', between the tag '\<name\>' and
|
|
* the tag '\</name\>'. If the tag '\<name\>' is not found, it returns NULL.
|
|
* \param[in] str The string where to find a given content.
|
|
* \param[in] name The name of the tag we are looking for.
|
|
* \return The string between '\<name\>' and '\</name\>' in 'str'.
|
|
*/
|
|
char * osl_util_tag_content(char * str, char * name) {
|
|
int i;
|
|
char * start;
|
|
char * stop;
|
|
char tag[strlen(name) + 3];
|
|
char endtag[strlen(name) + 4];
|
|
int size = 0;
|
|
int lentag;
|
|
char * res = NULL;
|
|
|
|
sprintf(tag, "<%s>", name);
|
|
sprintf(endtag, "</%s>", name);
|
|
|
|
if (str) {
|
|
start = str;
|
|
lentag = strlen(tag);
|
|
for (; start && *start && strncmp(start, tag, lentag); ++start)
|
|
continue;
|
|
|
|
// The tag 'tag' was not found.
|
|
if (! *start)
|
|
return NULL;
|
|
start += lentag;
|
|
stop = start;
|
|
lentag = strlen(endtag);
|
|
for (size = 0; *stop && strncmp(stop, endtag, lentag); ++stop, ++size)
|
|
continue;
|
|
|
|
// the tag 'endtag' was not found.
|
|
if (! *stop)
|
|
return NULL;
|
|
OSL_malloc(res, char *, (size + 1) * sizeof(char));
|
|
|
|
// Copy the chain between the two tags.
|
|
for (++start, i = 0; start != stop; ++start, ++i)
|
|
res[i] = *start;
|
|
res[i] = '\0';
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_safe_strcat function:
|
|
* this function concatenates the string src to the string *dst
|
|
* and reallocates *dst if necessary. The current size of the
|
|
* *dst buffer must be *hwm (high water mark), if there is some
|
|
* reallocation, this value is updated.
|
|
* \param[in,out] dst pointer to the destination string (may be reallocated).
|
|
* \param[in] src string to concatenate to dst.
|
|
* \param[in,out] hwm pointer to the size of the *dst buffer (may be updated).
|
|
*/
|
|
void osl_util_safe_strcat(char ** dst, char * src, int * hwm) {
|
|
|
|
while (strlen(*dst) + strlen(src) >= *hwm) {
|
|
*hwm += OSL_MAX_STRING;
|
|
OSL_realloc(*dst, char *, *hwm * sizeof(char));
|
|
}
|
|
|
|
strcat(*dst, src);
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_get_precision function:
|
|
* this function returns the precision defined by the precision environment
|
|
* variable or the highest available precision if it is not defined.
|
|
* \return environment precision if defined or highest available precision.
|
|
*/
|
|
int osl_util_get_precision() {
|
|
int precision = OSL_PRECISION_DP;
|
|
char * precision_env;
|
|
|
|
#ifdef OSL_GMP_IS_HERE
|
|
precision = OSL_PRECISION_MP;
|
|
#endif
|
|
|
|
precision_env = getenv(OSL_PRECISION_ENV);
|
|
if (precision_env != NULL) {
|
|
if (!strcmp(precision_env, OSL_PRECISION_ENV_SP))
|
|
precision = OSL_PRECISION_SP;
|
|
else if (!strcmp(precision_env, OSL_PRECISION_ENV_DP))
|
|
precision = OSL_PRECISION_DP;
|
|
else if (!strcmp(precision_env, OSL_PRECISION_ENV_MP)) {
|
|
#ifndef OSL_GMP_IS_HERE
|
|
OSL_warning("$OSL_PRECISION says GMP but osl not compiled with "
|
|
"GMP support, switching to double precision");
|
|
precision = OSL_PRECISION_DP;
|
|
#else
|
|
precision = OSL_PRECISION_MP;
|
|
#endif
|
|
}
|
|
else
|
|
OSL_warning("bad OSL_PRECISION environment value, see osl's manual");
|
|
}
|
|
|
|
return precision;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_print_provided function:
|
|
* this function prints a "provided" boolean in a file (file, possibly stdout),
|
|
* with a comment title according to the OpenScop specification.
|
|
* \param[in] file File where the information has to be printed.
|
|
* \param[in] provided The provided boolean to print.
|
|
* \param[in] title A string to use as a title for the provided booblean.
|
|
*/
|
|
void osl_util_print_provided(FILE * file, int provided, char * title) {
|
|
if (provided) {
|
|
fprintf(file, "# %s provided\n", title);
|
|
fprintf(file, "1\n");
|
|
}
|
|
else {
|
|
fprintf(file, "# %s not provided\n", title);
|
|
fprintf(file, "0\n\n");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_identifier_is_here function:
|
|
* this function returns 1 if the input "identifier" is found at the
|
|
* "index" position in the "expression" input string, 0 otherwise.
|
|
* \param[in] expression The input expression.
|
|
* \param[in] identifier The identifier to look for.
|
|
* \param[in] index The position in the expression where to look.
|
|
* \return 1 if the identifier is found at the position in the expression.
|
|
*/
|
|
static
|
|
int osl_util_identifier_is_here(char * expression, char * identifier,
|
|
int index) {
|
|
// If there is no space enough to find the identifier: no.
|
|
if (strlen(identifier) + index > strlen(expression))
|
|
return 0;
|
|
|
|
// If there is a character before and it is in [A-Za-z0-9]: no.
|
|
if ((index > 0) &&
|
|
(((expression[index - 1] >= 'A') && (expression[index - 1] <= 'Z')) ||
|
|
((expression[index - 1] >= 'a') && (expression[index - 1] <= 'z')) ||
|
|
((expression[index - 1] >= '0') && (expression[index - 1] <= '9'))))
|
|
return 0;
|
|
|
|
// If there is a character after and it is in [A-Za-z0-9]: no.
|
|
if ((strlen(identifier) + index < strlen(expression)) &&
|
|
(((expression[strlen(identifier) + index] >= 'A') &&
|
|
(expression[strlen(identifier) + index] <= 'Z')) ||
|
|
((expression[strlen(identifier) + index] >= 'a') &&
|
|
(expression[strlen(identifier) + index] <= 'z')) ||
|
|
((expression[strlen(identifier) + index] >= '0') &&
|
|
(expression[strlen(identifier) + index] <= '9'))))
|
|
return 0;
|
|
|
|
// If the identifier string is not here: no.
|
|
if (strncmp(expression + index, identifier, strlen(identifier)))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_lazy_isolated_identifier function:
|
|
* this function returns 1 if the identifier at the "index" position in the
|
|
* "expression" is guaranteed not to need parenthesis around is we
|
|
* substitute it with anything. For instance the identifier "i" can be
|
|
* always substituted in "A[i]" with no need of parenthesis but not in
|
|
* "A[2*i]". This function is lazy in the sense that it just check obvious
|
|
* cases, not all of them. The identifier must already be at the indicated
|
|
* position, this function does not check that.
|
|
* \param[in] expression The input expression.
|
|
* \param[in] identifier The identifier to check.
|
|
* \param[in] index The position of the identifier in the expression.
|
|
* \return 1 if the identifier is isolated, 0 if unsure.
|
|
*/
|
|
static
|
|
int osl_util_lazy_isolated_identifier(char * expression, char * identifier,
|
|
int index) {
|
|
int look;
|
|
|
|
// If the first non-space character before is not in [\[(,\+=]: no.
|
|
look = index - 1;
|
|
while (look >= 0) {
|
|
if (isspace(expression[look]))
|
|
look--;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if ((look >= 0) &&
|
|
(expression[look] != '[') &&
|
|
(expression[look] != '(') &&
|
|
(expression[look] != '+') &&
|
|
(expression[look] != '=') &&
|
|
(expression[look] != ','))
|
|
return 0;
|
|
|
|
// If the first non-space character after is not in [\]),;\+]: no.
|
|
look = index + strlen(identifier);
|
|
while (look < strlen(expression)) {
|
|
if (isspace(expression[look]))
|
|
look++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if ((look < strlen(expression)) &&
|
|
(expression[look] != ']') &&
|
|
(expression[look] != ')') &&
|
|
(expression[look] != '+') &&
|
|
(expression[look] != ',') &&
|
|
(expression[look] != ';'))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* osl_util_identifier_substitution function:
|
|
* this function replaces some identifiers in an input expression string and
|
|
* returns the final string. The list of identifiers to replace are provided
|
|
* as an array of strings. They are replaced from the input string with the
|
|
* new substring "@i@" or "(@i@)" where i is the rank of the identifier in the
|
|
* array of identifiers. The parentheses are added when it is not obvious that
|
|
* the identifier can be replaced with an arbitrary expression without the
|
|
* need of parentheses. For instance, let us consider the input expression
|
|
* "C[i+j]+=A[2*i]*B[j];" and the array of strings {"i", "j"}: the resulting
|
|
* string would be "C[@0@+@1@]+=A[2*(@0@)]*B[@1@];".
|
|
* \param[in] expression The original expression.
|
|
* \param[in] identifiers NULL-terminated array of identifiers.
|
|
* \return A new string where the ith identifier is replaced by \@i\@.
|
|
*/
|
|
char * osl_util_identifier_substitution(char * expression,
|
|
char ** identifiers) {
|
|
int index, j, found;
|
|
int high_water_mark = OSL_MAX_STRING;
|
|
char buffer[OSL_MAX_STRING];
|
|
char * string;
|
|
|
|
OSL_malloc(string, char *, high_water_mark * sizeof(char));
|
|
string[0] = '\0';
|
|
|
|
index = 0;
|
|
while (index < strlen(expression)) {
|
|
j = 0;
|
|
found = 0;
|
|
while (identifiers[j] != NULL) {
|
|
if (osl_util_identifier_is_here(expression, identifiers[j], index)) {
|
|
if (osl_util_lazy_isolated_identifier(expression,identifiers[j],index))
|
|
sprintf(buffer, "@%d@", j);
|
|
else
|
|
sprintf(buffer, "(@%d@)", j);
|
|
osl_util_safe_strcat(&string, buffer, &high_water_mark);
|
|
index += strlen(identifiers[j]);
|
|
found = 1;
|
|
break;
|
|
}
|
|
j++;
|
|
}
|
|
if (!found) {
|
|
sprintf(buffer, "%c", expression[index]);
|
|
osl_util_safe_strcat(&string, buffer, &high_water_mark);
|
|
index++;
|
|
}
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
|
|
|