| /***************************************************************************** | |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or | |
| more contributor license agreements. See the NOTICE file distributed | |
| with this work for additional information regarding copyright ownership. | |
| Accellera licenses this file to you 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. | |
| *****************************************************************************/ | |
| /***************************************************************************** | |
| sc_string.cpp -- Implementation of a simple string class. | |
| Original Author: Stan Y. Liao, Synopsys, Inc. | |
| CHANGE LOG AT END OF FILE | |
| *****************************************************************************/ | |
| #include <assert.h> | |
| #include <ctype.h> | |
| #include <cstdio> | |
| #include <stdarg.h> | |
| #include <string.h> | |
| #include "sysc/utils/sc_iostream.h" | |
| #include "sysc/utils/sc_string.h" | |
| #include "sysc/utils/sc_utils_ids.h" | |
| namespace sc_dt { | |
| inline static int | |
| sc_roundup( int n, int m ) | |
| { | |
| return ((n - 1) / m + 1) * m; | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_string_rep | |
| // | |
| // Reference counting string implementation class. | |
| // ---------------------------------------------------------------------------- | |
| class sc_string_rep | |
| { | |
| friend class sc_string_old; | |
| friend ::std::ostream& operator<<( ::std::ostream&, const sc_string_old& ); | |
| friend ::std::istream& operator>>( ::std::istream&, sc_string_old& ); | |
| friend sc_string_old operator+( const char*, const sc_string_old& ); | |
| sc_string_rep( int size = 16 ) : | |
| ref_count(1), alloc( sc_roundup( size, 16 ) ), str( new char[alloc] ) | |
| { | |
| *str = '\0'; | |
| } | |
| sc_string_rep( const char* s ) : ref_count(1), alloc(0), str(0) | |
| { | |
| if (s) { | |
| alloc = 1 + strlen(s); | |
| str = strcpy( new char[alloc], s ); | |
| } | |
| else { | |
| alloc = 16; | |
| str = strcpy( new char[alloc], "" ); | |
| } | |
| } | |
| sc_string_rep( const char* s, int n); // get first n chars from the string | |
| ~sc_string_rep() | |
| { | |
| assert( ref_count == 0 ); | |
| delete[] str; | |
| } | |
| void resize( int new_size ); | |
| void set_string( const char* s ); | |
| int ref_count; | |
| int alloc; | |
| char* str; | |
| }; | |
| // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII | |
| sc_string_rep::sc_string_rep( const char* s, int n) : | |
| ref_count(1), alloc(0), str(0) | |
| { | |
| if (s && n>0) { | |
| alloc = 1 + n; | |
| str = strncpy( new char[alloc], s,n ); | |
| str[n] = 00; | |
| } | |
| else { | |
| alloc = 16; | |
| str = strcpy( new char[alloc], "" ); | |
| } | |
| } | |
| void | |
| sc_string_rep::resize( int new_size ) | |
| { | |
| if (new_size <= alloc) return; | |
| alloc = sc_roundup( new_size, 16 ); | |
| char* new_str = strcpy( new char[alloc], str ); | |
| delete[] str; | |
| str = new_str; | |
| } | |
| void | |
| sc_string_rep::set_string( const char* s ) | |
| { | |
| int len = strlen(s); | |
| resize( len + 1 ); | |
| strcpy( str, s ); | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_string_old | |
| // | |
| // String class (yet another). | |
| // ---------------------------------------------------------------------------- | |
| // constructors | |
| sc_string_old::sc_string_old( int size ) : rep( new sc_string_rep(size) ) | |
| { | |
| } | |
| sc_string_old::sc_string_old( const char* s ) : rep( new sc_string_rep(s) ) | |
| { | |
| } | |
| sc_string_old::sc_string_old( const char* s, int n ) : | |
| rep( new sc_string_rep( s, n ) ) | |
| { | |
| } | |
| sc_string_old::sc_string_old( const sc_string_old& s ) : rep( s.rep ) | |
| { | |
| rep->ref_count ++; | |
| } | |
| sc_string_old::sc_string_old( sc_string_rep* r ) : rep(r) | |
| { | |
| } | |
| // destructor | |
| sc_string_old::~sc_string_old() | |
| { | |
| if( -- (rep->ref_count) == 0 ) { | |
| delete rep; | |
| } | |
| } | |
| int | |
| sc_string_old::length() const | |
| { | |
| return strlen(rep->str); | |
| } | |
| sc_string_old | |
| sc_string_old::operator+( const char* s ) const | |
| { | |
| int len = length(); | |
| sc_string_rep* r = new sc_string_rep( len + strlen(s) + 1 ); | |
| strcpy( r->str, rep->str ); | |
| strcpy( r->str + len, s ); | |
| return sc_string_old(r); | |
| } | |
| sc_string_old sc_string_old::operator+(char c) const | |
| { | |
| int len = length(); | |
| sc_string_rep* r = new sc_string_rep( len + 2 ); | |
| strcpy( r->str, rep->str ); | |
| r->str[len] = c; | |
| r->str[len+1] = 00; | |
| return sc_string_old(r); | |
| } | |
| sc_string_old | |
| operator+( const char* s, const sc_string_old& t ) | |
| { | |
| int len = strlen(s); | |
| sc_string_rep* r = new sc_string_rep( len + t.length() + 1 ); | |
| strcpy( r->str, s ); | |
| strcpy( r->str + len, t ); | |
| return sc_string_old(r); | |
| } | |
| sc_string_old | |
| sc_string_old::operator+( const sc_string_old& s ) const | |
| { | |
| int len = length(); | |
| sc_string_rep* r = new sc_string_rep( len + s.length() + 1 ); | |
| strcpy( r->str, rep->str ); | |
| strcpy( r->str + len, s.rep->str ); | |
| return sc_string_old(r); | |
| } | |
| sc_string_old& | |
| sc_string_old::operator=( const char* s ) | |
| { | |
| if (rep->ref_count > 1) { | |
| --rep->ref_count; | |
| rep = new sc_string_rep(s); | |
| } | |
| else { | |
| rep->set_string(s); | |
| } | |
| return *this; | |
| } | |
| sc_string_old& | |
| sc_string_old::operator=( const sc_string_old& s ) | |
| { | |
| if (&s == this) | |
| return *this; | |
| if (--(rep->ref_count) == 0) | |
| delete rep; | |
| rep = s.rep; | |
| rep->ref_count++; | |
| return *this; | |
| } | |
| sc_string_old& | |
| sc_string_old::operator+=( const char* s ) | |
| { | |
| int oldlen = length(); | |
| int slen = strlen(s); | |
| if (rep->ref_count > 1) { | |
| sc_string_rep* oldrep = rep; | |
| --rep->ref_count; | |
| rep = new sc_string_rep( oldlen + slen + 1 ); | |
| strcpy( rep->str, oldrep->str ); | |
| strcpy( rep->str + oldlen, s ); | |
| } | |
| else { | |
| rep->resize( oldlen + slen + 1 ); | |
| strcpy( rep->str + oldlen, s ); | |
| } | |
| return *this; | |
| } | |
| sc_string_old& sc_string_old::operator+=(char c) | |
| { | |
| int oldlen = length(); | |
| if (rep->ref_count > 1) { | |
| sc_string_rep* oldrep = rep; | |
| --rep->ref_count; | |
| rep = new sc_string_rep( oldlen + 2 ); | |
| strcpy( rep->str, oldrep->str ); | |
| rep->str[oldlen]=c; | |
| rep->str[oldlen+1]=00; | |
| } | |
| else { | |
| rep->resize( oldlen + 2 ); | |
| rep->str[oldlen]=c; | |
| rep->str[oldlen+1]=00; | |
| } | |
| return *this; | |
| } | |
| sc_string_old& | |
| sc_string_old::operator+=( const sc_string_old& s ) | |
| { | |
| return this->operator+=( s.rep->str ); | |
| } | |
| int | |
| sc_string_old::cmp( const char* s ) const | |
| { | |
| return strcmp( rep->str, s ); | |
| } | |
| int | |
| sc_string_old::cmp( const sc_string_old& s ) const | |
| { | |
| return strcmp( rep->str, s.rep->str ); | |
| } | |
| const char* sc_string_old::c_str() const | |
| { | |
| return rep->str; | |
| } | |
| // get substring | |
| sc_string_old sc_string_old::substr(int first,int last) const | |
| { | |
| if(first<0 || last<0 || first>last || first>=length() || last>=length()) | |
| return ""; | |
| return sc_string_old(rep->str+first, last-first+1); | |
| } | |
| sc_string_old sc_string_old::make_str(long n) // convert integer to string | |
| { | |
| char buf[32]; | |
| ::std::sprintf(buf,"%ld",n); | |
| return sc_string_old(buf); | |
| } | |
| #define DEFINE_RELOP(op) \ | |
| bool sc_string_old::operator op( const char* s ) const \ | |
| { \ | |
| return strcmp( rep->str, s ) op 0; \ | |
| } \ | |
| bool sc_string_old::operator op( const sc_string_old& s ) const \ | |
| { \ | |
| return strcmp( rep->str, s.rep->str ) op 0; \ | |
| } | |
| DEFINE_RELOP(==) | |
| DEFINE_RELOP(!=) | |
| DEFINE_RELOP(<) | |
| DEFINE_RELOP(<=) | |
| DEFINE_RELOP(>) | |
| DEFINE_RELOP(>=) | |
| sc_string_old::operator const char*() const | |
| { | |
| return rep->str; | |
| } | |
| char | |
| sc_string_old::operator[]( int i ) const | |
| { | |
| return rep->str[i]; | |
| } | |
| char& sc_string_old::operator[]( int i ) | |
| { | |
| if (rep->ref_count > 1) { | |
| rep->ref_count--; | |
| rep = new sc_string_rep(rep->str); | |
| } | |
| return rep->str[i]; | |
| } | |
| void | |
| sc_string_old::set( int i, char c ) | |
| { | |
| if (rep->ref_count > 1) { | |
| rep->ref_count--; | |
| rep = new sc_string_rep(rep->str); | |
| } | |
| rep->str[i] = c; | |
| } | |
| #if defined(_MSC_VER) | |
| // Windows provides safer implementation | |
| # define sc_vsnprintf _vsnprintf | |
| #else | |
| # define sc_vsnprintf vsnprintf | |
| #endif | |
| sc_string_old sc_string_old::to_string(const char* format, ...) | |
| { | |
| va_list argptr; | |
| sc_string_old result; | |
| char buffer[1024]; // static string buffer | |
| buffer[1023]=000; | |
| va_start(argptr, format); | |
| int cnt = sc_vsnprintf(buffer, 1024, format, argptr); | |
| if(cnt>1023) // string too long | |
| { | |
| int buf_size = 1024; | |
| const int max_size = 65000; | |
| char* buf = 0; // dynamic string buffer | |
| do | |
| { | |
| delete[] buf; | |
| buf_size*=2; | |
| buf = new char[buf_size]; | |
| cnt = sc_vsnprintf(buf, buf_size, format, argptr); | |
| } | |
| while( buf_size<max_size && cnt>=buf_size); | |
| if(cnt>=buf_size) | |
| { | |
| // string is longer the the maximum buffer size (max_size) | |
| SC_REPORT_WARNING( sc_core::SC_ID_STRING_TOO_LONG_, "truncated" ); | |
| buf[buf_size-1] = 000; | |
| } | |
| result = buf; | |
| delete[] buf; | |
| } | |
| else | |
| result = buffer; | |
| va_end(argptr); | |
| return result; | |
| } | |
| void | |
| sc_string_old::print( ::std::ostream& os ) const | |
| { | |
| os << rep->str; | |
| } | |
| void sc_string_old::test(int position)const | |
| { | |
| if(position<0 || position>=length()) | |
| SC_REPORT_ERROR( sc_core::SC_ID_OUT_OF_BOUNDS_, "sc_string_old::test" ); | |
| } | |
| // TODO: conveniece formatting functions for common types | |
| // e.g. sc_string_old("a=%d, s is %s").fmt(1).fmt("string") | |
| // should produce a=1, s is string | |
| // it should be safe: if less arguments specified | |
| // it should print %specifier; extra arguments should be ignored | |
| // if the type of the argument is incompatible with format | |
| // specifier it should be ignored | |
| // | |
| unsigned | |
| sc_string_old::fmt_length()const | |
| { | |
| unsigned result=0; | |
| if((*this)[0]!='%') | |
| return 0; | |
| else | |
| result++; | |
| if(is_delimiter("-+0 #",result)) // flags | |
| result++; | |
| while(is_delimiter("0123456789*",result)) // width | |
| result++; | |
| if(rep->str[result]=='.') // precision | |
| { | |
| result++; | |
| unsigned old_result = result; | |
| while(is_delimiter("0123456789*",result)) result++; | |
| if(old_result == result) //error in format | |
| return 0; | |
| } | |
| if(is_delimiter("hlL",result)) result++; // I64 is not supported | |
| if(is_delimiter("cCdiouxXeEfgGnpsS",result)) | |
| result++; | |
| else // error in format | |
| return 0; | |
| return result; | |
| } | |
| sc_string_old& | |
| sc_string_old::fmt(const sc_string_old& s) | |
| { | |
| return fmt(s.c_str()); | |
| } | |
| int | |
| sc_string_old::pos( const sc_string_old& sub_string ) const | |
| { | |
| int sub_len = sub_string.length(); | |
| if( sub_len == 0 ) { | |
| return 0; // empty string always matches | |
| } | |
| int ind = 0; | |
| int len = length(); | |
| bool found = false; | |
| while( ind < len && ! found ) | |
| { | |
| found = ( sub_string == substr( ind, ind + sub_len - 1 ) ); | |
| ++ ind; | |
| } | |
| if( found ) { | |
| return -- ind; | |
| } else { | |
| return -1; | |
| } | |
| } | |
| sc_string_old& | |
| sc_string_old::remove(unsigned index, unsigned length) | |
| { | |
| test((int)index); | |
| if(length!=0) | |
| (*this) = substr(0,index-1) + substr(index+length,this->length()-1); | |
| return *this; | |
| } | |
| sc_string_old& | |
| sc_string_old::insert(const sc_string_old& sub_string, unsigned index) | |
| { | |
| if(index>(unsigned)length()) | |
| SC_REPORT_ERROR( sc_core::SC_ID_OUT_OF_BOUNDS_, "sc_string_old::insert" ); | |
| return (*this) = substr(0,index-1)+sub_string+substr(index,length()-1); | |
| } | |
| bool | |
| sc_string_old::is_delimiter(const sc_string_old& str, unsigned index)const | |
| { | |
| test((int)index); | |
| return str.contains(rep->str[index]); | |
| } | |
| bool | |
| sc_string_old::contains(char c)const | |
| { | |
| int len = length(); | |
| int i=0; | |
| bool found = false; | |
| while(!found && i<len) | |
| found = rep->str[i++]==c; | |
| return found; | |
| } | |
| sc_string_old | |
| sc_string_old::uppercase()const | |
| { | |
| int len = length(); | |
| sc_string_old temp(*this); | |
| for(int i=0; i<len; i++) | |
| { | |
| char c = temp.rep->str[i]; | |
| if(c>='a' && c<='z') | |
| temp.rep->str[i] = static_cast<char>( c-32 ); | |
| } | |
| return temp; | |
| } | |
| sc_string_old | |
| sc_string_old::lowercase()const | |
| { | |
| int len = length(); | |
| sc_string_old temp(*this); | |
| for(int i=0; i<len; i++) | |
| { | |
| char c = temp.rep->str[i]; | |
| if(c>='A' && c<='Z') | |
| temp.rep->str[i] = static_cast<char>( c+32 ); | |
| } | |
| return temp; | |
| } | |
| // ---------------------------------------------------------------------------- | |
| ::std::istream& | |
| operator >> ( ::std::istream& is, sc_string_old& s ) | |
| { | |
| if( s.rep->ref_count > 1 ) { | |
| -- s.rep->ref_count; | |
| s.rep = new sc_string_rep; | |
| } | |
| int i = 0; | |
| char* p = s.rep->str; | |
| char c; | |
| // skip white spaces | |
| while( is.get( c ) && isspace( c ) ) | |
| ; | |
| for( ; is.good() && ! isspace( c ); is.get( c ) ) { | |
| if( i > s.rep->alloc - 2 ) { | |
| s.rep->str[i] = '\0'; | |
| s.rep->resize( (int) (s.rep->alloc * 1.5) ); | |
| p = s.rep->str + i; | |
| } | |
| *p ++ = c; | |
| i ++; | |
| } | |
| *p = '\0'; | |
| return is; | |
| } | |
| } // namespace sc_dt | |
| // $Log: sc_string.cpp,v $ | |
| // Revision 1.6 2011/08/29 18:04:32 acg | |
| // Philipp A. Hartmann: miscellaneous clean ups. | |
| // | |
| // Revision 1.5 2011/08/26 22:49:42 acg | |
| // Torsten Maehne: remove redudant assignment. | |
| // | |
| // Revision 1.4 2011/08/26 20:46:19 acg | |
| // Andy Goodrich: moved the modification log to the end of the file to | |
| // eliminate source line number skew when check-ins are done. | |
| // | |
| // Revision 1.3 2011/08/24 22:05:56 acg | |
| // Torsten Maehne: initialization changes to remove warnings. | |
| // | |
| // Revision 1.2 2011/02/18 20:38:44 acg | |
| // Andy Goodrich: Updated Copyright notice. | |
| // | |
| // Revision 1.1.1.1 2006/12/15 20:20:06 acg | |
| // SystemC 2.3 | |
| // | |
| // Revision 1.3 2006/01/13 18:53:11 acg | |
| // Andy Goodrich: Added $Log command so that CVS comments are reproduced in | |
| // the source. | |
| // taf |