summaryrefslogtreecommitdiff
path: root/strings.c
diff options
context:
space:
mode:
Diffstat (limited to 'strings.c')
-rw-r--r--strings.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/strings.c b/strings.c
new file mode 100644
index 0000000..8956123
--- /dev/null
+++ b/strings.c
@@ -0,0 +1,201 @@
+/* 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 "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;
+
+ 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( 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;
+ strncat( self->value, self->opt, sizeof(self->opt) );
+ assert( strlen( self->value ) <= self->capacity ); /* This is a 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 extend_full( string* self, char const* start, char const* 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 const* 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 const* start, char const* 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 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];
+}
+
+#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
+