/*
- PROJECT: FlowerSoft C++ library
- FILE : string.cc
- Rehacked by HWN 3/nov/95
- removed String &
- introduced class String_handle
- */
+ string.cc - implement String
+
+ (c) 1997--2003 Han-Wen Nienhuys & Jan Nieuwenhuizen
+
+ */
+
+#ifndef _GNU_SOURCE // we want memmem
+#define _GNU_SOURCE
+#endif
-#include <string.h>
#include <stdlib.h>
#include <stdio.h>
-#include <ctype.h>
#include <assert.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <iostream>
#include "string.hh"
+#include "libc-extension.hh"
+#include "string-convert.hh"
#ifdef STRING_DEBUG
-void* mymemmove( void* dest, void* src, size_t n );
+void* mymemmove (void* dest, void const* src, size_t n);
#define memmove mymemmove
#endif
-static char*
-strlwr( char* s )
+// return array, alloced with new.
+Byte*
+String::get_copy_byte () const
{
- char* p = s;
+ Byte const* src = strh_.to_bytes ();
+ Byte* dest = new Byte[strh_.length () + 1];
+ memcpy (dest, src, strh_.length () + 1);
+ return dest;
+}
- while( *p )
- {
- *p = tolower( *p ); /* a macro on some compilers */
- p++;
- }
- return s;
+char*
+String::get_copy_str0 () const
+{
+ return (char*)get_copy_byte ();
}
-static char*
-strupr( char* s )
+\f
+/*
+ copying, constructing.
+ */
+String&
+String::operator = (String const&source)
{
- char* p = s;
+ strh_ = source.strh_;
+ return *this;
+}
+
- while( *p )
- {
- *p = toupper( *p ); /* a macro on some compilers */
- p++;
- }
- return s;
+String::String (Byte const* byte, int len_i)
+{
+ strh_.set (byte, len_i);
}
-String::String(Rational r)
+/**
+ @see
+ String_convert::
+ */
+String
+to_string (char c, int n)
{
- char * n = Itoa(r.numerator()); // LEAK????
-
- *this = n;
- if (r.denominator() != 1) {
- char * d = Itoa(r.denominator());
- *this += String( '/' ) + String(d);
- //delete d;
- }
-/* delete n;
- */
+ return String_convert::char_string (c, n);
}
-// return array, alloced with new.
-Byte*
-String::copy_byte_p() const
+String
+to_string (double f, char const* format)
{
- Byte const* src = strh_.byte_c_l();
- Byte* dest = new Byte[strh_.length_i() + 1];
- memmove( dest, src, strh_.length_i() + 1 );
- return dest;
+ return String_convert::double_string (f, format);
}
-void
-String::printOn(ostream& os) const
+String
+to_string (int i, char const * format)
{
- if ( length_i() == strlen( ch_c_l() ) )
- os << ch_c_l();
- else
- for ( int i = 0; i < length_i(); i++ )
- os << (Byte)(*this)[ i ];
+ return String_convert::int_string (i, format);
}
-String::String (bool b)
+String
+to_string (bool b)
{
- *this = (char const* ) (b ? "true" : "false");
+ return String_convert::bool_string (b);
}
-String::String( char const* source )
-{
- assert(source);
- strh_ = source;
-}
-
-String::String( Byte const* byte_l, int length_i )
-{
-// assert( !length_i || byte_l );// ugh. Storing null pointers?
- strh_.set( byte_l, length_i );
+String
+to_string (long b)
+{
+ return String_convert::long_string (b);
}
-void
-String::operator +=(String s)
+String
+to_string (char const* format, ... )
{
- strh_.append( s.byte_c_l(), s.length_i() );
+ va_list args;
+ va_start (args, format);
+ String str = String_convert::vform_string (format, args);
+ va_end (args);
+ return str;
}
-int
-String::length_i() const
+\f
+void
+String::append (String s)
{
- return strh_.length_i();
+ strh_.append (s.to_bytes (), s.length ());
}
-
-// will go away, fixed anyway
-String::String( char c, int n )
+void
+String::operator += (String s)
{
- n = n >= 0 ? n : 0;
- char* ch_p = new char[ n ];
- memset( ch_p, c, n );
- strh_.set( (Byte*)ch_p, n );
- delete ch_p;
+ append (s);
}
-String::String(int i)
+void
+String::prepend (String s)
{
- char digits[ 81 ]; // who the fuck is 80???
- digits[ 0 ] = '\0';
- sprintf(digits, "%d", i ); // assume radix 10
- strh_ = digits;
+ s += *this;
+ *this = s;
}
-String::String( const int i, const int n, char const c )
+int
+String::length () const
{
- char fillChar = c;
- if ( fillChar)
- fillChar = '0';
-
- String v( i );
-
- String str = String( fillChar, n - v.length_i() ) + String( v );
- strh_.set( str.byte_c_l(), str.length_i() );
+ return strh_.length ();
}
Byte const*
-String::byte_c_l() const
+String::to_bytes () const
{
- return strh_.byte_c_l();
+ return strh_.to_bytes ();
}
char const*
-String::ch_c_l() const
+String::to_str0 () const
{
- return strh_.ch_c_l();
+ return strh_.to_str0 ();
}
Byte*
-String::byte_l()
+String::get_bytes ()
{
- return strh_.byte_l();
+ return strh_.get_bytes ();
}
char*
-String::ch_l()
+String::get_str0 ()
{
- return strh_.ch_l();
+ return strh_.get_str0 ();
}
-// signed comparison, analogous to memcmp;
+bool
+String::is_empty () const
+{
+ return !length ();
+}
+/**
+ Do a signed comparison, analogous to memcmp;
+ */
int
-String::compare(String const& s1, String const& s2 )
+String::compare (String const& s1, String const& s2)
{
- Byte const* p1 = s1.byte_c_l();
- Byte const* p2 = s2.byte_c_l();
- if ( p1 == p2 )
- return 0;
-
- int i1 = s1.length_i();
- int i2 = s2.length_i();
- int i = i1 <? i2;
+ Byte const* p1 = s1.to_bytes ();
+ Byte const* p2 = s2.to_bytes ();
+ if (p1 == p2)
+ return 0;
- int result= memcmp( p1, p2, i );
- return result ? result : i1-i2;
+ /*
+ don't forget the terminating '\0'
+ */
+ int f = (s1.length () <? s2.length ());
+ int cmp_length = 1+ f;
+ int i = memcmp (p1, p2, cmp_length);
+ return i;
}
-
+\f
int
-String::lastPos( char const c ) const
+String::index_last (char const c) const
{
- // not binary safe
- assert( length_i() == strlen( ch_c_l() ) );
- char const* me = strh_.ch_c_l();
- int pos = 0;
- if ( length_i() )
- {
- char const* p = strrchr(me, c );
- if ( p )
- pos = p - me + 1;
- }
- return pos;
+ if (!length ())
+ return -1;
+
+ char const* me = strh_.to_str0 ();
+ char const* p = (char const*)memrchr ((Byte*)me, length (), c);
+ if (p)
+ return p - me;
+ return -1;
}
int
-String::lastPos( char const* string ) const
-{
- // not binary safe
- assert( length_i() == strlen( ch_c_l() ) );
- int pos = 0;
- int length = strlen( string );
- if ( length_i() && length )
- {
- int nextpos = this->pos( string );
- while( nextpos )
- {
- pos += nextpos;
- nextpos = right( length_i() - pos - length + 1 ).pos( string );
- }
- }
- return pos;
-}
-
-// find c
-// return 0 if not found.
-
-// ? should return length_i()?, as in string.left(pos(delimiter))
-int
-String::pos(char c ) const
-{
- // not binary safe
- assert( length_i() == strlen( ch_c_l() ) );
- char const* me = strh_.ch_c_l();
- int pos = 0;
- if ( length_i() )
- {
- char const* p = strchr( me, c );
- if ( p )
- pos = p - me + 1;
- }
- return pos;
-}
-
-// find searchfor. (what if this == "" && searchfor == "") ???
+String::index_last (char const* string) const // UGK!
+{
+ assert (false); // broken
+ int len = strlen (string); // ugrh
+ if (!length () || !len)
+ return -1;
+
+ int next_i = index (string);
+ if (next_i == -1)
+ return -1;
+
+ int index_i = 0;
+ while (next_i >= 0)
+ {
+ index_i += next_i;
+ next_i = right_string (length () - index_i - len).index (string );
+ }
+ return index_i;
+}
+
+/** find a character.
+
+ @return
+ the index of the leftmost character #c# (0 <= return < length ()),
+ or -1 if not found.
+
+ ? should return length ()?, as in string.left_string (index (delimiter))
+*/
int
-String::pos( char const* searchfor ) const
-{
- // not binary safe
- assert( length_i() == strlen( ch_c_l() ) );
- char const* me = strh_.ch_c_l();
- int pos = 0;
- if ( length_i() && searchfor)
- {
- char const* p = strstr(me, searchfor);
- if ( p )
- pos = p - me + 1;
- }
- return pos;
-}
-
-// find chars of a set.
+String::index (char c) const
+{
+ char const* me = strh_.to_str0 ();
+ char const* p = (char const *) memchr (me,c, length ());
+ if (p)
+ return p - me;
+ return -1;
+}
+
+/**
+ find a substring.
+
+ @return
+1 index of leftmost occurrence of #searchfor#
+ */
int
-String::posAny( char const* string ) const
+String::index (String searchfor) const
{
- // not binary safe
- assert( length_i() == strlen( ch_c_l() ) );
- int pos = 0;
- char const* s = (char const* )strh_.ch_c_l();
- if ( length_i() && string )
- {
- char const* p = strpbrk( s, string );
- if ( p )
- pos = p - s + 1;
- }
- return pos;
+ char const* me = strh_.to_str0 ();
+
+ char const* p = (char const *)
+ memmem (me, length (), searchfor.to_str0 (), searchfor.length ());
+
+ if (p)
+ return p - me;
+ else
+ return -1;
}
+/** find chars of a set.
+
+ @return
+
+ the index of the leftmost occurance of an element of #set#. -1 if
+ nothing is found.
+
+
+*/
+int
+String::index_any (String set) const
+{
+ int n = length ();
+ if (!n)
+ return -1;
+
+ void const * me = (void const *) strh_.to_str0 ();
+ for (int i=0; i < set.length (); i++)
+ {
+ char * found= (char*) memchr (me, set[i], n );
+ if (found)
+ {
+ return found - (char const*)me;
+ }
+ }
+ return -1;
+}
+\f
String
-String::left( int n ) const
+String::left_string (int n) const
{
- if (n >= length_i())
- return *this;
+ if (n >= length ())
+ return *this;
- String retval;
- if (n < 1)
- return retval;
-
- retval = *this;
- retval.strh_.trunc(n);
+ String retval;
+ if (n < 1)
return retval;
+
+ retval = *this;
+ retval.strh_.trunc (n);
+ return retval;
}
-
-// n rightmst chars
String
-String::right( int n ) const
+String::right_string (int n) const
{
- if (n > length_i())
- return *this;
-
- if ( n < 1)
- String();
-
- return String( strh_.byte_c_l() + length_i() - n, n );
+ if (n > length ())
+ return *this;
+
+ if (n < 1)
+ return "";
+
+ return String (strh_.to_bytes () + length () - n, n);
}
String
-String::nomid( const int pos, const int n ) const
+String::nomid_string (int index_i, int n) const
{
- String retval;
-
- if ( pos < 1 )
- return String("");
- if ( pos > length_i())
- return *this;
-
- return String( String( left( pos - 1 ) ) + right( length_i() - pos - n + 1 ));
+ if (index_i < 0)
+ {
+ n += index_i;
+ index_i = 0;
+ }
+ if (n <= 0)
+ return *this;
+
+ return
+ left_string (index_i) +
+ right_string (length () - index_i - n) ;
}
-
String
-String::mid( int pos, int n ) const
+String::cut_string (int index_i, int n) const
{
- // HWN. This SUX: JCN: yep, please change me + all my invocations
- // pos 1 == strh_->string[ 0 ];
- // pos 0 allowed for convenience
- if ( !length_i() || ( pos < 0 ) || ( pos > length_i() ) && ( n < 1 ) )
- return String();
+ if (index_i <0)
+ {
+ n += index_i;
+ index_i=0;
+ }
+
+ if (!length () || (index_i < 0) || (index_i >= length () ) || (n < 1 ) )
+ return String ();
- // overflow...
- if ( ( n > length_i() ) || ( pos + n - 1 > length_i() ) )
- n = length_i() - pos + 1;
+ if ((n > length ()) || (index_i + n > length () ) )
+ n = length () - index_i;
- return String( byte_c_l() + pos -1, n );
+ return String (to_bytes () + index_i, n);
}
-
-
-// to uppercase
+\f
String
-String::upper()
+String::upper_string () const
{
- // not binary safe
- assert( length_i() == strlen( ch_c_l() ) );
- char *s = strh_.byte_l();
- strupr( s );
- return *this;
+ String str = *this;
+ str.to_upper ();
+ return str;
}
-
-
-// to lowercase
-String
-String::lower()
+void
+String::to_upper ()
{
- // not binary safe
- assert( length_i() == strlen( ch_c_l() ) );
- char* s = strh_.byte_l();
- strlwr(s);
- return *this;
+ char *s = (char*)strh_.get_bytes ();
+ strnupr (s ,length ());
}
-String::String (double f, char const* fmt)
+void
+String::to_lower ()
{
- /* worst case would be printing HUGE (or 1/HUGE), which is approx
- 2e318, this number would have approx 318 zero's in its string.
+ char* s = strh_.get_str0 ();
+ strnlwr (s,length ());
+}
- 1024 is a safe length for the buffer
- */
- char buf[1024];
- if (!fmt)
- sprintf(buf, "%f", f);
- else
- sprintf(buf, fmt,f);
- *this = buf;
+String
+String::lower_string () const
+{
+ String str = *this;
+ str.to_lower ();
+ return str;
}
-
-long
-String::value() const
+String
+String::reversed_string () const
{
- long l =0;
- if (length_i()) {
- int conv = sscanf(strh_.ch_c_l(), "%ld", &l);
- assert(conv);
- }
- return l;
+ String str = *this;
+ strrev (str.get_bytes (), str.length ());
+ return str;
}
-double
-String::fvalue() const
+int
+String::to_int () const
{
- double d =0;
- if (length_i()) {
- int conv = sscanf(strh_.ch_c_l(), "%lf", &d);
- assert(conv);
- }
- return d;
+ return String_convert::dec2int (*this);
}
-
-String quoteString( String msg, String quote)
+double
+String::to_double () const
{
- return msg + " `" + quote + "' ";
+ return String_convert::dec2double (*this);
}
-
-Byte*
-strrev( Byte* byte_l, int length_i )
+#ifdef STREAM_SUPPORT
+ostream &
+operator << (ostream& os, String d)
{
- Byte by;
- Byte* left_byte_l = byte_l;
- Byte* right_byte_l = byte_l + length_i;
-
- while ( right_byte_l > left_byte_l ) {
- by = *left_byte_l;
- *left_byte_l++ = *right_byte_l;
- *right_byte_l-- = by;
- }
- return byte_l;
+ d.print_on (os);
+ return os;
}
-String
-String::reversed() const
+void
+String::print_on (ostream& os) const
{
- String str = *this;
- strrev( str.byte_l(), str.length_i() );
- return str;
+ if (!strh_.is_binary_bo ())
+ os << to_str0 ();
+ else
+ for (int i = 0; i < length (); i++)
+ os << (Byte) (*this)[ i ];
}
+#endif