sc_string.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003   The following code is derived, directly or indirectly, from the SystemC
00004   source code Copyright (c) 1996-2006 by all Contributors.
00005   All Rights reserved.
00006 
00007   The contents of this file are subject to the restrictions and limitations
00008   set forth in the SystemC Open Source License Version 2.4 (the "License");
00009   You may not use this file except in compliance with such restrictions and
00010   limitations. You may obtain instructions on how to receive a copy of the
00011   License at http://www.systemc.org/. Software distributed by Contributors
00012   under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
00013   ANY KIND, either express or implied. See the License for the specific
00014   language governing rights and limitations under the License.
00015 
00016  *****************************************************************************/
00017 
00018 /*****************************************************************************
00019 
00020   sc_string.cpp -- Implementation of a simple string class.
00021 
00022   Original Author: Stan Y. Liao, Synopsys, Inc.
00023 
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027 
00028   MODIFICATION LOG - modifiers, enter your name, affiliation, date and
00029   changes you are making here.
00030 
00031       Name, Affiliation, Date:
00032   Description of Modification:
00033 
00034  *****************************************************************************/
00035 
00036 // $Log: sc_string.cpp,v $
00037 // Revision 1.1.1.1  2006/12/15 20:31:39  acg
00038 // SystemC 2.2
00039 //
00040 // Revision 1.3  2006/01/13 18:53:11  acg
00041 // Andy Goodrich: Added $Log command so that CVS comments are reproduced in
00042 // the source.
00043 //
00044 
00045 #include <assert.h>
00046 #include <ctype.h>
00047 #include <stdio.h>
00048 #include <stdarg.h>
00049 #include <string.h>
00050 
00051 #include "sysc/utils/sc_iostream.h"
00052 #include "sysc/utils/sc_string.h"
00053 #include "sysc/utils/sc_utils_ids.h"
00054 
00055 namespace sc_dt {
00056 
00057 inline int
00058 sc_roundup( int n, int m )
00059 {
00060     return ((n - 1) / m + 1) * m;
00061 }
00062 
00063 
00064 // ----------------------------------------------------------------------------
00065 //  ENUM : sc_numrep
00066 //
00067 //  Enumeration of number representations for character string conversion.
00068 // ----------------------------------------------------------------------------
00069 
00070 const std::string
00071 to_string( sc_numrep numrep )
00072 {
00073     switch( numrep )
00074     {
00075         case SC_DEC:
00076         return std::string( "SC_DEC" );
00077         case SC_BIN:
00078         return std::string( "SC_BIN" );
00079         case SC_BIN_US:
00080         return std::string( "SC_BIN_US" );
00081         case SC_BIN_SM:
00082         return std::string( "SC_BIN_SM" );
00083         case SC_OCT:
00084         return std::string( "SC_OCT" );
00085         case SC_OCT_US:
00086         return std::string( "SC_OCT_US" );
00087         case SC_OCT_SM:
00088         return std::string( "SC_OCT_SM" );
00089         case SC_HEX:
00090         return std::string( "SC_HEX" );
00091         case SC_HEX_US:
00092         return std::string( "SC_HEX_US" );
00093         case SC_HEX_SM:
00094         return std::string( "SC_HEX_SM" );
00095         case SC_CSD:
00096         return std::string( "SC_CSD" );
00097     default:
00098         return std::string( "unknown" );
00099     }
00100 }
00101 
00102 
00103 // ----------------------------------------------------------------------------
00104 //  CLASS : sc_string_rep
00105 //
00106 //  Reference counting string implementation class.
00107 // ----------------------------------------------------------------------------
00108 
00109 class sc_string_rep
00110 {
00111     friend class sc_string_old;
00112     friend ::std::ostream& operator<<( ::std::ostream&, const sc_string_old& );
00113     friend ::std::istream& operator>>( ::std::istream&, sc_string_old& );
00114     friend sc_string_old operator+( const char*, const sc_string_old& );
00115 
00116     sc_string_rep( int size = 16 )
00117     {
00118         ref_count = 1;
00119         alloc = sc_roundup( size, 16 );
00120         str = new char[alloc];
00121         *str = '\0';
00122     }
00123 
00124     sc_string_rep( const char* s )
00125     {
00126         ref_count = 1;
00127         if (s) {
00128             alloc = 1 + strlen(s);
00129             str = strcpy( new char[alloc], s );
00130         }
00131         else {
00132             alloc = 16;
00133             str = strcpy( new char[alloc], "" );
00134         }
00135     }
00136 
00137     sc_string_rep( const char* s, int n); // get first n chars from the string
00138 
00139     ~sc_string_rep()
00140     {
00141         assert( ref_count == 0 );
00142         delete[] str;
00143     }
00144 
00145     void resize( int new_size );
00146     void set_string( const char* s );
00147 
00148     int ref_count;
00149     int alloc;
00150     char* str;
00151 };
00152 
00153 
00154 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
00155 
00156 sc_string_rep::sc_string_rep( const char* s, int n)
00157 {
00158     ref_count = 1;
00159     if (s && n>0) {
00160         alloc = 1 + n;
00161         str = strncpy( new char[alloc], s,n );
00162         str[n] = 00;
00163     }
00164     else {
00165         alloc = 16;
00166         str = strcpy( new char[alloc], "" );
00167     }
00168 }
00169 
00170 void
00171 sc_string_rep::resize( int new_size )
00172 {
00173     if (new_size <= alloc) return;
00174     alloc = sc_roundup( new_size, 16 );
00175     char* new_str = strcpy( new char[alloc], str );
00176     delete[] str;
00177     str = new_str;
00178 }
00179 
00180 void
00181 sc_string_rep::set_string( const char* s )
00182 {
00183     int len = strlen(s);
00184     resize( len + 1 );
00185     strcpy( str, s );
00186 }
00187 
00188 
00189 // ----------------------------------------------------------------------------
00190 //  CLASS : sc_string_old
00191 //
00192 //  String class (yet another).
00193 // ----------------------------------------------------------------------------
00194 
00195 // constructors
00196 
00197 sc_string_old::sc_string_old( int size )
00198 {
00199     rep = new sc_string_rep( size );
00200 }
00201 
00202 sc_string_old::sc_string_old( const char* s )
00203 {
00204     rep = new sc_string_rep( s );
00205 }
00206 
00207 sc_string_old::sc_string_old( const char* s, int n )
00208 {
00209     rep = new sc_string_rep( s, n );
00210 }
00211 
00212 sc_string_old::sc_string_old( const sc_string_old& s )
00213 {
00214     rep = s.rep;
00215     rep->ref_count ++;
00216 }
00217 
00218 sc_string_old::sc_string_old( sc_string_rep* r )
00219 {
00220     rep = r;
00221 }
00222 
00223 
00224 // destructor
00225 
00226 sc_string_old::~sc_string_old()
00227 {
00228     if( -- (rep->ref_count) == 0 ) {
00229         delete rep;
00230     }
00231 }
00232 
00233 
00234 int
00235 sc_string_old::length() const
00236 {
00237     return strlen(rep->str);
00238 }
00239 
00240 sc_string_old
00241 sc_string_old::operator+( const char* s ) const
00242 {
00243     int len = length();
00244     sc_string_rep* r = new sc_string_rep( len + strlen(s) + 1 );
00245     strcpy( r->str, rep->str );
00246     strcpy( r->str + len, s );
00247     return sc_string_old(r);
00248 }
00249 
00250 sc_string_old sc_string_old::operator+(char c) const
00251 {
00252     int len = length();
00253     sc_string_rep* r = new sc_string_rep( len + 2 );
00254     strcpy( r->str, rep->str );
00255     r->str[len] = c;
00256     r->str[len+1] = 00;
00257     return sc_string_old(r);
00258 }
00259 
00260 sc_string_old
00261 operator+( const char* s, const sc_string_old& t )
00262 {
00263     int len = strlen(s);
00264     sc_string_rep* r = new sc_string_rep( len + t.length() + 1 );
00265     strcpy( r->str, s );
00266     strcpy( r->str + len, t );
00267     return sc_string_old(r);
00268 }
00269 
00270 sc_string_old
00271 sc_string_old::operator+( const sc_string_old& s ) const
00272 {
00273     int len = length();
00274     sc_string_rep* r = new sc_string_rep( len + s.length() + 1 );
00275     strcpy( r->str, rep->str );
00276     strcpy( r->str + len, s.rep->str );
00277     return sc_string_old(r);
00278 }
00279 
00280 sc_string_old&
00281 sc_string_old::operator=( const char* s )
00282 {
00283     if (rep->ref_count > 1) {
00284         --rep->ref_count;
00285         rep = new sc_string_rep(s);
00286     }
00287     else {
00288         rep->set_string(s);
00289     }
00290     return *this;
00291 }
00292 
00293 sc_string_old&
00294 sc_string_old::operator=( const sc_string_old& s )
00295 {
00296     if (&s == this)
00297         return *this;
00298     if (--(rep->ref_count) == 0)
00299         delete rep;
00300     rep = s.rep;
00301     rep->ref_count++;
00302     return *this;
00303 }
00304 
00305 sc_string_old&
00306 sc_string_old::operator+=( const char* s )
00307 {
00308     int oldlen = length();
00309     int slen   = strlen(s);
00310     if (rep->ref_count > 1) {
00311         sc_string_rep* oldrep = rep;
00312         --rep->ref_count;
00313         rep = new sc_string_rep( oldlen + slen + 1 );
00314         strcpy( rep->str, oldrep->str );
00315         strcpy( rep->str + oldlen, s );
00316     }
00317     else {
00318         rep->resize( oldlen + slen + 1 );
00319         strcpy( rep->str + oldlen, s );
00320     }
00321     return *this;
00322 }
00323 
00324 sc_string_old& sc_string_old::operator+=(char c)
00325 {
00326     int oldlen = length();
00327     if (rep->ref_count > 1) {
00328         sc_string_rep* oldrep = rep;
00329         --rep->ref_count;
00330         rep = new sc_string_rep( oldlen + 2 );
00331         strcpy( rep->str, oldrep->str );
00332         rep->str[oldlen]=c;
00333         rep->str[oldlen+1]=00;
00334     }
00335     else {
00336         rep->resize( oldlen + 2 );
00337         rep->str[oldlen]=c;
00338         rep->str[oldlen+1]=00;
00339     }
00340     return *this;
00341 }
00342 
00343 sc_string_old&
00344 sc_string_old::operator+=( const sc_string_old& s )
00345 {
00346     return this->operator+=( s.rep->str );
00347 }
00348 
00349 int
00350 sc_string_old::cmp( const char* s ) const
00351 {
00352     return strcmp( rep->str, s );
00353 }
00354 
00355 int
00356 sc_string_old::cmp( const sc_string_old& s ) const
00357 {
00358     return strcmp( rep->str, s.rep->str );
00359 }
00360 
00361 const char* sc_string_old::c_str() const
00362 {
00363   return rep->str;
00364 }
00365 
00366 // get substring
00367 sc_string_old sc_string_old::substr(int first,int last) const
00368 {
00369   if(first<0 || last<0 || first>last || first>=length() || last>=length())
00370     return "";
00371   return sc_string_old(rep->str+first, last-first+1);
00372 }
00373 
00374 
00375 sc_string_old sc_string_old::make_str(long n) // convert integer to string
00376 {
00377   char buf[32];
00378   ::std::sprintf(buf,"%ld",n);
00379   return sc_string_old(buf);
00380 }
00381 
00382 
00383 #define DEFINE_RELOP(op) \
00384 bool sc_string_old::operator op( const char* s ) const \
00385 {                       \
00386     return strcmp( rep->str, s ) op 0;      \
00387 }                       \
00388 bool sc_string_old::operator op( const sc_string_old& s ) const \
00389 {                       \
00390     return strcmp( rep->str, s.rep->str ) op 0; \
00391 }
00392 
00393 DEFINE_RELOP(==)
00394 DEFINE_RELOP(!=)
00395 DEFINE_RELOP(<)
00396 DEFINE_RELOP(<=)
00397 DEFINE_RELOP(>)
00398 DEFINE_RELOP(>=)
00399 
00400 sc_string_old::operator const char*() const
00401 {
00402     return rep->str;
00403 }
00404 
00405 char
00406 sc_string_old::operator[]( int i ) const
00407 {
00408     return rep->str[i];
00409 }
00410 
00411 char& sc_string_old::operator[]( int i )
00412 {
00413     if (rep->ref_count > 1) {
00414         rep->ref_count--;
00415         rep = new sc_string_rep(rep->str);
00416     }
00417     return rep->str[i];
00418 }
00419 
00420 void
00421 sc_string_old::set( int i, char c )
00422 {
00423     if (rep->ref_count > 1) {
00424         rep->ref_count--;
00425         rep = new sc_string_rep(rep->str);
00426     }
00427     rep->str[i] = c;
00428 }
00429 
00430 sc_string_old sc_string_old::to_string(const char* format, ...)
00431 {
00432    va_list argptr;
00433    int cnt;
00434    sc_string_old result;
00435    char buffer[1024]; // static string buffer
00436    buffer[1023]=000;
00437 
00438    va_start(argptr, format);
00439 #if defined(WIN32)
00440    // Windows provides safer implementation
00441 #if defined(_MSC_VER)
00442    cnt = _vsnprintf(buffer, 1024, format, argptr);
00443 #else
00444    cnt = vsnprintf(buffer, 1024, format, argptr);
00445 #endif
00446    if(cnt>1023) // string too long
00447    {
00448      int buf_size = 1024;
00449      const int max_size = 65000;
00450      char* buf; // dynamic buffer
00451      do
00452      {
00453        buf_size*=2;
00454        buf = new char[buf_size];
00455 #if defined(_MSC_VER)
00456        cnt = _vsnprintf(buffer, buf_size, format, argptr);
00457 #else
00458        cnt = vsnprintf(buffer, buf_size, format, argptr);
00459 #endif
00460        if(buf_size<max_size && cnt>=buf_size)
00461          delete[] buf;
00462      }
00463      while( buf_size<max_size && cnt>=buf_size);
00464      if(cnt>=buf_size)
00465      {
00466        // string is longer the the maximum buffer size (max_size)
00467        SC_REPORT_WARNING( sc_core::SC_ID_STRING_TOO_LONG_, "truncated" );
00468        buf[buf_size-1] = 000;
00469      }
00470      result = buf;
00471      delete[] buf;
00472    }
00473    else
00474      result = buffer;
00475 #else
00476    try {
00477      // this may end up in a core dump
00478      // if we are lucky we can catch exception
00479      cnt = vsprintf(buffer, format, argptr);
00480    }
00481    catch(...)
00482    {
00483      SC_REPORT_WARNING( sc_core::SC_ID_STRING_TOO_LONG_,
00484             "program may become unstable" );
00485    }
00486    buffer[1023]=000; // in case it's longer
00487    result = buffer;
00488 #endif
00489    va_end(argptr);
00490 
00491    return result;
00492 }
00493 
00494 void
00495 sc_string_old::print( ::std::ostream& os ) const
00496 {
00497     os << rep->str;
00498 }
00499 
00500 void sc_string_old::test(int position)const
00501 {
00502     if(position<0 || position>=length())
00503         SC_REPORT_ERROR( sc_core::SC_ID_OUT_OF_BOUNDS_, "sc_string_old::test" );
00504 }
00505 
00506 // TODO: conveniece formatting functions for common types
00507 //       e.g. sc_string_old("a=%d, s is %s").fmt(1).fmt("string")
00508 //       should produce a=1, s is string
00509 //       it should be safe: if less arguments specified
00510 //       it should print %specifier; extra arguments should be ignored
00511 //       if the type of the argument is incompatible with format 
00512 //       specifier it should be ignored
00513 //
00514 
00515 unsigned
00516 sc_string_old::fmt_length()const
00517 {
00518     unsigned result=0;
00519     if((*this)[0]!='%')
00520     return 0;
00521     else
00522     result++;
00523     if(is_delimiter("-+0 #",result)) // flags
00524     result++;
00525     while(is_delimiter("0123456789*",result)) // width
00526     result++;
00527     if(rep->str[result]=='.') // precision
00528     {
00529     result++;
00530     unsigned old_result = result;
00531     while(is_delimiter("0123456789*",result)) result++;
00532     if(old_result == result) //error in format
00533         return 0;
00534     }
00535     if(is_delimiter("hlL",result)) result++; // I64 is not supported
00536     if(is_delimiter("cCdiouxXeEfgGnpsS",result)) 
00537     result++;
00538     else // error in format
00539     return 0;
00540     return result;
00541 }
00542 
00543 sc_string_old&
00544 sc_string_old::fmt(const sc_string_old& s)
00545 {
00546     return fmt(s.c_str());
00547 }
00548 
00549 int
00550 sc_string_old::pos( const sc_string_old& sub_string ) const
00551 {
00552     int sub_len = sub_string.length();
00553     if( sub_len == 0 ) {
00554         return 0; // empty string always matches
00555     }
00556     int ind = 0;
00557     int len = length();
00558     bool found = false;
00559     while( ind < len && ! found )
00560     {
00561         found = ( sub_string == substr( ind, ind + sub_len - 1 ) );
00562         ++ ind;
00563     }
00564     if( found ) {
00565         return -- ind;
00566     } else {
00567         return -1;
00568     }
00569 }
00570 
00571 sc_string_old&
00572 sc_string_old::remove(unsigned index, unsigned length)
00573 {
00574     test((int)index);
00575     if(length!=0)
00576     (*this) = substr(0,index-1) + substr(index+length,this->length()-1);
00577     return *this;
00578 }
00579 
00580 sc_string_old&
00581 sc_string_old::insert(const sc_string_old& sub_string, unsigned index)
00582 {
00583     if(index>(unsigned)length())   
00584     SC_REPORT_ERROR( sc_core::SC_ID_OUT_OF_BOUNDS_, "sc_string_old::insert" );
00585     return (*this) = substr(0,index-1)+sub_string+substr(index,length()-1);
00586 }
00587 
00588 bool
00589 sc_string_old::is_delimiter(const sc_string_old& str, unsigned index)const
00590 {
00591     test((int)index);
00592     return str.contains(rep->str[index]);
00593 }
00594 
00595 bool
00596 sc_string_old::contains(char c)const
00597 {
00598     int len = length();
00599     int i=0;
00600     bool found = false;
00601     while(!found && i<len)
00602     found = rep->str[i++]==c;
00603     return found;
00604 }
00605 
00606 sc_string_old
00607 sc_string_old::uppercase()const
00608 {
00609     int len = length();
00610     sc_string_old temp(*this);
00611     for(int i=0; i<len; i++)
00612     {
00613     char c = temp.rep->str[i];
00614     if(c>='a' && c<='z')
00615         temp.rep->str[i] = static_cast<char>( c-32 );
00616     }
00617     return temp;
00618 }
00619 
00620 sc_string_old
00621 sc_string_old::lowercase()const
00622 {
00623     int len = length();
00624     sc_string_old temp(*this);
00625     for(int i=0; i<len; i++)
00626     {
00627     char c = temp.rep->str[i];
00628     if(c>='A' && c<='Z')
00629         temp.rep->str[i] = static_cast<char>( c+32 );
00630     }
00631     return temp;
00632 }
00633 
00634 
00635 // ----------------------------------------------------------------------------
00636 
00637 ::std::istream&
00638 operator >> ( ::std::istream& is, sc_string_old& s )
00639 {
00640     if( s.rep->ref_count > 1 ) {
00641         -- s.rep->ref_count;
00642         s.rep = new sc_string_rep;
00643     }
00644 
00645     int i = 0;
00646     char* p = s.rep->str;
00647     char c;
00648 
00649     // skip white spaces
00650     while( is.get( c ) && isspace( c ) )
00651         ;
00652 
00653     for( ; is.good() && ! isspace( c ); is.get( c ) ) {
00654         if( i > s.rep->alloc - 2 ) {
00655         s.rep->str[i] = '\0';
00656             s.rep->resize( (int) (s.rep->alloc * 1.5) );
00657             p = s.rep->str + i;
00658         }
00659         *p ++ = c;
00660         i ++;
00661     }
00662     *p = '\0';
00663 
00664     return is;
00665 }
00666  } // namespace sc_dt

Generated on Wed Jan 21 15:32:10 2009 for SystemC by  doxygen 1.5.5