mirror of
https://github.com/boostorg/build.git
synced 2026-02-11 23:52:20 +00:00
188 lines
4.1 KiB
C
188 lines
4.1 KiB
C
#include "strings.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
#ifndef NDEBUG
|
|
# define JAM_STRING_MAGIC ((char)0xcf)
|
|
# define JAM_STRING_MAGIC_SIZE 4
|
|
static void assert_invariants( string* self )
|
|
{
|
|
int i;
|
|
|
|
assert( self->size < self->capacity );
|
|
assert( ( self->capacity <= sizeof(self->opt) ) == ( self->value == self->opt ) );
|
|
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 )
|
|
free( s->value );
|
|
}
|
|
|
|
static void string_reserve_internal( string* self, size_t capacity )
|
|
{
|
|
if ( self->value == self->opt )
|
|
{
|
|
self->value = (char*)malloc( capacity + JAM_STRING_MAGIC_SIZE );
|
|
self->value[0] = 0;
|
|
strncat( self->value, self->opt, sizeof(self->opt) );
|
|
assert( strlen( self->value ) <= self->capacity ); /* This is a regression test */
|
|
}
|
|
else
|
|
{
|
|
self->value = (char*)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 extend_full( string* self, char* start, char *finish )
|
|
{
|
|
size_t new_size = self->capacity + ( finish - start );
|
|
size_t new_capacity = self->capacity;
|
|
size_t old_size = self->capacity;
|
|
while ( new_capacity < new_size + 1)
|
|
new_capacity <<= 1;
|
|
string_reserve_internal( self, new_capacity );
|
|
memcpy( self->value + old_size, start, new_size - old_size );
|
|
self->value[new_size] = 0;
|
|
self->size = new_size;
|
|
}
|
|
|
|
void string_append( string* self, char* rhs )
|
|
{
|
|
char* p = self->value + self->size;
|
|
char* end = self->value + self->capacity;
|
|
assert_invariants( self );
|
|
|
|
while ( *rhs && p != end)
|
|
*p++ = *rhs++;
|
|
|
|
if ( p != end )
|
|
{
|
|
*p = 0;
|
|
self->size = p - self->value;
|
|
}
|
|
else
|
|
{
|
|
extend_full( self, rhs, rhs + strlen(rhs) );
|
|
}
|
|
assert_invariants( self );
|
|
}
|
|
|
|
void string_append_range( string* self, char* start, char* finish )
|
|
{
|
|
char* p = self->value + self->size;
|
|
char* end = self->value + self->capacity;
|
|
assert_invariants( self );
|
|
|
|
while ( p != end && start != finish )
|
|
*p++ = *start++;
|
|
|
|
if ( p != end )
|
|
{
|
|
*p = 0;
|
|
self->size = p - self->value;
|
|
}
|
|
else
|
|
{
|
|
extend_full( self, start, finish );
|
|
}
|
|
assert_invariants( self );
|
|
}
|
|
|
|
void string_copy( string* s, char* 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];
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
void string_unit_test()
|
|
{
|
|
string s[1];
|
|
int i;
|
|
char buffer[sizeof(s->opt) * 2 + 2];
|
|
int limit = sizeof(buffer) > 254 ? 254 : sizeof(buffer);
|
|
|
|
string_new(s);
|
|
|
|
for (i = 0; i < limit; ++i)
|
|
{
|
|
string_push_back( s, (char)(i + 1) );
|
|
};
|
|
|
|
for (i = 0; i < limit; ++i)
|
|
{
|
|
assert( i < s->size );
|
|
assert( s->value[i] == (char)(i + 1));
|
|
}
|
|
|
|
string_free(s);
|
|
|
|
}
|
|
#endif
|
|
|