added JAM_FORCE_GCC_OPTIONS variable
[k8jam.git] / kstrings.c
blob52800c8e12c85eaec76314612e949f18e3b50851
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 #include <stdlib.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <stdio.h>
8 #include "jam.h"
10 #include "kstrings.h"
13 #ifndef NDEBUG
14 # define JAM_STRING_MAGIC ((char)0xcf)
15 # define JAM_STRING_MAGIC_SIZE 4
16 static void AssertInvariants (tKString *self) {
17 int i;
19 if (self->value == 0) {
20 assert(self->size == 0);
21 assert(self->capacity == 0);
22 assert(self->opt[0] == 0);
23 return;
26 assert(self->size < self->capacity);
27 assert((self->capacity <= sizeof(self->opt)) == (self->value == self->opt));
28 assert(strlen(self->value) == self->size);
30 for (i = 0; i < 4; ++i) {
31 assert(self->magic[i] == JAM_STRING_MAGIC);
32 assert(self->value[self->capacity+i] == JAM_STRING_MAGIC);
35 #else
36 # define JAM_STRING_MAGIC_SIZE 0
37 # define AssertInvariants(x) do {} while (0)
38 #endif
41 void kStringNew (tKString *s) {
42 s->value = s->opt;
43 s->size = 0;
44 s->capacity = sizeof(s->opt);
45 s->opt[0] = 0;
46 #ifndef NDEBUG
47 memset(s->magic, JAM_STRING_MAGIC, sizeof(s->magic));
48 #endif
49 AssertInvariants(s);
53 void kStringFree (tKString *s) {
54 AssertInvariants(s);
55 if (s->value != s->opt) free(s->value);
56 kStringNew(s);
60 static void kStringReserveInternal (tKString *self, size_t capacity) {
61 if (self->value == self->opt) {
62 self->value = (char *)malloc(capacity+JAM_STRING_MAGIC_SIZE);
63 assert(self->value);
64 self->value[0] = 0;
65 strncat(self->value, self->opt, sizeof(self->opt));
66 assert(strlen(self->value) <= self->capacity); /* This is a regression test */
67 } else {
68 self->value = (char *)realloc(self->value, capacity+JAM_STRING_MAGIC_SIZE);
69 assert(self->value);
71 #ifndef NDEBUG
72 memcpy(self->value+capacity, self->magic, JAM_STRING_MAGIC_SIZE);
73 #endif
74 self->capacity = capacity;
78 void kStringReserve (tKString *self, size_t capacity) {
79 AssertInvariants(self);
80 if (capacity <= self->capacity) return;
81 kStringReserveInternal(self, capacity);
82 AssertInvariants(self);
86 static void kStringExtendFull (tKString *self, char const *start, char const *finish) {
87 size_t new_size = self->capacity+(finish-start);
88 size_t new_capacity = self->capacity;
89 size_t old_size = self->capacity;
90 while (new_capacity < new_size+1) new_capacity <<= 1;
91 kStringReserveInternal(self, new_capacity);
92 memcpy(self->value+old_size, start, new_size-old_size);
93 self->value[new_size] = 0;
94 self->size = new_size;
98 void kStringAppend (tKString *self, char const *rhs) {
99 char *p = self->value+self->size;
100 char *end = self->value+self->capacity;
101 AssertInvariants(self);
103 while (*rhs && p != end) *p++ = *rhs++;
104 if (p != end) {
105 *p = 0;
106 self->size = p-self->value;
107 } else kStringExtendFull(self, rhs, rhs+strlen(rhs));
108 AssertInvariants(self);
112 void kStringAppendRange (tKString *self, char const *start, char const *finish) {
113 char *p = self->value+self->size;
114 char *end = self->value+self->capacity;
115 AssertInvariants(self);
117 while (p != end && start != finish) *p++ = *start++;
118 if (p != end) {
119 *p = 0;
120 self->size = p-self->value;
121 } else kStringExtendFull(self, start, finish);
122 AssertInvariants(self);
126 void kStringCopy (tKString *s, char const *rhs) {
127 kStringNew(s);
128 kStringAppend(s, rhs);
132 void kStringTruncate (tKString *self, size_t n) {
133 AssertInvariants(self);
134 assert(n <= self->capacity);
135 self->value[self->size = n] = 0;
136 AssertInvariants(self);
140 void kStringPopBack (tKString *self) {
141 kStringTruncate(self, self->size-1);
145 void kStringPushBack (tKString *self, char x) {
146 kStringAppendRange(self, &x, &x+1);
150 char kStringBack (tKString *self) {
151 AssertInvariants(self);
152 return self->value[self->size-1];
156 #ifndef NDEBUG
157 void kStringUnitTest (void) {
158 tKString s[1];
159 int i;
160 char buffer[sizeof(s->opt)*2+2];
161 int limit = sizeof(buffer)>254?254:sizeof(buffer);
163 kStringNew(s);
164 for (i = 0; i < limit; ++i) {
165 kStringPushBack(s, (char)(i+1));
168 for (i = 0; i < limit; ++i) {
169 assert(i < s->size);
170 assert(s->value[i] == (char)(i+1));
173 kStringFree(s);
175 #endif