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