Imported Upstream version 201104
[platform/upstream/boost-jam.git] / strings.c
1 /* Copyright David Abrahams 2004. Distributed under the Boost */
2 /* Software License, Version 1.0. (See accompanying */
3 /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
4
5 #include "jam.h"
6 #include "strings.h"
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <stdio.h>
11
12
13 #ifndef NDEBUG
14 # define JAM_STRING_MAGIC ((char)0xcf)
15 # define JAM_STRING_MAGIC_SIZE 4
16 static void assert_invariants( string* self )
17 {
18     int i;
19
20     if ( self->value == 0 )
21     {
22         assert( self->size == 0 );
23         assert( self->capacity == 0 );
24         assert( self->opt[0] == 0 );
25         return;
26     }
27
28     assert( self->size < self->capacity );
29     assert( ( self->capacity <= sizeof(self->opt) ) == ( self->value == self->opt ) );
30     assert( strlen( self->value ) == self->size );
31
32     for (i = 0; i < 4; ++i)
33     {
34         assert( self->magic[i] == JAM_STRING_MAGIC );
35         assert( self->value[self->capacity + i] == JAM_STRING_MAGIC );
36     }
37 }
38 #else
39 # define JAM_STRING_MAGIC_SIZE 0
40 # define assert_invariants(x) do {} while (0)
41 #endif
42
43 void string_new( string* s )
44 {
45     s->value = s->opt;
46     s->size = 0;
47     s->capacity = sizeof(s->opt);
48     s->opt[0] = 0;
49 #ifndef NDEBUG
50     memset(s->magic, JAM_STRING_MAGIC, sizeof(s->magic));
51 #endif
52     assert_invariants( s );
53 }
54
55 void string_free( string* s )
56 {
57     assert_invariants( s );
58     if ( s->value != s->opt )
59         BJAM_FREE( s->value );
60     string_new( s );
61 }
62
63 static void string_reserve_internal( string* self, size_t capacity )
64 {
65     if ( self->value == self->opt )
66     {
67         self->value = (char*)BJAM_MALLOC_ATOMIC( capacity + JAM_STRING_MAGIC_SIZE );
68         self->value[0] = 0;
69         strncat( self->value, self->opt, sizeof(self->opt) );
70         assert( strlen( self->value ) <= self->capacity ); /* This is a regression test */
71     }
72     else
73     {
74         self->value = (char*)BJAM_REALLOC( self->value, capacity + JAM_STRING_MAGIC_SIZE );
75     }
76 #ifndef NDEBUG
77     memcpy( self->value + capacity, self->magic, JAM_STRING_MAGIC_SIZE );
78 #endif
79     self->capacity = capacity;
80 }
81
82 void string_reserve( string* self, size_t capacity )
83 {
84     assert_invariants( self );
85     if ( capacity <= self->capacity )
86         return;
87     string_reserve_internal( self, capacity );
88     assert_invariants( self );
89 }
90
91 static void extend_full( string* self, char const* start, char const* finish )
92 {
93     size_t new_size = self->capacity + ( finish - start );
94     size_t new_capacity = self->capacity;
95     size_t old_size = self->capacity;
96     while ( new_capacity < new_size + 1)
97         new_capacity <<= 1;
98     string_reserve_internal( self, new_capacity );
99     memcpy( self->value + old_size, start, new_size - old_size );
100     self->value[new_size] = 0;
101     self->size = new_size;
102 }
103
104 void string_append( string* self, char const* rhs )
105 {
106     char* p = self->value + self->size;
107     char* end = self->value + self->capacity;
108     assert_invariants( self );
109
110     while ( *rhs && p != end)
111         *p++ = *rhs++;
112
113     if ( p != end )
114     {
115         *p = 0;
116         self->size = p - self->value;
117     }
118     else
119     {
120         extend_full( self, rhs, rhs + strlen(rhs) );
121     }
122     assert_invariants( self );
123 }
124
125 void string_append_range( string* self, char const* start, char const* finish )
126 {
127     char* p = self->value + self->size;
128     char* end = self->value + self->capacity;
129     assert_invariants( self );
130
131     while ( p != end && start != finish )
132         *p++ = *start++;
133
134     if ( p != end )
135     {
136         *p = 0;
137         self->size = p - self->value;
138     }
139     else
140     {
141         extend_full( self, start, finish );
142     }
143     assert_invariants( self );
144 }
145
146 void string_copy( string* s, char const* rhs )
147 {
148     string_new( s );
149     string_append( s, rhs );
150 }
151
152 void string_truncate( string* self, size_t n )
153 {
154     assert_invariants( self );
155     assert( n <= self->capacity );
156     self->value[self->size = n] = 0;
157     assert_invariants( self );
158 }
159
160 void string_pop_back( string* self )
161 {
162     string_truncate( self, self->size - 1 );
163 }
164
165 void string_push_back( string* self, char x )
166 {
167     string_append_range( self, &x, &x + 1 );
168 }
169
170 char string_back( string* self )
171 {
172     assert_invariants( self );
173     return self->value[self->size - 1];
174 }
175
176 #ifndef NDEBUG
177 void string_unit_test()
178 {
179     string s[1];
180     int i;
181     char buffer[sizeof(s->opt) * 2 + 2];
182     int limit = sizeof(buffer) > 254 ? 254 : sizeof(buffer);
183
184     string_new(s);
185
186     for (i = 0; i < limit; ++i)
187     {
188         string_push_back( s, (char)(i + 1) );
189     };
190
191     for (i = 0; i < limit; ++i)
192     {
193         assert( i < s->size );
194         assert( s->value[i] == (char)(i + 1));
195     }
196
197     string_free(s);
198
199 }
200 #endif
201