1 /********************************************************************/
2 /* */
3 /* bst_rtl.c Primitive actions for the byte string type. */
4 /* Copyright (C) 1989 - 2018 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/bst_rtl.c */
27 /* Changes: 2007, 2010, 2011, 2013 - 2016, 2018 Thomas Mertes */
28 /* Content: Primitive actions for the byte string type. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40
41 #include "common.h"
42 #include "data_rtl.h"
43 #include "heaputl.h"
44 #include "striutl.h"
45 #include "rtl_err.h"
46
47 #undef EXTERN
48 #define EXTERN
49 #include "bst_rtl.h"
50
51
52
53 /**
54 * Append the bstring 'extension' to 'destination'.
55 * @exception MEMORY_ERROR Not enough memory for the concatenated
56 * bstring.
57 */
bstAppend(bstriType * const destination,const_bstriType extension)58 void bstAppend (bstriType *const destination, const_bstriType extension)
59
60 {
61 memSizeType new_size;
62 bstriType bstri_dest;
63 bstriType new_bstri;
64
65 /* bstAppend */
66 bstri_dest = *destination;
67 if (unlikely(bstri_dest->size > MAX_BSTRI_LEN - extension->size)) {
68 /* number of bytes does not fit into memSizeType */
69 raise_error(MEMORY_ERROR);
70 } else {
71 new_size = bstri_dest->size + extension->size;
72 REALLOC_BSTRI_SIZE_OK(new_bstri, bstri_dest, bstri_dest->size, new_size);
73 if (unlikely(new_bstri == NULL)) {
74 raise_error(MEMORY_ERROR);
75 } else {
76 if (bstri_dest == extension) {
77 /* It is possible that bstri_dest == extension holds. */
78 /* In this case 'extension' must be corrected */
79 /* after realloc() enlarged 'bstri_dest'. */
80 extension = new_bstri;
81 } /* if */
82 COUNT3_BSTRI(new_bstri->size, new_size);
83 memcpy(&new_bstri->mem[new_bstri->size], extension->mem,
84 (size_t) extension->size);
85 new_bstri->size = new_size;
86 *destination = new_bstri ;
87 } /* if */
88 } /* if */
89 } /* bstAppend */
90
91
92
93 /**
94 * Concatenate two bstrings.
95 * @return the result of the concatenation.
96 * @exception MEMORY_ERROR Not enough memory for the concatenated
97 * bstring.
98 */
bstCat(const const_bstriType bstri1,const const_bstriType bstri2)99 bstriType bstCat (const const_bstriType bstri1, const const_bstriType bstri2)
100
101 {
102 memSizeType result_size;
103 bstriType result;
104
105 /* bstCat */
106 if (unlikely(bstri1->size > MAX_BSTRI_LEN - bstri2->size)) {
107 /* number of bytes does not fit into memSizeType */
108 raise_error(MEMORY_ERROR);
109 result = NULL;
110 } else {
111 result_size = bstri1->size + bstri2->size;
112 if (unlikely(!ALLOC_BSTRI_SIZE_OK(result, result_size))) {
113 raise_error(MEMORY_ERROR);
114 } else {
115 result->size = result_size;
116 memcpy(result->mem, bstri1->mem, bstri1->size);
117 memcpy(&result->mem[bstri1->size], bstri2->mem, bstri2->size);
118 } /* if */
119 } /* if */
120 return result;
121 } /* bstCat */
122
123
124
125 /**
126 * Compare two bstrings.
127 * @return -1, 0 or 1 if the first argument is considered to be
128 * respectively less than, equal to, or greater than the
129 * second.
130 */
bstCmp(const const_bstriType bstri1,const const_bstriType bstri2)131 intType bstCmp (const const_bstriType bstri1, const const_bstriType bstri2)
132
133 {
134 intType signumValue;
135
136 /* bstCmp */
137 #if MEMCMP_RETURNS_SIGNUM
138 if (bstri1->size < bstri2->size) {
139 signumValue = memcmp(bstri1->mem, bstri2->mem, bstri1->size);
140 if (signumValue == 0) {
141 signumValue = -1;
142 } /* if */
143 } else {
144 signumValue = memcmp(bstri1->mem, bstri2->mem, bstri2->size);
145 if (signumValue == 0 && bstri1->size > bstri2->size) {
146 signumValue = 1;
147 } /* if */
148 } /* if */
149 #else
150 if (bstri1->size < bstri2->size) {
151 if (memcmp(bstri1->mem, bstri2->mem, bstri1->size) <= 0) {
152 signumValue = -1;
153 } else {
154 signumValue = 1;
155 } /* if */
156 } else {
157 signumValue = memcmp(bstri1->mem, bstri2->mem, bstri2->size);
158 if (signumValue == 0) {
159 if (bstri1->size > bstri2->size) {
160 signumValue = 1;
161 } /* if */
162 } else if (signumValue > 0) {
163 signumValue = 1;
164 } else {
165 signumValue = -1;
166 } /* if */
167 } /* if */
168 #endif
169 return signumValue;
170 } /* bstCmp */
171
172
173
174 /**
175 * Reinterpret the generic parameters as bstriType and call bstCmp.
176 * Function pointers in C programs generated by the Seed7 compiler
177 * may point to this function. This assures correct behaviour even
178 * if sizeof(genericType) != sizeof(bstriType).
179 * @return -1, 0 or 1 if the first argument is considered to be
180 * respectively less than, equal to, or greater than the
181 * second.
182 */
bstCmpGeneric(const genericType value1,const genericType value2)183 intType bstCmpGeneric (const genericType value1, const genericType value2)
184
185 { /* bstCmpGeneric */
186 return bstCmp(((const_rtlObjectType *) &value1)->value.bstriValue,
187 ((const_rtlObjectType *) &value2)->value.bstriValue);
188 } /* bstCmpGeneric */
189
190
191
192 /**
193 * Assign source to *dest.
194 * A copy function assumes that *dest contains a legal value.
195 * @exception MEMORY_ERROR Not enough memory to create dest.
196 */
bstCpy(bstriType * const dest,const const_bstriType source)197 void bstCpy (bstriType *const dest, const const_bstriType source)
198
199 {
200 memSizeType new_size;
201 bstriType bstri_dest;
202
203 /* bstCpy */
204 bstri_dest = *dest;
205 new_size = source->size;
206 if (bstri_dest->size != new_size) {
207 if (unlikely(!ALLOC_BSTRI_SIZE_OK(bstri_dest, new_size))) {
208 raise_error(MEMORY_ERROR);
209 return;
210 } else {
211 FREE_BSTRI(*dest, (*dest)->size);
212 bstri_dest->size = new_size;
213 *dest = bstri_dest;
214 } /* if */
215 } /* if */
216 /* It is possible that *dest == source holds. The */
217 /* behavior of memcpy() is undefined if source and */
218 /* destination areas overlap (or are identical). */
219 /* Therefore memmove() is used instead of memcpy(). */
220 memmove(bstri_dest->mem, source->mem, new_size);
221 } /* bstCpy */
222
223
224
225 /**
226 * Reinterpret the generic parameters as bstriType and call bstCpy.
227 * Function pointers in C programs generated by the Seed7 compiler
228 * may point to this function. This assures correct behaviour even
229 * if sizeof(genericType) != sizeof(bstriType).
230 */
bstCpyGeneric(genericType * const dest,const genericType source)231 void bstCpyGeneric (genericType *const dest, const genericType source)
232
233 { /* bstCpyGeneric */
234 bstCpy(&((rtlObjectType *) dest)->value.bstriValue,
235 ((const_rtlObjectType *) &source)->value.bstriValue);
236 } /* bstCpyGeneric */
237
238
239
240 /**
241 * Return a copy of source, that can be assigned to a new destination.
242 * It is assumed that the destination of the assignment is undefined.
243 * Create functions can be used to initialize Seed7 constants.
244 * @return a copy of source.
245 * @exception MEMORY_ERROR Not enough memory to represent the result.
246 */
bstCreate(const const_bstriType source)247 bstriType bstCreate (const const_bstriType source)
248
249 {
250 memSizeType new_size;
251 bstriType result;
252
253 /* bstCreate */
254 logFunction(printf("bstCreate(\"%s\")", bstriAsUnquotedCStri(source));
255 fflush(stdout););
256 new_size = source->size;
257 if (unlikely(!ALLOC_BSTRI_SIZE_OK(result, new_size))) {
258 raise_error(MEMORY_ERROR);
259 } else {
260 result->size = new_size;
261 memcpy(result->mem, source->mem, (size_t) new_size);
262 } /* if */
263 logFunctionResult(printf("\"%s\"\n", bstriAsUnquotedCStri(result)););
264 return result;
265 } /* bstCreate */
266
267
268
269 /**
270 * Generic Create function to be used via function pointers.
271 * Function pointers in C programs generated by the Seed7 compiler
272 * may point to this function. This assures correct behaviour even
273 * if sizeof(genericType) != sizeof(bstriType).
274 */
bstCreateGeneric(const genericType from_value)275 genericType bstCreateGeneric (const genericType from_value)
276
277 {
278 rtlObjectType result;
279
280 /* bstCreateGeneric */
281 INIT_GENERIC_PTR(result.value.genericValue);
282 result.value.bstriValue =
283 bstCreate(((const_rtlObjectType *) &from_value)->value.bstriValue);
284 return result.value.genericValue;
285 } /* bstCreateGeneric */
286
287
288
289 /**
290 * Free the memory referred by 'old_bstring'.
291 * After bstDestr is left 'old_bstring' refers to not existing memory.
292 * The memory where 'old_bstring' is stored can be freed afterwards.
293 */
bstDestr(const const_bstriType old_bstring)294 void bstDestr (const const_bstriType old_bstring)
295
296 { /* bstDestr */
297 if (old_bstring != NULL) {
298 FREE_BSTRI(old_bstring, old_bstring->size);
299 } /* if */
300 } /* bstDestr */
301
302
303
304 /**
305 * Generic Destr function to be used via function pointers.
306 * Function pointers in C programs generated by the Seed7 compiler
307 * may point to this function. This assures correct behaviour even
308 * if sizeof(genericType) != sizeof(bstriType).
309 */
bstDestrGeneric(const genericType old_value)310 void bstDestrGeneric (const genericType old_value)
311
312 { /* bstDestrGeneric */
313 bstDestr(((const_rtlObjectType *) &old_value)->value.bstriValue);
314 } /* bstDestrGeneric */
315
316
317
318 /**
319 * Compute the hash value of a 'bstring'.
320 * @return the hash value.
321 */
bstHashCode(const const_bstriType bstri)322 intType bstHashCode (const const_bstriType bstri)
323
324 {
325 intType result;
326
327 /* bstHashCode */
328 if (bstri->size == 0) {
329 result = 0;
330 } else {
331 result = (intType) ((memSizeType) bstri->mem[0] << 5 ^
332 bstri->size << 3 ^ bstri->mem[bstri->size - 1]);
333 } /* if */
334 return result;
335 } /* bstHashCode */
336
337
338
339 /**
340 * Convert a string to a 'bstring' value.
341 * @return the 'bstring' result of the conversion.
342 * @exception RANGE_ERROR If characters beyond '\255;' are present.
343 * @exception MEMORY_ERROR Not enough memory to represent the result.
344 */
bstParse(const const_striType stri)345 bstriType bstParse (const const_striType stri)
346
347 {
348 bstriType result;
349
350 /* bstParse */
351 logFunction(printf("bstParse(\"%s\")\n", striAsUnquotedCStri(stri)););
352 if (unlikely(!ALLOC_BSTRI_CHECK_SIZE(result, stri->size))) {
353 raise_error(MEMORY_ERROR);
354 } else {
355 result->size = stri->size;
356 if (unlikely(memcpy_from_strelem(result->mem, stri->mem, stri->size))) {
357 FREE_BSTRI(result, result->size);
358 logError(printf("bstParse(\"%s\"): Character beyond '\255;' present.\n",
359 striAsUnquotedCStri(stri)););
360 raise_error(RANGE_ERROR);
361 return NULL;
362 } /* if */
363 } /* if */
364 logFunction(printf("bstParse --> \"%s\"\n", bstriAsUnquotedCStri(result)););
365 return result;
366 } /* bstParse */
367
368
369
370 /**
371 * Convert a 'bstring' value to a string.
372 * @return the string result of the conversion.
373 * @exception MEMORY_ERROR Not enough memory to represent the result.
374 */
bstStr(const const_bstriType bstri)375 striType bstStr (const const_bstriType bstri)
376
377 {
378 striType result;
379
380 /* bstStr */
381 logFunction(printf("bstStr(\"%s\")\n", bstriAsUnquotedCStri(bstri)););
382 if (unlikely(!ALLOC_STRI_CHECK_SIZE(result, bstri->size))) {
383 raise_error(MEMORY_ERROR);
384 } else {
385 result->size = bstri->size;
386 memcpy_to_strelem(result->mem, bstri->mem, bstri->size);
387 } /* if */
388 logFunction(printf("bstStr --> \"%s\"\n", striAsUnquotedCStri(result)););
389 return result;
390 } /* bstStr */
391
392
393
bstTail(const const_bstriType stri,intType start)394 bstriType bstTail (const const_bstriType stri, intType start)
395
396 {
397 memSizeType length;
398 memSizeType result_size;
399 bstriType result;
400
401 /* bstTail */
402 length = stri->size;
403 if (start < 1) {
404 start = 1;
405 } /* if */
406 if ((uintType) start <= length && length >= 1) {
407 result_size = length - (memSizeType) start + 1;
408 if (unlikely(!ALLOC_BSTRI_SIZE_OK(result, result_size))) {
409 raise_error(MEMORY_ERROR);
410 return NULL;
411 } /* if */
412 /* Reversing the order of the following two statements */
413 /* causes an "Internal Compiler Error" with MSC 6.0 */
414 /* if using the -Ozacegilt optimisation option in the */
415 /* large memory model (-AL). Note that the order of the */
416 /* two statements make no difference to the logic of the */
417 /* program. */
418 memcpy(result->mem, &stri->mem[start - 1], result_size);
419 result->size = result_size;
420 } else {
421 if (unlikely(!ALLOC_BSTRI_SIZE_OK(result, (memSizeType) 0))) {
422 raise_error(MEMORY_ERROR);
423 return NULL;
424 } /* if */
425 result->size = 0;
426 } /* if */
427 return result;
428 } /* bstTail */
429