| //---------------------------------------------------------------------- |
| // Copyright 2007-2011 Mentor Graphics Corporation |
| // Copyright 2011 Cadence Design Systems, Inc. |
| // All Rights Reserved Worldwide |
| // |
| // Licensed under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in |
| // compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in |
| // writing, software distributed under the License is |
| // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
| // CONDITIONS OF ANY KIND, either express or implied. See |
| // the License for the specific language governing |
| // permissions and limitations under the License. |
| //---------------------------------------------------------------------- |
| |
| |
| #include "uvm_dpi.h" |
| #include <sys/types.h> |
| |
| |
| const char uvm_re_bracket_char = '/'; |
| #define UVM_REGEX_MAX_LENGTH 2048 |
| static char uvm_re[UVM_REGEX_MAX_LENGTH+4]; |
| |
| |
| //-------------------------------------------------------------------- |
| // uvm_re_match |
| // |
| // Match a string to a regular expression. The regex is first lookup |
| // up in the regex cache to see if it has already been compiled. If |
| // so, the compile version is retrieved from the cache. Otherwise, it |
| // is compiled and cached for future use. After compilation the |
| // matching is done using regexec(). |
| //-------------------------------------------------------------------- |
| int uvm_re_match(const char * re, const char *str) |
| { |
| regex_t *rexp; |
| int err; |
| |
| // safety check. Args should never be ~null~ since this is called |
| // from DPI. But we'll check anyway. |
| if(re == NULL) |
| return 1; |
| if(str == NULL) |
| return 1; |
| |
| int len = strlen(re); |
| char * rex = &uvm_re[0]; |
| |
| if (len > UVM_REGEX_MAX_LENGTH) { |
| const char* err_str = "uvm_re_match : regular expression greater than max %0d: |%s|"; |
| char buffer[strlen(err_str) + int_str_max(10) + strlen(re)]; |
| sprintf(buffer, err_str, UVM_REGEX_MAX_LENGTH, re); |
| m_uvm_report_dpi(M_UVM_ERROR, |
| (char*) "UVM/DPI/REGEX_MAX", |
| &buffer[0], |
| M_UVM_NONE, |
| (char*)__FILE__, |
| __LINE__); |
| return 1; |
| } |
| |
| // we copy the regexp because we need to remove any brackets around it |
| strncpy(&uvm_re[0],re,UVM_REGEX_MAX_LENGTH); |
| if (len>1 && (re[0] == uvm_re_bracket_char) && re[len-1] == uvm_re_bracket_char) { |
| uvm_re[len-1] = '\0'; |
| rex++; |
| } |
| |
| rexp = (regex_t*)malloc(sizeof(regex_t)); |
| |
| if (rexp == NULL) { |
| m_uvm_report_dpi(M_UVM_ERROR, |
| (char*) "UVM/DPI/REGEX_ALLOC", |
| (char*) "uvm_re_match: internal memory allocation error", |
| M_UVM_NONE, |
| (char*)__FILE__, |
| __LINE__); |
| return 1; |
| } |
| |
| err = regcomp(rexp, rex, REG_EXTENDED); |
| |
| if (err != 0) { |
| regerror(err,rexp,uvm_re,UVM_REGEX_MAX_LENGTH-1); |
| const char * err_str = "uvm_re_match : invalid glob or regular expression: |%s||%s|"; |
| char buffer[strlen(err_str) + strlen(re) + strlen(uvm_re)]; |
| sprintf(buffer, err_str, re, uvm_re); |
| m_uvm_report_dpi(M_UVM_ERROR, |
| (char*) "UVM/DPI/REGEX_INV", |
| &buffer[0], |
| M_UVM_NONE, |
| (char*)__FILE__, |
| __LINE__); |
| regfree(rexp); |
| free(rexp); |
| return err; |
| } |
| |
| err = regexec(rexp, str, 0, NULL, 0); |
| |
| //vpi_printf((PLI_BYTE8*) "UVM_INFO: uvm_re_match: re=%s str=%s ERR=%0d\n",rex,str,err); |
| regfree(rexp); |
| free(rexp); |
| |
| return err; |
| } |
| |
| |
| //-------------------------------------------------------------------- |
| // uvm_glob_to_re |
| // |
| // Convert a glob expression to a normal regular expression. |
| //-------------------------------------------------------------------- |
| |
| const char * uvm_glob_to_re(const char *glob) |
| { |
| const char *p; |
| int len; |
| |
| // safety check. Glob should never be ~null~ since this is called |
| // from DPI. But we'll check anyway. |
| if(glob == NULL) |
| return NULL; |
| |
| len = strlen(glob); |
| |
| if (len > 2040) { |
| const char * err_str = "uvm_re_match : glob expression greater than max 2040: |%s|"; |
| char buffer[strlen(err_str) + strlen(glob)]; |
| sprintf(buffer, err_str, glob); |
| m_uvm_report_dpi(M_UVM_ERROR, |
| (char*) "UVM/DPI/REGEX_MAX", |
| &buffer[0], |
| M_UVM_NONE, |
| (char*)__FILE__, |
| __LINE__); |
| return glob; |
| } |
| |
| // If either of the following cases appear then return an empty string |
| // |
| // 1. The glob string is empty (it has zero characters) |
| // 2. The glob string has a single character that is the |
| // uvm_re_bracket_char (i.e. "/") |
| if(len == 0 || (len == 1 && *glob == uvm_re_bracket_char)) |
| { |
| uvm_re[0] = '\0'; |
| return &uvm_re[0]; // return an empty string |
| } |
| |
| // If bracketed with the /glob/, then it's already a regex |
| if(glob[0] == uvm_re_bracket_char && glob[len-1] == uvm_re_bracket_char) |
| { |
| strcpy(uvm_re,glob); |
| return &uvm_re[0]; |
| } |
| else |
| { |
| // Convert the glob to a true regular expression (Posix syntax) |
| len = 0; |
| |
| uvm_re[len++] = uvm_re_bracket_char; |
| |
| // ^ goes at the beginning... |
| if (*glob != '^') |
| uvm_re[len++] = '^'; |
| |
| for(p = glob; *p; p++) |
| { |
| // Replace the glob metacharacters with corresponding regular |
| // expression metacharacters. |
| switch(*p) |
| { |
| case '*': |
| uvm_re[len++] = '.'; |
| uvm_re[len++] = '*'; |
| break; |
| |
| case '+': |
| uvm_re[len++] = '.'; |
| uvm_re[len++] = '+'; |
| break; |
| |
| case '.': |
| uvm_re[len++] = '\\'; |
| uvm_re[len++] = '.'; |
| break; |
| |
| case '?': |
| uvm_re[len++] = '.'; |
| break; |
| |
| case '[': |
| uvm_re[len++] = '\\'; |
| uvm_re[len++] = '['; |
| break; |
| |
| case ']': |
| uvm_re[len++] = '\\'; |
| uvm_re[len++] = ']'; |
| break; |
| |
| case '(': |
| uvm_re[len++] = '\\'; |
| uvm_re[len++] = '('; |
| break; |
| |
| case ')': |
| uvm_re[len++] = '\\'; |
| uvm_re[len++] = ')'; |
| break; |
| |
| default: |
| uvm_re[len++] = *p; |
| break; |
| } |
| } |
| } |
| |
| // Let's check to see if the regular expression is bounded by ^ at |
| // the beginning and $ at the end. If not, add those characters in |
| // the appropriate position. |
| |
| if (uvm_re[len-1] != '$') |
| uvm_re[len++] = '$'; |
| |
| uvm_re[len++] = uvm_re_bracket_char; |
| |
| uvm_re[len++] = '\0'; |
| |
| return &uvm_re[0]; |
| } |
| |
| |
| //-------------------------------------------------------------------- |
| // uvm_dump_re_cache |
| // |
| // Dumps the set of regular expressions stored in the cache |
| //-------------------------------------------------------------------- |
| |
| void uvm_dump_re_cache() |
| { |
| m_uvm_report_dpi(M_UVM_INFO, |
| (char*) "UVM/DPI/REGEX_MAX", |
| (char*) "uvm_dump_re_cache: cache not implemented", |
| M_UVM_LOW, |
| (char*)__FILE__, |
| __LINE__); |
| } |
| |