1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 sc_string.cpp -- Implementation of a simple string class. 23 24 Original Author: Stan Y. Liao, Synopsys, Inc. 25 26 CHANGE LOG AT END OF FILE 27 *****************************************************************************/ 28 29#include <assert.h> 30#include <ctype.h> 31#include <cstdio> 32#include <stdarg.h> 33#include <string.h> 34 35#include "sysc/utils/sc_iostream.h" 36#include "sysc/utils/sc_string.h" 37#include "sysc/utils/sc_utils_ids.h" 38 39namespace sc_dt { 40 41inline static int 42sc_roundup( int n, int m ) 43{ 44 return ((n - 1) / m + 1) * m; 45} 46 47 48// ---------------------------------------------------------------------------- 49// CLASS : sc_string_rep 50// 51// Reference counting string implementation class. 52// ---------------------------------------------------------------------------- 53 54class sc_string_rep 55{ 56 friend class sc_string_old; 57 friend ::std::ostream& operator<<( ::std::ostream&, const sc_string_old& ); 58 friend ::std::istream& operator>>( ::std::istream&, sc_string_old& ); 59 friend sc_string_old operator+( const char*, const sc_string_old& ); 60 61 sc_string_rep( int size = 16 ) : 62 ref_count(1), alloc( sc_roundup( size, 16 ) ), str( new char[alloc] ) 63 { 64 *str = '\0'; 65 } 66 67 sc_string_rep( const char* s ) : ref_count(1), alloc(0), str(0) 68 { 69 if (s) { 70 alloc = 1 + strlen(s); 71 str = strcpy( new char[alloc], s ); 72 } 73 else { 74 alloc = 16; 75 str = strcpy( new char[alloc], "" ); 76 } 77 } 78 79 sc_string_rep( const char* s, int n); // get first n chars from the string 80 81 ~sc_string_rep() 82 { 83 assert( ref_count == 0 ); 84 delete[] str; 85 } 86 87 void resize( int new_size ); 88 void set_string( const char* s ); 89 90 int ref_count; 91 int alloc; 92 char* str; 93}; 94 95 96// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 97 98sc_string_rep::sc_string_rep( const char* s, int n) : 99 ref_count(1), alloc(0), str(0) 100{ 101 if (s && n>0) { 102 alloc = 1 + n; 103 str = strncpy( new char[alloc], s,n ); 104 str[n] = 00; 105 } 106 else { 107 alloc = 16; 108 str = strcpy( new char[alloc], "" ); 109 } 110} 111 112void 113sc_string_rep::resize( int new_size ) 114{ 115 if (new_size <= alloc) return; 116 alloc = sc_roundup( new_size, 16 ); 117 char* new_str = strcpy( new char[alloc], str ); 118 delete[] str; 119 str = new_str; 120} 121 122void 123sc_string_rep::set_string( const char* s ) 124{ 125 int len = strlen(s); 126 resize( len + 1 ); 127 strcpy( str, s ); 128} 129 130 131// ---------------------------------------------------------------------------- 132// CLASS : sc_string_old 133// 134// String class (yet another). 135// ---------------------------------------------------------------------------- 136 137// constructors 138 139sc_string_old::sc_string_old( int size ) : rep( new sc_string_rep(size) ) 140{ 141} 142 143sc_string_old::sc_string_old( const char* s ) : rep( new sc_string_rep(s) ) 144{ 145} 146 147sc_string_old::sc_string_old( const char* s, int n ) : 148 rep( new sc_string_rep( s, n ) ) 149{ 150} 151 152sc_string_old::sc_string_old( const sc_string_old& s ) : rep( s.rep ) 153{ 154 rep->ref_count ++; 155} 156 157sc_string_old::sc_string_old( sc_string_rep* r ) : rep(r) 158{ 159} 160 161 162// destructor 163 164sc_string_old::~sc_string_old() 165{ 166 if( -- (rep->ref_count) == 0 ) { 167 delete rep; 168 } 169} 170 171 172int 173sc_string_old::length() const 174{ 175 return strlen(rep->str); 176} 177 178sc_string_old 179sc_string_old::operator+( const char* s ) const 180{ 181 int len = length(); 182 sc_string_rep* r = new sc_string_rep( len + strlen(s) + 1 ); 183 strcpy( r->str, rep->str ); 184 strcpy( r->str + len, s ); 185 return sc_string_old(r); 186} 187 188sc_string_old sc_string_old::operator+(char c) const 189{ 190 int len = length(); 191 sc_string_rep* r = new sc_string_rep( len + 2 ); 192 strcpy( r->str, rep->str ); 193 r->str[len] = c; 194 r->str[len+1] = 00; 195 return sc_string_old(r); 196} 197 198sc_string_old 199operator+( const char* s, const sc_string_old& t ) 200{ 201 int len = strlen(s); 202 sc_string_rep* r = new sc_string_rep( len + t.length() + 1 ); 203 strcpy( r->str, s ); 204 strcpy( r->str + len, t ); 205 return sc_string_old(r); 206} 207 208sc_string_old 209sc_string_old::operator+( const sc_string_old& s ) const 210{ 211 int len = length(); 212 sc_string_rep* r = new sc_string_rep( len + s.length() + 1 ); 213 strcpy( r->str, rep->str ); 214 strcpy( r->str + len, s.rep->str ); 215 return sc_string_old(r); 216} 217 218sc_string_old& 219sc_string_old::operator=( const char* s ) 220{ 221 if (rep->ref_count > 1) { 222 --rep->ref_count; 223 rep = new sc_string_rep(s); 224 } 225 else { 226 rep->set_string(s); 227 } 228 return *this; 229} 230 231sc_string_old& 232sc_string_old::operator=( const sc_string_old& s ) 233{ 234 if (&s == this) 235 return *this; 236 if (--(rep->ref_count) == 0) 237 delete rep; 238 rep = s.rep; 239 rep->ref_count++; 240 return *this; 241} 242 243sc_string_old& 244sc_string_old::operator+=( const char* s ) 245{ 246 int oldlen = length(); 247 int slen = strlen(s); 248 if (rep->ref_count > 1) { 249 sc_string_rep* oldrep = rep; 250 --rep->ref_count; 251 rep = new sc_string_rep( oldlen + slen + 1 ); 252 strcpy( rep->str, oldrep->str ); 253 strcpy( rep->str + oldlen, s ); 254 } 255 else { 256 rep->resize( oldlen + slen + 1 ); 257 strcpy( rep->str + oldlen, s ); 258 } 259 return *this; 260} 261 262sc_string_old& sc_string_old::operator+=(char c) 263{ 264 int oldlen = length(); 265 if (rep->ref_count > 1) { 266 sc_string_rep* oldrep = rep; 267 --rep->ref_count; 268 rep = new sc_string_rep( oldlen + 2 ); 269 strcpy( rep->str, oldrep->str ); 270 rep->str[oldlen]=c; 271 rep->str[oldlen+1]=00; 272 } 273 else { 274 rep->resize( oldlen + 2 ); 275 rep->str[oldlen]=c; 276 rep->str[oldlen+1]=00; 277 } 278 return *this; 279} 280 281sc_string_old& 282sc_string_old::operator+=( const sc_string_old& s ) 283{ 284 return this->operator+=( s.rep->str ); 285} 286 287int 288sc_string_old::cmp( const char* s ) const 289{ 290 return strcmp( rep->str, s ); 291} 292 293int 294sc_string_old::cmp( const sc_string_old& s ) const 295{ 296 return strcmp( rep->str, s.rep->str ); 297} 298 299const char* sc_string_old::c_str() const 300{ 301 return rep->str; 302} 303 304// get substring 305sc_string_old sc_string_old::substr(int first,int last) const 306{ 307 if(first<0 || last<0 || first>last || first>=length() || last>=length()) 308 return ""; 309 return sc_string_old(rep->str+first, last-first+1); 310} 311 312 313sc_string_old sc_string_old::make_str(long n) // convert integer to string 314{ 315 char buf[32]; 316 ::std::sprintf(buf,"%ld",n); 317 return sc_string_old(buf); 318} 319 320 321#define DEFINE_RELOP(op) \ 322bool sc_string_old::operator op( const char* s ) const \ 323{ \ 324 return strcmp( rep->str, s ) op 0; \ 325} \ 326bool sc_string_old::operator op( const sc_string_old& s ) const \ 327{ \ 328 return strcmp( rep->str, s.rep->str ) op 0; \ 329} 330 331DEFINE_RELOP(==) 332DEFINE_RELOP(!=) 333DEFINE_RELOP(<) 334DEFINE_RELOP(<=) 335DEFINE_RELOP(>) 336DEFINE_RELOP(>=) 337 338sc_string_old::operator const char*() const 339{ 340 return rep->str; 341} 342 343char 344sc_string_old::operator[]( int i ) const 345{ 346 return rep->str[i]; 347} 348 349char& sc_string_old::operator[]( int i ) 350{ 351 if (rep->ref_count > 1) { 352 rep->ref_count--; 353 rep = new sc_string_rep(rep->str); 354 } 355 return rep->str[i]; 356} 357 358void 359sc_string_old::set( int i, char c ) 360{ 361 if (rep->ref_count > 1) { 362 rep->ref_count--; 363 rep = new sc_string_rep(rep->str); 364 } 365 rep->str[i] = c; 366} 367 368#if defined(_MSC_VER) 369 // Windows provides safer implementation 370# define sc_vsnprintf _vsnprintf 371#else 372# define sc_vsnprintf vsnprintf 373#endif 374 375sc_string_old sc_string_old::to_string(const char* format, ...) 376{ 377 va_list argptr; 378 sc_string_old result; 379 char buffer[1024]; // static string buffer 380 buffer[1023]=000; 381 382 va_start(argptr, format); 383 int cnt = sc_vsnprintf(buffer, 1024, format, argptr); 384 if(cnt>1023) // string too long 385 { 386 int buf_size = 1024; 387 const int max_size = 65000; 388 char* buf = 0; // dynamic string buffer 389 do 390 { 391 delete[] buf; 392 buf_size*=2; 393 buf = new char[buf_size]; 394 cnt = sc_vsnprintf(buf, buf_size, format, argptr); 395 } 396 while( buf_size<max_size && cnt>=buf_size); 397 if(cnt>=buf_size) 398 { 399 // string is longer the the maximum buffer size (max_size) 400 SC_REPORT_WARNING( sc_core::SC_ID_STRING_TOO_LONG_, "truncated" ); 401 buf[buf_size-1] = 000; 402 } 403 result = buf; 404 delete[] buf; 405 } 406 else 407 result = buffer; 408 409 va_end(argptr); 410 411 return result; 412} 413 414void 415sc_string_old::print( ::std::ostream& os ) const 416{ 417 os << rep->str; 418} 419 420void sc_string_old::test(int position)const 421{ 422 if(position<0 || position>=length()) 423 SC_REPORT_ERROR( sc_core::SC_ID_OUT_OF_BOUNDS_, "sc_string_old::test" ); 424} 425 426// TODO: conveniece formatting functions for common types 427// e.g. sc_string_old("a=%d, s is %s").fmt(1).fmt("string") 428// should produce a=1, s is string 429// it should be safe: if less arguments specified 430// it should print %specifier; extra arguments should be ignored 431// if the type of the argument is incompatible with format 432// specifier it should be ignored 433// 434 435unsigned 436sc_string_old::fmt_length()const 437{ 438 unsigned result=0; 439 if((*this)[0]!='%') 440 return 0; 441 else 442 result++; 443 if(is_delimiter("-+0 #",result)) // flags 444 result++; 445 while(is_delimiter("0123456789*",result)) // width 446 result++; 447 if(rep->str[result]=='.') // precision 448 { 449 result++; 450 unsigned old_result = result; 451 while(is_delimiter("0123456789*",result)) result++; 452 if(old_result == result) //error in format 453 return 0; 454 } 455 if(is_delimiter("hlL",result)) result++; // I64 is not supported 456 if(is_delimiter("cCdiouxXeEfgGnpsS",result)) 457 result++; 458 else // error in format 459 return 0; 460 return result; 461} 462 463sc_string_old& 464sc_string_old::fmt(const sc_string_old& s) 465{ 466 return fmt(s.c_str()); 467} 468 469int 470sc_string_old::pos( const sc_string_old& sub_string ) const 471{ 472 int sub_len = sub_string.length(); 473 if( sub_len == 0 ) { 474 return 0; // empty string always matches 475 } 476 int ind = 0; 477 int len = length(); 478 bool found = false; 479 while( ind < len && ! found ) 480 { 481 found = ( sub_string == substr( ind, ind + sub_len - 1 ) ); 482 ++ ind; 483 } 484 if( found ) { 485 return -- ind; 486 } else { 487 return -1; 488 } 489} 490 491sc_string_old& 492sc_string_old::remove(unsigned index, unsigned length) 493{ 494 test((int)index); 495 if(length!=0) 496 (*this) = substr(0,index-1) + substr(index+length,this->length()-1); 497 return *this; 498} 499 500sc_string_old& 501sc_string_old::insert(const sc_string_old& sub_string, unsigned index) 502{ 503 if(index>(unsigned)length()) 504 SC_REPORT_ERROR( sc_core::SC_ID_OUT_OF_BOUNDS_, "sc_string_old::insert" ); 505 return (*this) = substr(0,index-1)+sub_string+substr(index,length()-1); 506} 507 508bool 509sc_string_old::is_delimiter(const sc_string_old& str, unsigned index)const 510{ 511 test((int)index); 512 return str.contains(rep->str[index]); 513} 514 515bool 516sc_string_old::contains(char c)const 517{ 518 int len = length(); 519 int i=0; 520 bool found = false; 521 while(!found && i<len) 522 found = rep->str[i++]==c; 523 return found; 524} 525 526sc_string_old 527sc_string_old::uppercase()const 528{ 529 int len = length(); 530 sc_string_old temp(*this); 531 for(int i=0; i<len; i++) 532 { 533 char c = temp.rep->str[i]; 534 if(c>='a' && c<='z') 535 temp.rep->str[i] = static_cast<char>( c-32 ); 536 } 537 return temp; 538} 539 540sc_string_old 541sc_string_old::lowercase()const 542{ 543 int len = length(); 544 sc_string_old temp(*this); 545 for(int i=0; i<len; i++) 546 { 547 char c = temp.rep->str[i]; 548 if(c>='A' && c<='Z') 549 temp.rep->str[i] = static_cast<char>( c+32 ); 550 } 551 return temp; 552} 553 554 555// ---------------------------------------------------------------------------- 556 557::std::istream& 558operator >> ( ::std::istream& is, sc_string_old& s ) 559{ 560 if( s.rep->ref_count > 1 ) { 561 -- s.rep->ref_count; 562 s.rep = new sc_string_rep; 563 } 564 565 int i = 0; 566 char* p = s.rep->str; 567 char c; 568 569 // skip white spaces 570 while( is.get( c ) && isspace( c ) ) 571 ; 572 573 for( ; is.good() && ! isspace( c ); is.get( c ) ) { 574 if( i > s.rep->alloc - 2 ) { 575 s.rep->str[i] = '\0'; 576 s.rep->resize( (int) (s.rep->alloc * 1.5) ); 577 p = s.rep->str + i; 578 } 579 *p ++ = c; 580 i ++; 581 } 582 *p = '\0'; 583 584 return is; 585} 586 } // namespace sc_dt 587 588// $Log: sc_string.cpp,v $ 589// Revision 1.6 2011/08/29 18:04:32 acg 590// Philipp A. Hartmann: miscellaneous clean ups. 591// 592// Revision 1.5 2011/08/26 22:49:42 acg 593// Torsten Maehne: remove redudant assignment. 594// 595// Revision 1.4 2011/08/26 20:46:19 acg 596// Andy Goodrich: moved the modification log to the end of the file to 597// eliminate source line number skew when check-ins are done. 598// 599// Revision 1.3 2011/08/24 22:05:56 acg 600// Torsten Maehne: initialization changes to remove warnings. 601// 602// Revision 1.2 2011/02/18 20:38:44 acg 603// Andy Goodrich: Updated Copyright notice. 604// 605// Revision 1.1.1.1 2006/12/15 20:20:06 acg 606// SystemC 2.3 607// 608// Revision 1.3 2006/01/13 18:53:11 acg 609// Andy Goodrich: Added $Log command so that CVS comments are reproduced in 610// the source. 611 612// taf 613