OpenScop  0.9.0
util.c
Go to the documentation of this file.
00001 
00002     /*+-----------------------------------------------------------------**
00003      **                       OpenScop Library                          **
00004      **-----------------------------------------------------------------**
00005      **                            util.c                               **
00006      **-----------------------------------------------------------------**
00007      **                   First version: 08/10/2010                     **
00008      **-----------------------------------------------------------------**
00009 
00010  
00011  *****************************************************************************
00012  * OpenScop: Structures and formats for polyhedral tools to talk together    *
00013  *****************************************************************************
00014  *    ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__,                *
00015  *    /   / /  //  //  //  // /   / /  //  //   / /  // /  /|,_,             *
00016  *   /   / /  //  //  //  // /   / /  //  //   / /  // /  / / /\             *
00017  *  |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/  \            *
00018  *  | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\  \ /\           *
00019  *  | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\          *
00020  *  | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \  \         *
00021  *  | P |n| l | = | s | t |=| = |d| = | = | = | |   |=| o | | \# \  \        *
00022  *  | H | | y |   | e | o | | = |l|   |   | = | |   | | G | |  \  \  \       *
00023  *  | I | |   |   | e |   | |   | |   |   |   | |   | |   | |   \  \  \      *
00024  *  | T | |   |   |   |   | |   | |   |   |   | |   | |   | |    \  \  \     *
00025  *  | E | |   |   |   |   | |   | |   |   |   | |   | |   | |     \  \  \    *
00026  *  | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | /      \* \  \   *
00027  *  | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/        \  \ /   *
00028  *  '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---'          '--'    *
00029  *                                                                           *
00030  * Copyright (C) 2008 University Paris-Sud 11 and INRIA                      *
00031  *                                                                           *
00032  * (3-clause BSD license)                                                    *
00033  * Redistribution and use in source  and binary forms, with or without       *
00034  * modification, are permitted provided that the following conditions        *
00035  * are met:                                                                  *
00036  *                                                                           *
00037  * 1. Redistributions of source code must retain the above copyright notice, *
00038  *    this list of conditions and the following disclaimer.                  *
00039  * 2. Redistributions in binary form must reproduce the above copyright      *
00040  *    notice, this list of conditions and the following disclaimer in the    *
00041  *    documentation and/or other materials provided with the distribution.   *
00042  * 3. The name of the author may not be used to endorse or promote products  *
00043  *    derived from this software without specific prior written permission.  *
00044  *                                                                           *
00045  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR      *
00046  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
00047  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   *
00048  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,          *
00049  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  *
00050  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
00051  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     *
00052  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       *
00053  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF  *
00054  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.         *
00055  *                                                                           *
00056  * OpenScop Library, a library to manipulate OpenScop formats and data       *
00057  * structures. Written by:                                                   *
00058  * Cedric Bastoul     <Cedric.Bastoul@u-psud.fr> and                         *
00059  * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr>                          *
00060  *                                                                           *
00061  *****************************************************************************/
00062 
00063 #include <stdlib.h>
00064 #include <stdio.h>
00065 #include <ctype.h>
00066 #include <string.h>
00067 
00068 #include <osl/macros.h>
00069 #include <osl/util.h>
00070 
00071 
00072 /*+***************************************************************************
00073  *                             Utility functions                             *
00074  *****************************************************************************/
00075 
00076 
00091 char * osl_util_skip_blank_and_comments(FILE * file, char * str) {
00092   char * start;
00093 
00094   do {
00095     start = fgets(str, OSL_MAX_STRING, file);
00096     while ((start != NULL) && isspace(*start) && (*start != '\n'))
00097       start++;
00098   }
00099   while (start != NULL && (*start == '#' || *start == '\n'));
00100 
00101   return start;
00102 }
00103 
00104 
00113 void osl_util_sskip_blank_and_comments(char ** str) {
00114   do {
00115     // Skip spaces/blanc lines.
00116     while (*str && **str && isspace(**str))
00117       (*str)++;
00118 
00119     // Skip the comment if any.
00120     if (*str && **str && **str == '#') {
00121       while (**str && **str != '\n') {
00122         (*str)++;
00123       }
00124     }
00125   }
00126   while (*str && **str && **str == '\n');
00127 }
00128 
00129 
00140 int osl_util_read_int(FILE * file, char ** str) {
00141   char s[OSL_MAX_STRING], * start;
00142   int res;
00143   int i = 0;
00144 
00145   if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
00146     OSL_error("one and only one of the two parameters can be non-NULL");
00147 
00148   if (file != NULL) {
00149     // Parse from a file.
00150     start = osl_util_skip_blank_and_comments(file, s);
00151     if (sscanf(start, " %d", &res) != 1)
00152       OSL_error("an int was expected");
00153   }
00154   else {
00155     // Parse from a string.
00156     // Skip blank/commented lines.
00157     osl_util_sskip_blank_and_comments(str);
00158     
00159     // Build the chain to analyze.
00160     while (**str && !isspace(**str) && **str != '\n' && **str != '#')
00161       s[i++] = *((*str)++);
00162     s[i] = '\0';
00163     if (sscanf(s, "%d", &res) != 1)
00164       OSL_error("an int was expected");
00165   }
00166 
00167   return res;
00168 }
00169 
00170 
00181 char * osl_util_read_string(FILE * file, char ** str) {
00182   char s[OSL_MAX_STRING], * start;
00183   char * res;
00184   int i = 0;
00185 
00186   if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
00187     OSL_error("one and only one of the two parameters can be non-NULL");
00188 
00189   OSL_malloc(res, char *, OSL_MAX_STRING * sizeof(char));
00190   if (file != NULL) {
00191     // Parse from a file.
00192     start = osl_util_skip_blank_and_comments(file, s);
00193     if (sscanf(start, " %s", res) != 1)
00194       OSL_error("a string was expected");
00195   }
00196   else {
00197     // Parse from a string.
00198     // Skip blank/commented lines.
00199     osl_util_sskip_blank_and_comments(str);
00200     
00201     // Build the chain to analyze.
00202     while (**str && !isspace(**str) && **str != '\n' && **str != '#')
00203       s[i++] = *((*str)++);
00204     s[i] = '\0';
00205     if (sscanf(s, "%s", res) != 1)
00206       OSL_error("a string was expected");
00207   }
00208 
00209   OSL_realloc(res, char *, strlen(res) + 1);
00210   return res;
00211 }
00212 
00213 
00226 char * osl_util_read_line(FILE * file, char ** str) {
00227   char s[OSL_MAX_STRING], * start;
00228   char * res;
00229   int i = 0;
00230 
00231   if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
00232     OSL_error("one and only one of the two parameters can be non-NULL");
00233 
00234   OSL_malloc(res, char *, OSL_MAX_STRING * sizeof(char));
00235   if (file != NULL) {
00236     // Parse from a file.
00237     start = osl_util_skip_blank_and_comments(file, s);
00238     while (*start && *start != '\n' && *start != '#' && i < OSL_MAX_STRING)
00239       res[i++] = *start++;
00240   }
00241   else {
00242     // Parse from a string.
00243     osl_util_sskip_blank_and_comments(str);
00244     while (**str && **str != '\n' && **str != '#' && i < OSL_MAX_STRING)
00245       res[i++] = *((*str)++);
00246   }
00247 
00248   res[i] = '\0';
00249   OSL_realloc(res, char *, strlen(res) + 1);
00250   return res;
00251 }
00252 
00253 
00268 char * osl_util_read_tag(FILE * file, char ** str) {
00269   char s[OSL_MAX_STRING], * start;
00270   char * res;
00271   int i = 0;
00272 
00273   if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
00274     OSL_error("one and only one of the two parameters can be non-NULL");
00275 
00276   // Skip blank/commented lines.
00277   if (file != NULL) {
00278     start = osl_util_skip_blank_and_comments(file, s);
00279     str = &start;
00280   }
00281   else {
00282     osl_util_sskip_blank_and_comments(str);
00283   }
00284 
00285   // If the end of the input has been reached, return NULL.
00286   if (((file != NULL) && (feof(file))) ||
00287       ((str  != NULL) && (**str == '\0')))
00288     return NULL;
00289   
00290   // Pass the starting '<'.
00291   if (**str != '<')
00292     OSL_error("a \"<\" to start a tag was expected");
00293   (*str)++;
00294 
00295   // Read the tag.
00296   OSL_malloc(res, char *, (OSL_MAX_STRING + 1) * sizeof(char));
00297   res[OSL_MAX_STRING] = '\0';
00298   
00299   while (**str && **str != '>') {
00300     if (((**str >= 'A') && (**str <= 'Z')) ||
00301         ((**str >= 'a') && (**str <= 'z')) ||
00302         ((**str == '/') && (i == 0))       ||
00303         (**str == '_')) {
00304       res[i++] = *((*str)++);
00305       res[i] = '\0';
00306     }
00307     else {
00308       OSL_error("illegal character in the tag name");
00309     }
00310   }
00311 
00312   // Check we actually end up with a '>' and pass it.
00313   if (**str != '>')
00314     OSL_error("a \">\" to end a tag was expected");
00315   (*str)++;
00316 
00317   return res;
00318 }
00319 
00320 
00334 char * osl_util_read_uptoflag(FILE * file, char ** str, char * flag) {
00335   int high_water_mark = OSL_MAX_STRING;
00336   int nb_chars = 0;
00337   int lenflag = strlen(flag), lenstr;
00338   int flag_found = 0;
00339   char * res;
00340 
00341   if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
00342     OSL_error("one and only one of the two parameters can be non-NULL");
00343   
00344   OSL_malloc(res, char *, high_water_mark * sizeof(char));
00345 
00346   // Copy everything to the res string.
00347   if (str != NULL)
00348     lenstr = strlen(*str);
00349   while (((str  != NULL) && (nb_chars != lenstr)) ||
00350          ((file != NULL) && (!feof(file)))) {
00351     res[nb_chars++] = (str != NULL) ? *((*str)++) : fgetc(file);
00352 
00353     if ((nb_chars >= lenflag) &&
00354         (!strncmp(&res[nb_chars - lenflag], flag, lenflag))) {
00355       flag_found = 1;
00356       break;
00357     }
00358 
00359     if (nb_chars >= high_water_mark) {
00360       high_water_mark += high_water_mark;
00361       OSL_realloc(res, char *, high_water_mark * sizeof(char));
00362     }
00363   }
00364 
00365   if (!flag_found) {
00366     OSL_debug("flag was not found, end of input reached");
00367     free(res);
00368     return NULL;
00369   }
00370 
00371   // - 0-terminate the string.
00372   OSL_realloc(res, char *, (nb_chars - strlen(flag) + 1) * sizeof(char));
00373   res[nb_chars - strlen(flag)] = '\0';
00374 
00375   return res;
00376 }
00377 
00378 
00392 char * osl_util_read_uptotag(FILE * file, char ** str, char * name) {
00393   char tag[strlen(name) + 3];
00394   
00395   sprintf(tag, "<%s>", name);
00396   return osl_util_read_uptoflag(file, str, tag);
00397 }
00398 
00399 
00413 char * osl_util_read_uptoendtag(FILE * file, char ** str, char * name) {
00414   char endtag[strlen(name) + 4];
00415   
00416   sprintf(endtag, "</%s>", name);
00417   return osl_util_read_uptoflag(file, str, endtag);
00418 }
00419 
00420 
00430 char * osl_util_tag_content(char * str, char * name) {
00431   int i;
00432   char * start;
00433   char * stop;
00434   char tag[strlen(name) + 3];
00435   char endtag[strlen(name) + 4];
00436   int size = 0;
00437   size_t lentag;
00438   char * res = NULL;
00439 
00440   sprintf(tag, "<%s>", name);
00441   sprintf(endtag, "</%s>", name);
00442   
00443   if (str) {
00444     start = str;
00445     lentag = strlen(tag);
00446     for (; start && *start && strncmp(start, tag, lentag); ++start)
00447       continue;
00448     
00449     // The tag 'tag' was not found.
00450     if (! *start)
00451       return NULL;
00452     start += lentag;
00453     stop = start;
00454     lentag = strlen(endtag);
00455     for (size = 0; *stop && strncmp(stop, endtag, lentag); ++stop, ++size)
00456       continue;
00457     
00458     // the tag 'endtag' was not found.
00459     if (! *stop)
00460       return NULL;
00461     OSL_malloc(res, char *, (size + 1) * sizeof(char));
00462     
00463     // Copy the chain between the two tags.
00464     for (++start, i = 0; start != stop; ++start, ++i)
00465       res[i] = *start;
00466     res[i] = '\0';
00467   }
00468 
00469   return res;
00470 }
00471 
00472 
00483 void osl_util_safe_strcat(char ** dst, char * src, int * hwm) {
00484 
00485   while ((int)(strlen(*dst) + strlen(src)) >= *hwm) {
00486     *hwm += OSL_MAX_STRING;
00487     OSL_realloc(*dst, char *, *hwm * sizeof(char));
00488   }
00489 
00490   strcat(*dst, src);
00491 }
00492 
00493 
00504 char * osl_util_strdup(char const * str) {
00505   char * dup = NULL;
00506   OSL_malloc(dup, char *, (strlen(str) + 1) * sizeof(char));
00507   if (dup) { strcpy(dup, str); }
00508   return dup;
00509 }
00510 
00511 
00518 int osl_util_get_precision() {
00519   int precision = OSL_PRECISION_DP;
00520   char * precision_env;
00521 
00522 #ifdef OSL_GMP_IS_HERE
00523   precision = OSL_PRECISION_MP;
00524 #endif
00525 
00526   precision_env = getenv(OSL_PRECISION_ENV);
00527   if (precision_env != NULL) {
00528     if (!strcmp(precision_env, OSL_PRECISION_ENV_SP))
00529       precision = OSL_PRECISION_SP;
00530     else if (!strcmp(precision_env, OSL_PRECISION_ENV_DP))
00531       precision = OSL_PRECISION_DP;
00532     else if (!strcmp(precision_env, OSL_PRECISION_ENV_MP)) {
00533 #ifndef OSL_GMP_IS_HERE
00534       OSL_warning("$OSL_PRECISION says GMP but osl not compiled with "
00535                   "GMP support, switching to double precision");
00536       precision = OSL_PRECISION_DP;
00537 #else
00538       precision = OSL_PRECISION_MP;
00539 #endif
00540     }
00541     else
00542       OSL_warning("bad OSL_PRECISION environment value, see osl's manual");
00543   }
00544 
00545   return precision;
00546 }
00547 
00548 
00557 void osl_util_print_provided(FILE * file, int provided, char * title) {
00558   if (provided) {
00559     fprintf(file, "# %s provided\n", title);
00560     fprintf(file, "1\n");
00561   }
00562   else {
00563     fprintf(file, "# %s not provided\n", title);
00564     fprintf(file, "0\n\n");
00565   }
00566 }
00567 
00568 
00578 static
00579 int osl_util_identifier_is_here(char * expression, char * identifier,
00580                                 int index) {
00581   // If there is no space enough to find the identifier: no.
00582   if (strlen(identifier) + index > strlen(expression))
00583     return 0;
00584   
00585   // If there is a character before and it is in [A-Za-z0-9]: no.
00586   if ((index > 0) &&
00587       (((expression[index - 1] >= 'A') && (expression[index - 1] <= 'Z')) || 
00588        ((expression[index - 1] >= 'a') && (expression[index - 1] <= 'z')) || 
00589        ((expression[index - 1] >= '0') && (expression[index - 1] <= '9'))))
00590     return 0;
00591 
00592   // If there is a character after and it is in [A-Za-z0-9]: no.
00593   if ((strlen(identifier) + index < strlen(expression)) &&
00594       (((expression[strlen(identifier) + index] >= 'A') &&
00595         (expression[strlen(identifier) + index] <= 'Z'))   || 
00596        ((expression[strlen(identifier) + index] >= 'a') &&
00597         (expression[strlen(identifier) + index] <= 'z'))   || 
00598        ((expression[strlen(identifier) + index] >= '0') &&
00599         (expression[strlen(identifier) + index] <= '9'))))
00600     return 0;
00601 
00602   // If the identifier string is not here: no.
00603   if (strncmp(expression + index, identifier, strlen(identifier)))
00604     return 0;
00605 
00606   return 1;
00607 }
00608 
00609 
00624 static
00625 int osl_util_lazy_isolated_identifier(char * expression, char * identifier,
00626                                       int index) {
00627   int look;
00628 
00629   // If the first non-space character before is not in [\[(,\+=]: no. 
00630   look = index - 1;
00631   while (look >= 0) {
00632     if (isspace(expression[look]))
00633       look--;
00634     else
00635       break;
00636   }
00637 
00638   if ((look >= 0) &&
00639       (expression[look] != '[') &&
00640       (expression[look] != '(') &&
00641       (expression[look] != '+') &&
00642       (expression[look] != '=') &&
00643       (expression[look] != ','))
00644     return 0;
00645         
00646   // If the first non-space character after is not in [\]),;\+]: no. 
00647   look = index + strlen(identifier);
00648   while (look < (int)strlen(expression)) {
00649     if (isspace(expression[look]))
00650       look++;
00651     else
00652       break;
00653   }
00654 
00655   if ((look < (int)strlen(expression)) &&
00656       (expression[look] != ']')   &&
00657       (expression[look] != ')')   &&
00658       (expression[look] != '+')   &&
00659       (expression[look] != ',')   &&
00660       (expression[look] != ';'))
00661     return 0;
00662 
00663   return 1;
00664 }
00665 
00666 
00682 char * osl_util_identifier_substitution(char * expression,
00683                                         char ** identifiers) {
00684   size_t index;
00685   int j, found;
00686   int high_water_mark = OSL_MAX_STRING;
00687   char buffer[OSL_MAX_STRING];
00688   char * string;
00689  
00690   OSL_malloc(string, char *, high_water_mark * sizeof(char));
00691   string[0] = '\0';
00692 
00693   index = 0;
00694   while (index < strlen(expression)) {
00695     j = 0;
00696     found = 0;
00697     while (identifiers[j] != NULL) {
00698       if (osl_util_identifier_is_here(expression, identifiers[j], index)) {
00699         if (osl_util_lazy_isolated_identifier(expression,identifiers[j],index))
00700           sprintf(buffer, "@%d@", j);
00701         else
00702           sprintf(buffer, "(@%d@)", j);
00703         osl_util_safe_strcat(&string, buffer, &high_water_mark);
00704         index += strlen(identifiers[j]);
00705         found = 1;
00706         break;
00707       }
00708       j++;
00709     }
00710     if (!found) {
00711       sprintf(buffer, "%c", expression[index]);
00712       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00713       index++;
00714     }
00715   }
00716 
00717   return string;
00718 }
00719 
00720 
00721