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