Commit | Line | Data |
---|---|---|
970ed795 | 1 | /////////////////////////////////////////////////////////////////////////////// |
3abe9331 | 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
970ed795 EL |
3 | // All rights reserved. This program and the accompanying materials |
4 | // are made available under the terms of the Eclipse Public License v1.0 | |
5 | // which accompanies this distribution, and is available at | |
6 | // http://www.eclipse.org/legal/epl-v10.html | |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | #include <stdio.h> | |
9 | #include <string.h> | |
10 | #include <stddef.h> | |
11 | #include <ctype.h> | |
12 | ||
13 | #include "../common/memory.h" | |
14 | #include "error.h" | |
15 | ||
16 | #include "string.hh" | |
17 | #include "ustring.hh" | |
18 | ||
19 | #include "Int.hh" | |
20 | ||
21 | /** Parameters for tuning memory usage of class stringpool */ | |
22 | #define STRINGPOOL_INITIAL_SIZE 8 | |
23 | #define STRINGPOOL_INCREMENT_FACTOR 2 | |
24 | ||
25 | /** The amount of memory needed for a string containing n characters. */ | |
26 | #define MEMORY_SIZE(n) (sizeof(string_struct) - sizeof(size_t) + 1 + (n)) | |
27 | ||
28 | void string::init_struct(size_t n_chars) | |
29 | { | |
30 | if (n_chars == 0) { | |
31 | /** This will represent the empty strings so they won't need allocated | |
32 | * memory, this delays the memory allocation until it is really needed. */ | |
33 | static string_struct empty_string = { 1, 0, "" }; | |
34 | val_ptr = &empty_string; | |
35 | empty_string.ref_count++; | |
36 | } else { | |
37 | val_ptr = static_cast<string_struct*>(Malloc(MEMORY_SIZE(n_chars))); | |
38 | val_ptr->ref_count = 1; | |
39 | val_ptr->n_chars = n_chars; | |
40 | val_ptr->chars_ptr[n_chars] = '\0'; | |
41 | } | |
42 | } | |
43 | ||
44 | void string::copy_value_and_append(const char *s, size_t n) | |
45 | { | |
46 | if (n > max_string_len - val_ptr->n_chars) | |
47 | FATAL_ERROR("string::copy_value_and_append(const char*, size_t): " \ | |
48 | "length overflow"); | |
49 | if (val_ptr->ref_count == 1) { | |
50 | ptrdiff_t offset = s - val_ptr->chars_ptr; | |
51 | val_ptr = static_cast<string_struct*> | |
52 | (Realloc(val_ptr, MEMORY_SIZE(val_ptr->n_chars + n))); | |
53 | // check whether the source buffer s is (part of) our existing buffer | |
54 | if (offset >= 0 && static_cast<size_t>(offset) < val_ptr->n_chars) | |
55 | memcpy(val_ptr->chars_ptr + val_ptr->n_chars, | |
56 | val_ptr->chars_ptr + offset, n); | |
57 | else memcpy(val_ptr->chars_ptr + val_ptr->n_chars, s, n); | |
58 | val_ptr->n_chars += n; | |
59 | val_ptr->chars_ptr[val_ptr->n_chars] = '\0'; | |
60 | } else { | |
61 | string_struct *old_ptr = val_ptr; | |
62 | old_ptr->ref_count--; | |
63 | init_struct(old_ptr->n_chars + n); | |
64 | memcpy(val_ptr->chars_ptr, old_ptr->chars_ptr, old_ptr->n_chars); | |
65 | memcpy(val_ptr->chars_ptr + old_ptr->n_chars, s, n); | |
66 | } | |
67 | } | |
68 | ||
69 | /** Internal worker for various replace() methods. | |
70 | * | |
71 | * @param pos the index of the first character to replace | |
72 | * @param n the number of characters to replace | |
73 | * @param s the replacement | |
74 | * @param s_len the length of the replacement | |
75 | * | |
76 | * @pre \p pos must point inside the string | |
77 | * @pre \p pos + \p n must point inside the string | |
78 | * @pre the resulting string must not exceed max_string_len | |
79 | */ | |
80 | void string::replace(size_t pos, size_t n, const char *s, size_t s_len) | |
81 | { | |
82 | if (pos > val_ptr->n_chars) | |
83 | FATAL_ERROR("string::replace(): start position is outside the string"); | |
84 | if (pos + n > val_ptr->n_chars) | |
85 | FATAL_ERROR("string::replace(): end position is outside the string"); | |
86 | if (s_len > max_string_len - val_ptr->n_chars + n) | |
87 | FATAL_ERROR("string::replace(): length overflow"); | |
88 | // do nothing if we are replacing with the same string | |
89 | if (n == s_len && memcmp(val_ptr->chars_ptr + pos, s, n) == 0) return; | |
90 | size_t new_size = val_ptr->n_chars - n + s_len; | |
91 | if (new_size == 0) { | |
92 | // the result is an empty string | |
93 | clean_up(val_ptr); | |
94 | init_struct(0); | |
95 | } else if (val_ptr->ref_count == 1 && (s < val_ptr->chars_ptr || | |
96 | s >= val_ptr->chars_ptr + val_ptr->n_chars)) { | |
97 | // check whether this string is not referenced by others and we are not | |
98 | // replacing with ourselves | |
99 | if (val_ptr->n_chars < new_size) val_ptr = static_cast<string_struct*> | |
100 | (Realloc(val_ptr, MEMORY_SIZE(new_size))); | |
101 | memmove(val_ptr->chars_ptr + pos + s_len, | |
102 | val_ptr->chars_ptr + pos + n, val_ptr->n_chars - pos - n); | |
103 | memcpy(val_ptr->chars_ptr + pos, s, s_len); | |
104 | if (val_ptr->n_chars > new_size) val_ptr = static_cast<string_struct*> | |
105 | (Realloc(val_ptr, MEMORY_SIZE(new_size))); | |
106 | val_ptr->n_chars = new_size; | |
107 | val_ptr->chars_ptr[new_size] = '\0'; | |
108 | } else { | |
109 | // the result must be copied into a new memory area | |
110 | string_struct *old_ptr = val_ptr; | |
111 | old_ptr->ref_count--; | |
112 | init_struct(new_size); | |
113 | memcpy(val_ptr->chars_ptr, old_ptr->chars_ptr, pos); | |
114 | memcpy(val_ptr->chars_ptr + pos, s, s_len); | |
115 | memcpy(val_ptr->chars_ptr + pos + s_len, old_ptr->chars_ptr + pos + n, | |
116 | old_ptr->n_chars - pos - n); | |
117 | if (old_ptr->ref_count == 0) Free(old_ptr); | |
118 | } | |
119 | } | |
120 | ||
121 | void string::clean_up(string_struct *ptr) | |
122 | { | |
123 | if (ptr->ref_count > 1) ptr->ref_count--; | |
124 | else if (ptr->ref_count == 1) Free(ptr); | |
125 | else FATAL_ERROR("string::clean_up()"); | |
126 | } | |
127 | ||
128 | int string::compare(const string& s) const | |
129 | { | |
130 | if (val_ptr == s.val_ptr) return 0; | |
131 | else return strcmp(val_ptr->chars_ptr, s.val_ptr->chars_ptr); | |
132 | } | |
133 | ||
134 | int string::compare(const char *s) const | |
135 | { | |
136 | if (val_ptr->chars_ptr == s) return 0; | |
137 | else return strcmp(val_ptr->chars_ptr, s); | |
138 | } | |
139 | ||
140 | string::string(const char *s) | |
141 | { | |
142 | if (s == NULL) FATAL_ERROR("string::string(const char*): called with NULL"); | |
143 | size_t n_chars = strlen(s); | |
144 | init_struct(n_chars); | |
145 | memcpy(val_ptr->chars_ptr, s, n_chars); | |
146 | } | |
147 | ||
148 | string::string(size_t n, const char *s) | |
149 | { | |
150 | if (s == NULL && n > 0) | |
151 | FATAL_ERROR("string::string(size_t, const char*): called with NULL"); | |
152 | init_struct(n); | |
153 | memcpy(val_ptr->chars_ptr, s, n); | |
154 | } | |
155 | ||
156 | string::string(const ustring& s) | |
157 | { | |
158 | size_t s_len = s.size(); | |
159 | init_struct(s_len); | |
160 | const ustring::universal_char *src = s.u_str(); | |
161 | for (size_t i = 0; i < s_len; i++) { | |
162 | if (src[i].group != 0 || src[i].plane != 0 || src[i].row != 0) | |
163 | FATAL_ERROR("string::string(const ustring&)"); | |
164 | val_ptr->chars_ptr[i] = src[i].cell; | |
165 | } | |
166 | } | |
167 | ||
168 | bool string::is_cstr() const | |
169 | { | |
170 | for (size_t i = 0; i < val_ptr->n_chars; i++) | |
171 | if ((unsigned char)val_ptr->chars_ptr[i] > 127) return false; | |
172 | return true; | |
173 | } | |
174 | ||
175 | void string::clear() | |
176 | { | |
177 | if (val_ptr->n_chars > 0) { | |
178 | clean_up(val_ptr); | |
179 | init_struct(0); | |
180 | } | |
181 | } | |
182 | ||
183 | string string::substr(size_t pos, size_t n) const | |
184 | { | |
185 | if (pos > val_ptr->n_chars) | |
186 | FATAL_ERROR("string::substr(size_t, size_t): position is outside the " \ | |
187 | "string"); | |
188 | size_t n_chars = val_ptr->n_chars - pos; | |
189 | if (n_chars > n) n_chars = n; | |
190 | if (n_chars == val_ptr->n_chars) return *this; | |
191 | else return string(n_chars, val_ptr->chars_ptr + pos); | |
192 | } | |
193 | ||
194 | void string::resize(size_t n, char c) | |
195 | { | |
196 | size_t old_length = val_ptr->n_chars; | |
197 | if (old_length == n) return; | |
198 | if (val_ptr->ref_count == 1) { | |
199 | if (n > 0) { | |
200 | val_ptr = static_cast<string_struct*>(Realloc(val_ptr, MEMORY_SIZE(n))); | |
201 | if (n > old_length) { | |
202 | memset(val_ptr->chars_ptr + old_length, c, n - old_length); | |
203 | } | |
204 | val_ptr->chars_ptr[n] = '\0'; | |
205 | val_ptr->n_chars = n; | |
206 | } else { | |
207 | clean_up(val_ptr); | |
208 | init_struct(0); | |
209 | } | |
210 | } else { | |
211 | val_ptr->ref_count--; | |
212 | string_struct *tmp_ptr = val_ptr; | |
213 | init_struct(n); | |
214 | if (n > old_length) { | |
215 | memcpy(val_ptr->chars_ptr, tmp_ptr->chars_ptr, old_length); | |
216 | memset(val_ptr->chars_ptr + old_length, c, n - old_length); | |
217 | } else { | |
218 | memcpy(val_ptr->chars_ptr, tmp_ptr->chars_ptr, n); | |
219 | } | |
220 | } | |
221 | } | |
222 | ||
223 | void string::replace(size_t pos, size_t n, const char *s) | |
224 | { | |
225 | if (s == NULL) FATAL_ERROR("string::replace(size_t, size_t, const char*): " \ | |
226 | "called with NULL"); | |
227 | replace(pos, n, s, strlen(s)); | |
228 | } | |
229 | ||
230 | void string::replace(size_t pos, size_t n, const string& s) | |
231 | { | |
232 | if (pos == 0 && n == val_ptr->n_chars) *this = s; | |
233 | else replace(pos, n, s.val_ptr->chars_ptr, s.val_ptr->n_chars); | |
234 | } | |
235 | ||
236 | size_t string::find(char c, size_t pos) const | |
237 | { | |
238 | if (pos > val_ptr->n_chars) | |
239 | FATAL_ERROR("string::find(char, size_t): position is outside of string"); | |
240 | for (size_t r = pos; r < val_ptr->n_chars; r++) | |
241 | if (c == val_ptr->chars_ptr[r]) return r; | |
242 | return val_ptr->n_chars; | |
243 | } | |
244 | ||
245 | size_t string::find(const char *s, size_t pos) const | |
246 | { | |
247 | if (s == NULL) | |
248 | FATAL_ERROR("string::find(const char *, size_t): called with NULL"); | |
249 | if (pos >= val_ptr->n_chars) | |
250 | FATAL_ERROR("string::find(const char *, size_t): position outside of string"); | |
251 | const char *ptr = strstr(val_ptr->chars_ptr + pos, s); | |
252 | if (ptr != NULL) return ptr - val_ptr->chars_ptr; | |
253 | else return val_ptr->n_chars; | |
254 | } | |
255 | ||
256 | size_t string::rfind(char c, size_t pos) const | |
257 | { | |
258 | if (pos > val_ptr->n_chars) pos = val_ptr->n_chars; | |
259 | for (size_t i = pos; i > 0; i--) | |
260 | if (c == val_ptr->chars_ptr[i - 1]) return i - 1; | |
261 | return val_ptr->n_chars; | |
262 | } | |
263 | ||
264 | size_t string::find_if(size_t first, size_t last, int (*pred)(int)) const | |
265 | { | |
266 | if (first > last) FATAL_ERROR("string::find_if(): first greater than last"); | |
267 | else if (last > val_ptr->n_chars) | |
268 | FATAL_ERROR("string::find_if(): last greater than string length"); | |
269 | for (size_t r = first; r < last; r++) | |
270 | if (pred(val_ptr->chars_ptr[r])) return r; | |
271 | return last; | |
272 | } | |
273 | ||
274 | bool string::is_whitespace(unsigned char c) | |
275 | { | |
276 | switch (c) { | |
277 | case ' ': | |
278 | case '\t': | |
279 | case '\n': | |
280 | case '\r': | |
281 | case '\v': | |
282 | case '\f': | |
283 | return true; | |
284 | default: | |
285 | return false; | |
286 | } | |
287 | } | |
288 | ||
289 | bool string::is_printable(unsigned char c) | |
290 | { | |
291 | if (isprint(c)) return true; | |
292 | else { | |
293 | switch (c) { | |
294 | case '\a': | |
295 | case '\b': | |
296 | case '\t': | |
297 | case '\n': | |
298 | case '\v': | |
299 | case '\f': | |
300 | case '\r': | |
301 | return true; | |
302 | default: | |
303 | return false; | |
304 | } | |
305 | } | |
306 | } | |
307 | ||
308 | void string::append_stringRepr(char c) | |
309 | { | |
310 | switch (c) { | |
311 | case '\a': | |
312 | *this += "\\a"; | |
313 | break; | |
314 | case '\b': | |
315 | *this += "\\b"; | |
316 | break; | |
317 | case '\t': | |
318 | *this += "\\t"; | |
319 | break; | |
320 | case '\n': | |
321 | *this += "\\n"; | |
322 | break; | |
323 | case '\v': | |
324 | *this += "\\v"; | |
325 | break; | |
326 | case '\f': | |
327 | *this += "\\f"; | |
328 | break; | |
329 | case '\r': | |
330 | *this += "\\r"; | |
331 | break; | |
332 | case '\\': | |
333 | *this += "\\\\"; | |
334 | break; | |
335 | case '"': | |
336 | *this += "\\\""; | |
337 | break; | |
338 | default: | |
339 | if (is_printable(c)) *this += c; | |
340 | else FATAL_ERROR("string::append_stringRepr()"); | |
341 | break; | |
342 | } | |
343 | } | |
344 | ||
345 | string string::get_stringRepr() const | |
346 | { | |
347 | string ret_val; | |
348 | enum { INIT, PCHAR, NPCHAR } state = INIT; | |
349 | for (size_t i = 0; i < val_ptr->n_chars; i++) { | |
350 | char c = val_ptr->chars_ptr[i]; | |
351 | if (is_printable(c)) { | |
352 | // the actual character is printable | |
353 | switch (state) { | |
354 | case NPCHAR: // concatenation sign if previous part was not printable | |
355 | ret_val += " & "; | |
356 | // no break | |
357 | case INIT: // opening " | |
358 | ret_val += '"'; | |
359 | // no break | |
360 | case PCHAR: // the character itself | |
361 | ret_val.append_stringRepr(c); | |
362 | break; | |
363 | } | |
364 | state = PCHAR; | |
365 | } else { | |
366 | // the actual character is not printable | |
367 | switch (state) { | |
368 | case PCHAR: // closing " if previous part was printable | |
369 | ret_val += '"'; | |
370 | // no break | |
371 | case NPCHAR: // concatenation sign | |
372 | ret_val += " & "; | |
373 | // no break | |
374 | case INIT: // the character itself in quadruple notation | |
375 | ret_val += "char(0, 0, 0, "; | |
376 | ret_val += Common::Int2string((unsigned char)c); | |
377 | ret_val += ')'; | |
378 | break; | |
379 | } | |
380 | state = NPCHAR; | |
381 | } | |
382 | } | |
383 | // final steps | |
384 | switch (state) { | |
385 | case INIT: // the string was empty | |
386 | ret_val += "\"\""; | |
387 | break; | |
388 | case PCHAR: // last character was printable -> closing " | |
389 | ret_val += '"'; | |
390 | break; | |
391 | default: | |
392 | break; | |
393 | } | |
394 | return ret_val; | |
395 | } | |
396 | ||
397 | ustring string::convert_stringRepr_for_pattern() const { | |
398 | ustring ret_val; | |
399 | ||
400 | if (val_ptr->n_chars % 8 != 0) | |
401 | FATAL_ERROR("string::convert_stringRepr_for_pattern(): Cannot create" | |
402 | "universal string. Length must be a multiple of 8."); | |
403 | ||
404 | unsigned char c1, c2; | |
405 | unsigned char array[4]; | |
406 | size_t index = 0; | |
407 | while (index < val_ptr->n_chars) { | |
408 | for (size_t j = 0; j < 4; j++) { | |
409 | c1 = (unsigned char)val_ptr->chars_ptr[index++]; | |
410 | c2 = (unsigned char)val_ptr->chars_ptr[index++]; | |
411 | if (c1 >= 'A' && c1 <= 'P' && c2 >= 'A' && c2 <= 'P') { | |
412 | array[j] = ((c1 - 'A') << 4) | (c2 - 'A'); | |
413 | } else | |
414 | FATAL_ERROR("string::convert_stringRepr_for_pattern(): Cannot create" | |
415 | "universal string. Source contains illegal character."); | |
416 | } | |
417 | ret_val += ustring(array[0], array[1], array[2], array[3]); | |
418 | } | |
419 | return ret_val; | |
420 | } | |
421 | ||
422 | string& string::operator=(const string& s) | |
423 | { | |
424 | if (&s != this) { | |
425 | clean_up(val_ptr); | |
426 | val_ptr = s.val_ptr; | |
427 | val_ptr->ref_count++; | |
428 | } | |
429 | return *this; | |
430 | } | |
431 | ||
432 | string& string::operator=(const char *s) | |
433 | { | |
434 | if (s == NULL) | |
435 | FATAL_ERROR("string::operator=(const char*): called with NULL"); | |
436 | if (val_ptr->chars_ptr != s) { | |
437 | clean_up(val_ptr); | |
438 | size_t n_chars = strlen(s); | |
439 | init_struct(n_chars); | |
440 | memcpy(val_ptr->chars_ptr, s, n_chars); | |
441 | } | |
442 | return *this; | |
443 | } | |
444 | ||
445 | char& string::operator[](size_t n) | |
446 | { | |
447 | if (n >= val_ptr->n_chars) | |
448 | FATAL_ERROR("string::operator[](size_t): position is outside the string"); | |
449 | if (val_ptr->ref_count > 1) { | |
450 | string_struct *old_ptr = val_ptr; | |
451 | old_ptr->ref_count--; | |
452 | init_struct(old_ptr->n_chars); | |
453 | memcpy(val_ptr->chars_ptr, old_ptr->chars_ptr, old_ptr->n_chars); | |
454 | } | |
455 | return val_ptr->chars_ptr[n]; | |
456 | } | |
457 | ||
458 | char string::operator[](size_t n) const | |
459 | { | |
460 | if (n >= val_ptr->n_chars) | |
461 | FATAL_ERROR("string::operator[](size_t) const: position is outside the string"); | |
462 | return val_ptr->chars_ptr[n]; | |
463 | } | |
464 | ||
465 | string string::operator+(const string& s) const | |
466 | { | |
467 | if (s.val_ptr->n_chars > max_string_len - val_ptr->n_chars) | |
468 | FATAL_ERROR("string::operator+(const string&): length overflow"); | |
469 | if (val_ptr->n_chars == 0) return s; | |
470 | else if (s.val_ptr->n_chars == 0) return *this; | |
471 | else { | |
472 | string ret_val(val_ptr->n_chars + s.val_ptr->n_chars); | |
473 | memcpy(ret_val.val_ptr->chars_ptr, val_ptr->chars_ptr, val_ptr->n_chars); | |
474 | memcpy(ret_val.val_ptr->chars_ptr + val_ptr->n_chars, | |
475 | s.val_ptr->chars_ptr, s.val_ptr->n_chars); | |
476 | return ret_val; | |
477 | } | |
478 | } | |
479 | ||
480 | string string::operator+(const char *s) const | |
481 | { | |
482 | if (s == NULL) | |
483 | FATAL_ERROR("string::operator+(const char*): called with NULL)"); | |
484 | size_t s_len = strlen(s); | |
485 | if (s_len > max_string_len - val_ptr->n_chars) | |
486 | FATAL_ERROR("string::operator+(const char*): length overflow"); | |
487 | if (s_len == 0) return *this; | |
488 | else { | |
489 | string ret_val(val_ptr->n_chars + s_len); | |
490 | memcpy(ret_val.val_ptr->chars_ptr, val_ptr->chars_ptr, val_ptr->n_chars); | |
491 | memcpy(ret_val.val_ptr->chars_ptr + val_ptr->n_chars, s, s_len); | |
492 | return ret_val; | |
493 | } | |
494 | } | |
495 | ||
496 | string& string::operator+=(const string& s) | |
497 | { | |
498 | if (s.val_ptr->n_chars > 0) { | |
499 | if (val_ptr->n_chars > 0) { | |
500 | copy_value_and_append(s.val_ptr->chars_ptr, s.val_ptr->n_chars); | |
501 | } else { | |
502 | clean_up(val_ptr); | |
503 | val_ptr = s.val_ptr; | |
504 | val_ptr->ref_count++; | |
505 | } | |
506 | } | |
507 | return *this; | |
508 | } | |
509 | ||
510 | string& string::operator+=(const char *s) | |
511 | { | |
512 | if (s == NULL) | |
513 | FATAL_ERROR("string::operator+=(const char*): called with NULL"); | |
514 | size_t s_len = strlen(s); | |
515 | if (s_len > 0) copy_value_and_append(s, s_len); | |
516 | return *this; | |
517 | } | |
518 | ||
519 | bool string::operator==(const string& s) const | |
520 | { | |
521 | if (val_ptr == s.val_ptr) return true; | |
522 | else if (val_ptr->n_chars != s.val_ptr->n_chars) return false; | |
523 | else return memcmp(val_ptr->chars_ptr, s.val_ptr->chars_ptr, | |
524 | val_ptr->n_chars) == 0; | |
525 | } | |
526 | ||
527 | bool string::operator==(const char *s) const | |
528 | { | |
529 | if (s == NULL) | |
530 | FATAL_ERROR("string::operator==(const char*): called with NULL"); | |
531 | if (s == val_ptr->chars_ptr) return true; | |
532 | else return strcmp(val_ptr->chars_ptr, s) == 0; | |
533 | } | |
534 | ||
535 | string operator+(const char *s1, const string& s2) | |
536 | { | |
537 | if (s1 == NULL) | |
538 | FATAL_ERROR("operator+(const char *, const string&): called with NULL"); | |
539 | size_t s1_len = strlen(s1); | |
540 | if (s1_len > string::max_string_len - s2.val_ptr->n_chars) | |
541 | FATAL_ERROR("operator+(const char *,const string&): length overflow"); | |
542 | if (s1_len > 0) { | |
543 | string s(s1_len + s2.val_ptr->n_chars); | |
544 | memcpy(s.val_ptr->chars_ptr, s1, s1_len); | |
545 | memcpy(s.val_ptr->chars_ptr + s1_len, s2.val_ptr->chars_ptr, | |
546 | s2.val_ptr->n_chars); | |
547 | return s; | |
548 | } else return s2; | |
549 | } | |
550 | ||
551 | void stringpool::clear() | |
552 | { | |
553 | for (size_t i = 0; i < list_len; i++) string::clean_up(string_list[i]); | |
554 | Free(string_list); | |
555 | string_list = NULL; | |
556 | list_size = 0; | |
557 | list_len = 0; | |
558 | } | |
559 | ||
560 | const char *stringpool::add(const string& s) | |
561 | { | |
562 | if (list_len > list_size) FATAL_ERROR("stringpool::add()"); | |
563 | else if (list_len == list_size) { | |
564 | if (list_size == 0) { | |
565 | string_list = static_cast<string::string_struct**> | |
566 | (Malloc(STRINGPOOL_INITIAL_SIZE * sizeof(*string_list))); | |
567 | list_size = STRINGPOOL_INITIAL_SIZE; | |
568 | } else { | |
569 | list_size *= STRINGPOOL_INCREMENT_FACTOR; | |
570 | string_list = static_cast<string::string_struct**> | |
571 | (Realloc(string_list, list_size * sizeof(*string_list))); | |
572 | } | |
573 | if (list_len >= list_size) FATAL_ERROR("stringpool::add()"); | |
574 | } | |
575 | string::string_struct *val_ptr = s.val_ptr; | |
576 | string_list[list_len++] = val_ptr; | |
577 | val_ptr->ref_count++; | |
578 | return val_ptr->chars_ptr; | |
579 | } | |
580 | ||
581 | const char *stringpool::get_str(size_t n) const | |
582 | { | |
583 | if (n >= list_len) FATAL_ERROR("stringpool::get_str()"); | |
584 | return string_list[n]->chars_ptr; | |
585 | } | |
586 | ||
587 | string stringpool::get_string(size_t n) const | |
588 | { | |
589 | if (n >= list_len) FATAL_ERROR("stringpool::get_string()"); | |
590 | return string(string_list[n]); | |
591 | } |