diff options
Diffstat (limited to 'src/boost/tools/build/src/engine/jam_strings.cpp')
-rw-r--r-- | src/boost/tools/build/src/engine/jam_strings.cpp | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/boost/tools/build/src/engine/jam_strings.cpp b/src/boost/tools/build/src/engine/jam_strings.cpp new file mode 100644 index 000000000..c9ed8a17f --- /dev/null +++ b/src/boost/tools/build/src/engine/jam_strings.cpp @@ -0,0 +1,240 @@ +/* Copyright David Abrahams 2004. Distributed under the Boost */ +/* Software License, Version 1.0. (See accompanying */ +/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ + +#include "jam.h" +#include "jam_strings.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + + +#ifndef NDEBUG +# define JAM_STRING_MAGIC ((char)0xcf) +# define JAM_STRING_MAGIC_SIZE 4 +static void assert_invariants( string * self ) +{ + int i; + + if ( self->value == 0 ) + { + assert( self->size == 0 ); + assert( self->capacity == 0 ); + assert( self->opt[ 0 ] == 0 ); + return; + } + + assert( self->size < self->capacity ); + assert( ( self->capacity <= sizeof( self->opt ) ) == ( self->value == self->opt ) ); + assert( self->value[ self->size ] == 0 ); + /* String objects modified manually after construction to contain embedded + * '\0' characters are considered structurally valid. + */ + assert( strlen( self->value ) <= self->size ); + + for ( i = 0; i < 4; ++i ) + { + assert( self->magic[ i ] == JAM_STRING_MAGIC ); + assert( self->value[ self->capacity + i ] == JAM_STRING_MAGIC ); + } +} +#else +# define JAM_STRING_MAGIC_SIZE 0 +# define assert_invariants(x) do {} while (0) +#endif + + +void string_new( string * s ) +{ + s->value = s->opt; + s->size = 0; + s->capacity = sizeof( s->opt ); + s->opt[ 0 ] = 0; +#ifndef NDEBUG + memset( s->magic, JAM_STRING_MAGIC, sizeof( s->magic ) ); +#endif + assert_invariants( s ); +} + + +void string_free( string * s ) +{ + assert_invariants( s ); + if ( s->value != s->opt ) + BJAM_FREE( s->value ); + string_new( s ); +} + + +static void string_reserve_internal( string * self, size_t capacity ) +{ + if ( self->value == self->opt ) + { + self->value = (char *)BJAM_MALLOC_ATOMIC( capacity + + JAM_STRING_MAGIC_SIZE ); + self->value[ 0 ] = 0; + size_t opt_size = sizeof(self->opt); // Workaround sizeof in strncat warning. + strncat( self->value, self->opt, opt_size ); + assert( strlen( self->value ) <= self->capacity && "Regression test" ); + } + else + { + self->value = (char *)BJAM_REALLOC( self->value, capacity + + JAM_STRING_MAGIC_SIZE ); + } +#ifndef NDEBUG + memcpy( self->value + capacity, self->magic, JAM_STRING_MAGIC_SIZE ); +#endif + self->capacity = capacity; +} + + +void string_reserve( string * self, size_t capacity ) +{ + assert_invariants( self ); + if ( capacity <= self->capacity ) + return; + string_reserve_internal( self, capacity ); + assert_invariants( self ); +} + + +static void maybe_reserve( string * self, size_t new_size ) +{ + size_t capacity = self->capacity; + if ( capacity <= new_size ) + { + size_t new_capacity = capacity; + while ( new_capacity <= new_size ) + new_capacity <<= 1; + string_reserve_internal( self, new_capacity ); + } +} + + +void string_append( string * self, char const * rhs ) +{ + size_t rhs_size = strlen( rhs ); + size_t new_size = self->size + rhs_size; + assert_invariants( self ); + + maybe_reserve( self, new_size ); + + memcpy( self->value + self->size, rhs, rhs_size + 1 ); + self->size = new_size; + + assert_invariants( self ); +} + + +void string_append_range( string * self, char const * start, char const * finish ) +{ + size_t rhs_size = finish - start; + size_t new_size = self->size + rhs_size; + assert_invariants( self ); + + maybe_reserve( self, new_size ); + + if ( start != finish ) + memcpy( self->value + self->size, start, rhs_size ); + self->size = new_size; + self->value[ new_size ] = 0; + + assert_invariants( self ); +} + + +void string_copy( string * s, char const * rhs ) +{ + string_new( s ); + string_append( s, rhs ); +} + +void string_truncate( string * self, size_t n ) +{ + assert_invariants( self ); + assert( n <= self->capacity ); + self->value[ self->size = n ] = 0; + assert_invariants( self ); +} + + +void string_pop_back( string * self ) +{ + string_truncate( self, self->size - 1 ); +} + + +void string_push_back( string * self, char x ) +{ + string_append_range( self, &x, &x + 1 ); +} + + +char string_back( string * self ) +{ + assert_invariants( self ); + return self->value[ self->size - 1 ]; +} + +void string_rtrim( string * self ) +{ + char *p; + assert_invariants( self ); + p = self->value + self->size - 1; + for ( ; p >= self->value && ( *p == '\0' || isspace( *p ) ); *p-- = 0 ); +} + +#ifndef NDEBUG +void string_unit_test() +{ + { + string s[ 1 ]; + unsigned long i; + unsigned long const limit = sizeof( s->opt ) * 2 + 2; + string_new( s ); + assert( s->value == s->opt ); + for ( i = 0; i < limit; ++i ) + { + string_push_back( s, (char)( i + 1 ) ); + assert( s->size == i + 1 ); + } + assert( s->size == limit ); + assert( s->value != s->opt ); + for ( i = 0; i < limit; ++i ) + assert( s->value[ i ] == (char)( i + 1 ) ); + string_free( s ); + } + + { + const char * const original = " \n\t\v Foo \r\n\v \tBar\n\n\r\r\t\n\v\t \t"; + string copy[ 1 ]; + string_copy( copy, original ); + assert( !strcmp( copy->value, original ) ); + assert( copy->size == strlen( original ) ); + string_free( copy ); + } + + { + const char * const foo = "Foo "; + string foo_copy[ 1 ]; + string_copy( foo_copy, foo ); + string_rtrim( foo_copy ); + assert( !strcmp( foo_copy->value, "Foo" ) ); + + string_rtrim( foo_copy ); + assert( !strcmp( foo_copy->value, "Foo" ) ); + } + { + const char * const bar = "Bar\0\0\0"; + string bar_copy[ 1 ]; + string_copy( bar_copy, bar ); + string_rtrim( bar_copy ); + assert( !strcmp( bar_copy->value, "Bar" ) ); + + string_rtrim( bar_copy ); + assert( !strcmp( bar_copy->value, "Bar" ) ); + } +} +#endif |