1 /********************************************************************/
2 /*                                                                  */
3 /*  striutl.c     Procedures to work with wide char strings.        */
4 /*  Copyright (C) 1989 - 2021  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/striutl.c                                       */
27 /*  Changes: 1991 - 1994, 2005 - 2021  Thomas Mertes                */
28 /*  Content: Procedures to work with wide char strings.             */
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 #include "ctype.h"
41 #ifdef OS_STRI_WCHAR
42 #include "wchar.h"
43 #endif
44 
45 #include "common.h"
46 #include "heaputl.h"
47 #include "int_rtl.h"
48 
49 #undef EXTERN
50 #define EXTERN
51 #define DO_INIT
52 #include "striutl.h"
53 
54 
55 const const_cstriType stri_escape_sequence[] = {
56     "\\0;",  "\\1;",  "\\2;",  "\\3;",  "\\4;",
57     "\\5;",  "\\6;",  "\\a",   "\\b",   "\\t",
58     "\\n",   "\\v",   "\\f",   "\\r",   "\\14;",
59     "\\15;", "\\16;", "\\17;", "\\18;", "\\19;",
60     "\\20;", "\\21;", "\\22;", "\\23;", "\\24;",
61     "\\25;", "\\26;", "\\e",   "\\28;", "\\29;",
62     "\\30;", "\\31;"};
63 
64 const const_cstriType cstri_escape_sequence[] = {
65     "\\000", "\\001", "\\002", "\\003", "\\004",
66     "\\005", "\\006", "\\007", "\\b",   "\\t",
67     "\\n",   "\\013", "\\f",   "\\r",   "\\016",
68     "\\017", "\\020", "\\021", "\\022", "\\023",
69     "\\024", "\\025", "\\026", "\\027", "\\030",
70     "\\031", "\\032", "\\033", "\\034", "\\035",
71     "\\036", "\\037"};
72 
73 static const char null_string_marker[]      = "\\ *NULL_STRING* ";
74 static const char null_byte_string_marker[] = "\\ *NULL_BYTE_STRING* ";
75 
76 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
77 #if EMULATE_ROOT_CWD
78 const_os_striType current_emulated_cwd = NULL;
79 #endif
80 const os_charType emulated_root[] = {'/', '\0'};
81 #endif
82 
83 #define USE_DUFFS_UNROLLING 1
84 #define STACK_ALLOC_SIZE    1000
85 
86 /** Strings longer than the AND_SO_ON_LIMIT are truncated. */
87 #define AND_SO_ON_LIMIT     128
88 #define AND_SO_ON_TEXT      "\\ *AND_SO_ON* SIZE="
89 
90 /** The AND_SO_ON_LENGTH includes the length of the terminating \0 byte. */
91 #define AND_SO_ON_LENGTH    (STRLEN(AND_SO_ON_TEXT) + MEMSIZETYPE_DECIMAL_SIZE + NULL_TERMINATION_LEN)
92 
93 /**
94  *  The maximum width when an UTF-32 character is displayed
95  *  in a literal is 12 characters (e.g.: \4294967295; ).
96  */
97 #define MAXIMUM_UTF32_ESCAPE_WIDTH STRLEN("\\4294967295;")
98 
99 /**
100  *  The maximum width when an unsigned char (byte) is displayed
101  *  in a literal is 5 characters (e.g.: \255; ).
102  */
103 #define MAXIMUM_BYTE_ESCAPE_WIDTH STRLEN("\\255;")
104 
105 #ifdef OS_STRI_WCHAR
106 
107 #define MAX_OS_STRI_SIZE    (((MAX_MEMSIZETYPE / sizeof(os_charType)) - NULL_TERMINATION_LEN) / SURROGATE_PAIR_FACTOR)
108 #define MAX_OS_BSTRI_SIZE   (((MAX_BSTRI_LEN / sizeof(os_charType)) - NULL_TERMINATION_LEN) / SURROGATE_PAIR_FACTOR)
109 #define OS_STRI_SIZE(size)  ((size) * SURROGATE_PAIR_FACTOR)
110 #define OS_BSTRI_SIZE(size) (((size) * SURROGATE_PAIR_FACTOR + NULL_TERMINATION_LEN) * sizeof(os_charType))
111 
112 #elif defined OS_STRI_USES_CODE_PAGE
113 
114 #define MAX_OS_STRI_SIZE    ((MAX_MEMSIZETYPE / sizeof(os_charType)) - NULL_TERMINATION_LEN)
115 #define MAX_OS_BSTRI_SIZE   ((MAX_BSTRI_LEN / sizeof(os_charType)) - NULL_TERMINATION_LEN)
116 #define OS_STRI_SIZE(size)  (size)
117 #define OS_BSTRI_SIZE(size) (((size) + NULL_TERMINATION_LEN) * sizeof(os_charType))
118 int code_page = DEFAULT_CODE_PAGE;
119 
120 #elif defined OS_STRI_UTF8
121 
122 #define MAX_OS_STRI_SIZE    (MAX_CSTRI_LEN / MAX_UTF8_EXPANSION_FACTOR)
123 #define MAX_OS_BSTRI_SIZE   ((MAX_BSTRI_LEN - NULL_TERMINATION_LEN) / MAX_UTF8_EXPANSION_FACTOR)
124 #define OS_STRI_SIZE(size)  max_utf8_size(size)
125 #define OS_BSTRI_SIZE(size) (max_utf8_size(size) + NULL_TERMINATION_LEN)
126 
127 #else
128 
129 #define MAX_OS_STRI_SIZE    ((MAX_MEMSIZETYPE / sizeof(os_charType)) - NULL_TERMINATION_LEN)
130 #define MAX_OS_BSTRI_SIZE   ((MAX_BSTRI_LEN / sizeof(os_charType)) - NULL_TERMINATION_LEN)
131 #define OS_STRI_SIZE(size)  (size)
132 #define OS_BSTRI_SIZE(size) (((size) + NULL_TERMINATION_LEN) * sizeof(os_charType))
133 
134 #endif
135 
136 
137 
138 /**
139  *  Write a Seed7 string to a static C string buffer.
140  *  This function is intended to do debug/log output with printf().
141  *  Control chars and chars byond ASCII are written with Seed7
142  *  escape sequences. Strings longer than the AND_SO_ON_LIMIT are
143  *  truncated and an information about the total length is added.
144  *  Since a static buffer is used every call of printf() can only
145  *  work correctly with one call of striAsUnquotedCStri(). Because
146  *  of the static buffer this function is not thread safe.
147  *  @param stri String to be written into the static buffer.
148  *  @return a pointer to the static buffer containing the string.
149  */
striAsUnquotedCStri(const const_striType stri)150 cstriType striAsUnquotedCStri (const const_striType stri)
151 
152   {
153     memSizeType size;
154     strElemType ch;
155     memSizeType idx;
156     memSizeType pos = 0;
157     static char buffer[AND_SO_ON_LIMIT * MAXIMUM_UTF32_ESCAPE_WIDTH +
158                        AND_SO_ON_LENGTH];
159 
160   /* striAsUnquotedCStri */
161     if (stri != NULL) {
162       size = stri->size;
163       if (size > AND_SO_ON_LIMIT) {
164         size = AND_SO_ON_LIMIT;
165       } /* if */
166       for (idx = 0; idx < size; idx++) {
167         ch = stri->mem[idx];
168         if (ch < 127) {
169           if (ch < ' ') {
170             buffer[pos] = '\\';
171             if (stri_escape_sequence[ch][1] <= '9') {
172               /* Numeric escape sequence with one or two digits. */
173               if (ch <= 9) {
174                 buffer[pos + 1] = (char) (ch + '0');
175                 buffer[pos + 2] = ';';
176                 pos += 3;
177               } else {
178                 buffer[pos + 1] = stri_escape_sequence[ch][1];
179                 buffer[pos + 2] = stri_escape_sequence[ch][2];
180                 buffer[pos + 3] = ';';
181                 pos += 4;
182               } /* if */
183             } else {
184               /* Character escape sequence. */
185               buffer[pos + 1] = stri_escape_sequence[ch][1];
186               pos += 2;
187             } /* if */
188           } else if (ch == (charType) '\\') {
189             memcpy(&buffer[pos], "\\\\", 2);
190             pos += 2;
191           } else if (ch == (charType) '\"') {
192             memcpy(&buffer[pos], "\\\"", 2);
193             pos += 2;
194           } else {
195             buffer[pos] = (char) ch;
196             pos++;
197           } /* if */
198         } else if (ch == (charType) -1) {
199           memcpy(&buffer[pos], "\\-1;", 4);
200           pos += 4;
201         } else {
202           pos += (memSizeType) sprintf(&buffer[pos], "\\%lu;", (unsigned long) ch);
203         } /* if */
204       } /* for */
205       if (stri->size > AND_SO_ON_LIMIT) {
206         pos += (memSizeType) sprintf(&buffer[pos], AND_SO_ON_TEXT FMT_U_MEM, stri->size);
207       } /* if */
208     } else {
209       MEMCPY_STRING(buffer, null_string_marker);
210       pos = STRLEN(null_string_marker);
211     } /* if */
212     buffer[pos] = '\0';
213     return buffer;
214   } /* striAsUnquotedCStri */
215 
216 
217 
218 #if LOG_FUNCTIONS || LOG_FUNCTIONS_EVERYWHERE
striCharsAsUnquotedCStri(const strElemType * const striChars,memSizeType striSize)219 static cstriType striCharsAsUnquotedCStri (const strElemType *const striChars,
220     memSizeType striSize)
221 
222   {
223     striRecord striSlice;
224 
225   /* striCharsAsUnquotedCStri */
226 #if ALLOW_STRITYPE_SLICES
227     striSlice.size = striSize;
228     striSlice.mem = (strElemType *) striChars;
229     return striAsUnquotedCStri(&striSlice);
230 #else
231     return "\\ STRING_WITHOUT_DETAILS \\";
232 #endif
233   } /* striCharsAsUnquotedCStri */
234 #endif
235 
236 
237 
238 /**
239  *  Write a Seed7 bstring to a static C string buffer.
240  *  This function is intended to do debug/log output with printf().
241  *  Control chars and chars byond ASCII are written with Seed7
242  *  escape sequences. Strings longer than the AND_SO_ON_LIMIT are
243  *  truncated and an information about the total length is added.
244  *  Since a static buffer is used every call of printf() can only
245  *  work correctly with one call of bstriAsUnquotedCStri(). Because
246  *  of the static buffer this function is not thread safe.
247  *  @param bstri Bstring to be written into the static buffer.
248  *  @return a pointer to the static buffer containing the string.
249  */
bstriAsUnquotedCStri(const const_bstriType bstri)250 cstriType bstriAsUnquotedCStri (const const_bstriType bstri)
251 
252   {
253     memSizeType size;
254     ucharType ch;
255     memSizeType idx;
256     memSizeType pos = 0;
257     static char buffer[AND_SO_ON_LIMIT * MAXIMUM_BYTE_ESCAPE_WIDTH +
258                        AND_SO_ON_LENGTH];
259 
260   /* bstriAsUnquotedCStri */
261     if (bstri != NULL) {
262       size = bstri->size;
263       if (size > AND_SO_ON_LIMIT) {
264         size = AND_SO_ON_LIMIT;
265       } /* if */
266       for (idx = 0; idx < size; idx++) {
267         ch = bstri->mem[idx];
268         if (ch < 127) {
269           if (ch < ' ') {
270             strcpy(&buffer[pos], stri_escape_sequence[ch]);
271             pos += strlen(&buffer[pos]);
272           } else if (ch == '\\') {
273             memcpy(&buffer[pos], "\\\\", 2);
274             pos += 2;
275           } else if (ch == '\"') {
276             memcpy(&buffer[pos], "\\\"", 2);
277             pos += 2;
278           } else {
279             buffer[pos] = (char) ch;
280             pos++;
281           } /* if */
282         } else {
283           pos += (memSizeType) sprintf(&buffer[pos], "\\%u;", (unsigned int) ch);
284         } /* if */
285       } /* for */
286       if (bstri->size > AND_SO_ON_LIMIT) {
287         pos += (memSizeType) sprintf(&buffer[pos], AND_SO_ON_TEXT FMT_U_MEM, bstri->size);
288       } /* if */
289     } else {
290       MEMCPY_STRING(buffer, null_byte_string_marker);
291       pos = STRLEN(null_byte_string_marker);
292     } /* if */
293     buffer[pos] = '\0';
294     return buffer;
295   } /* bstriAsUnquotedCStri */
296 
297 
298 
299 #if !STRINGIFY_WORKS
stringify(intType number)300 cstriType stringify (intType number)
301 
302   {
303     static char buffer[10];
304 
305   /* stringify */
306     sprintf(buffer, FMT_D, number);
307     return buffer;
308   } /* stringify */
309 #endif
310 
311 
312 
313 #if USE_DUFFS_UNROLLING
314 /**
315  *  Copy len bytes to Seed7 characters in a string.
316  *  This function works also correct if 'src' and 'dest' point
317  *  to the same address. In other words it works correct for:
318  *    memcpy_to_strelem(mem, (ustriType) mem, num);
319  *  This function uses loop unrolling inspired by Duff's device.
320  *  @param dest Destination array with UTF-32 encoded characters.
321  *  @param src Source array with ISO-8859-1 encoded bytes.
322  *  @param len Number of bytes in 'src' and UTF-32 characters in 'dest'.
323  */
memcpy_to_strelem(register strElemType * const dest,register const const_ustriType src,memSizeType len)324 void memcpy_to_strelem (register strElemType *const dest,
325     register const const_ustriType src, memSizeType len)
326 
327   {
328     register memSizeType pos;
329 
330   /* memcpy_to_strelem */
331     if (len != 0) {
332       pos = (len + 31) & ~(memSizeType) 31;
333       switch (len & 31) {
334         do {
335           case  0: dest[pos -  1] = src[pos -  1];
336           case 31: dest[pos -  2] = src[pos -  2];
337           case 30: dest[pos -  3] = src[pos -  3];
338           case 29: dest[pos -  4] = src[pos -  4];
339           case 28: dest[pos -  5] = src[pos -  5];
340           case 27: dest[pos -  6] = src[pos -  6];
341           case 26: dest[pos -  7] = src[pos -  7];
342           case 25: dest[pos -  8] = src[pos -  8];
343           case 24: dest[pos -  9] = src[pos -  9];
344           case 23: dest[pos - 10] = src[pos - 10];
345           case 22: dest[pos - 11] = src[pos - 11];
346           case 21: dest[pos - 12] = src[pos - 12];
347           case 20: dest[pos - 13] = src[pos - 13];
348           case 19: dest[pos - 14] = src[pos - 14];
349           case 18: dest[pos - 15] = src[pos - 15];
350           case 17: dest[pos - 16] = src[pos - 16];
351           case 16: dest[pos - 17] = src[pos - 17];
352           case 15: dest[pos - 18] = src[pos - 18];
353           case 14: dest[pos - 19] = src[pos - 19];
354           case 13: dest[pos - 20] = src[pos - 20];
355           case 12: dest[pos - 21] = src[pos - 21];
356           case 11: dest[pos - 22] = src[pos - 22];
357           case 10: dest[pos - 23] = src[pos - 23];
358           case  9: dest[pos - 24] = src[pos - 24];
359           case  8: dest[pos - 25] = src[pos - 25];
360           case  7: dest[pos - 26] = src[pos - 26];
361           case  6: dest[pos - 27] = src[pos - 27];
362           case  5: dest[pos - 28] = src[pos - 28];
363           case  4: dest[pos - 29] = src[pos - 29];
364           case  3: dest[pos - 30] = src[pos - 30];
365           case  2: dest[pos - 31] = src[pos - 31];
366           case  1: dest[pos - 32] = src[pos - 32];
367         } while ((pos -= 32) != 0);
368       } /* switch */
369     } /* if */
370   } /* memcpy_to_strelem */
371 
372 
373 
374 /**
375  *  Fill an array of len Seed7 characters with the character ch.
376  *  This function uses loop unrolling inspired by Duff's device.
377  *  Up to a length of 6 a simple loop is faster than calling
378  *  this function. With a length of 7 a simple loop is as fast
379  *  as calling this function.
380  *  The use of indices relative to pos allows the C compiler
381  *  to do more optimizations.
382  *  @param dest Destination array with UTF-32 encoded characters.
383  *  @param ch UTF-32 encoded character to be filled into 'dest'.
384  *  @param len Specifies how often 'ch' is filled into 'dest'.
385  */
memset_to_strelem(register strElemType * const dest,register const strElemType ch,memSizeType len)386 void memset_to_strelem (register strElemType *const dest,
387     register const strElemType ch, memSizeType len)
388 
389   {
390     register memSizeType pos;
391 
392   /* memset_to_strelem */
393     if (len != 0) {
394       pos = (len + 31) & ~(memSizeType) 31;
395       switch (len & 31) {
396         do {
397           case  0: dest[pos -  1] = ch;
398           case 31: dest[pos -  2] = ch;
399           case 30: dest[pos -  3] = ch;
400           case 29: dest[pos -  4] = ch;
401           case 28: dest[pos -  5] = ch;
402           case 27: dest[pos -  6] = ch;
403           case 26: dest[pos -  7] = ch;
404           case 25: dest[pos -  8] = ch;
405           case 24: dest[pos -  9] = ch;
406           case 23: dest[pos - 10] = ch;
407           case 22: dest[pos - 11] = ch;
408           case 21: dest[pos - 12] = ch;
409           case 20: dest[pos - 13] = ch;
410           case 19: dest[pos - 14] = ch;
411           case 18: dest[pos - 15] = ch;
412           case 17: dest[pos - 16] = ch;
413           case 16: dest[pos - 17] = ch;
414           case 15: dest[pos - 18] = ch;
415           case 14: dest[pos - 19] = ch;
416           case 13: dest[pos - 20] = ch;
417           case 12: dest[pos - 21] = ch;
418           case 11: dest[pos - 22] = ch;
419           case 10: dest[pos - 23] = ch;
420           case  9: dest[pos - 24] = ch;
421           case  8: dest[pos - 25] = ch;
422           case  7: dest[pos - 26] = ch;
423           case  6: dest[pos - 27] = ch;
424           case  5: dest[pos - 28] = ch;
425           case  4: dest[pos - 29] = ch;
426           case  3: dest[pos - 30] = ch;
427           case  2: dest[pos - 31] = ch;
428           case  1: dest[pos - 32] = ch;
429         } while ((pos -= 32) != 0);
430       } /* switch */
431     } /* if */
432   } /* memset_to_strelem */
433 
434 
435 
436 /**
437  *  Copy len Seed7 characters to a byte string.
438  *  This function uses loop unrolling inspired by Duff's device
439  *  and a trick with a binary or (|=) to check for allowed values.
440  *  @param dest Destination array with ISO-8859-1 encoded bytes.
441  *  @param src Source array with UTF-32 encoded characters.
442  *  @param len Number of UTF-32 characters in 'src' and bytes in 'dest'.
443  *  @return TRUE if one of the characters does not fit into a byte,
444  *          FALSE otherwise.
445  */
memcpy_from_strelem(register const ustriType dest,register const strElemType * const src,memSizeType len)446 boolType memcpy_from_strelem (register const ustriType dest,
447     register const strElemType *const src, memSizeType len)
448 
449   {
450     register memSizeType pos;
451     register strElemType check = 0;
452 
453   /* memcpy_from_strelem */
454     if (len != 0) {
455       pos = (len + 31) & ~(memSizeType) 31;
456       switch (len & 31) {
457         do {
458           case  0: check |= src[pos -  1]; dest[pos -  1] = (ucharType) src[pos -  1];
459           case 31: check |= src[pos -  2]; dest[pos -  2] = (ucharType) src[pos -  2];
460           case 30: check |= src[pos -  3]; dest[pos -  3] = (ucharType) src[pos -  3];
461           case 29: check |= src[pos -  4]; dest[pos -  4] = (ucharType) src[pos -  4];
462           case 28: check |= src[pos -  5]; dest[pos -  5] = (ucharType) src[pos -  5];
463           case 27: check |= src[pos -  6]; dest[pos -  6] = (ucharType) src[pos -  6];
464           case 26: check |= src[pos -  7]; dest[pos -  7] = (ucharType) src[pos -  7];
465           case 25: check |= src[pos -  8]; dest[pos -  8] = (ucharType) src[pos -  8];
466           case 24: check |= src[pos -  9]; dest[pos -  9] = (ucharType) src[pos -  9];
467           case 23: check |= src[pos - 10]; dest[pos - 10] = (ucharType) src[pos - 10];
468           case 22: check |= src[pos - 11]; dest[pos - 11] = (ucharType) src[pos - 11];
469           case 21: check |= src[pos - 12]; dest[pos - 12] = (ucharType) src[pos - 12];
470           case 20: check |= src[pos - 13]; dest[pos - 13] = (ucharType) src[pos - 13];
471           case 19: check |= src[pos - 14]; dest[pos - 14] = (ucharType) src[pos - 14];
472           case 18: check |= src[pos - 15]; dest[pos - 15] = (ucharType) src[pos - 15];
473           case 17: check |= src[pos - 16]; dest[pos - 16] = (ucharType) src[pos - 16];
474           case 16: check |= src[pos - 17]; dest[pos - 17] = (ucharType) src[pos - 17];
475           case 15: check |= src[pos - 18]; dest[pos - 18] = (ucharType) src[pos - 18];
476           case 14: check |= src[pos - 19]; dest[pos - 19] = (ucharType) src[pos - 19];
477           case 13: check |= src[pos - 20]; dest[pos - 20] = (ucharType) src[pos - 20];
478           case 12: check |= src[pos - 21]; dest[pos - 21] = (ucharType) src[pos - 21];
479           case 11: check |= src[pos - 22]; dest[pos - 22] = (ucharType) src[pos - 22];
480           case 10: check |= src[pos - 23]; dest[pos - 23] = (ucharType) src[pos - 23];
481           case  9: check |= src[pos - 24]; dest[pos - 24] = (ucharType) src[pos - 24];
482           case  8: check |= src[pos - 25]; dest[pos - 25] = (ucharType) src[pos - 25];
483           case  7: check |= src[pos - 26]; dest[pos - 26] = (ucharType) src[pos - 26];
484           case  6: check |= src[pos - 27]; dest[pos - 27] = (ucharType) src[pos - 27];
485           case  5: check |= src[pos - 28]; dest[pos - 28] = (ucharType) src[pos - 28];
486           case  4: check |= src[pos - 29]; dest[pos - 29] = (ucharType) src[pos - 29];
487           case  3: check |= src[pos - 30]; dest[pos - 30] = (ucharType) src[pos - 30];
488           case  2: check |= src[pos - 31]; dest[pos - 31] = (ucharType) src[pos - 31];
489           case  1: check |= src[pos - 32]; dest[pos - 32] = (ucharType) src[pos - 32];
490         } while ((pos -= 32) != 0);
491       } /* switch */
492     } /* if */
493     return check >= 256;
494   } /* memcpy_from_strelem */
495 
496 
497 
498 #if !HAS_WMEMCHR || WCHAR_T_SIZE != 32
499 /**
500  *  Scan the first len Seed7 characters for the character ch.
501  *  This function uses loop unrolling inspired by Duff's device.
502  *  @param mem Array with UTF-32 characters.
503  *  @param ch UTF-32 character to be searched in 'mem'.
504  *  @param len Number of UTF-32 characters in 'mem'.
505  *  @return a pointer to the matching character, or NULL if the
506  *          character does not occur in the given string area.
507  */
memchr_strelem(register const strElemType * mem,const strElemType ch,memSizeType len)508 const strElemType *memchr_strelem (register const strElemType *mem,
509     const strElemType ch, memSizeType len)
510 
511   {
512     register memSizeType blockCount;
513 
514   /* memchr_strelem */
515     if (len != 0) {
516       blockCount = (len + 31) >> 5;
517       switch (len & 31) {
518         do {
519           case  0: if (unlikely(*mem == ch)) return mem; mem++;
520           case 31: if (unlikely(*mem == ch)) return mem; mem++;
521           case 30: if (unlikely(*mem == ch)) return mem; mem++;
522           case 29: if (unlikely(*mem == ch)) return mem; mem++;
523           case 28: if (unlikely(*mem == ch)) return mem; mem++;
524           case 27: if (unlikely(*mem == ch)) return mem; mem++;
525           case 26: if (unlikely(*mem == ch)) return mem; mem++;
526           case 25: if (unlikely(*mem == ch)) return mem; mem++;
527           case 24: if (unlikely(*mem == ch)) return mem; mem++;
528           case 23: if (unlikely(*mem == ch)) return mem; mem++;
529           case 22: if (unlikely(*mem == ch)) return mem; mem++;
530           case 21: if (unlikely(*mem == ch)) return mem; mem++;
531           case 20: if (unlikely(*mem == ch)) return mem; mem++;
532           case 19: if (unlikely(*mem == ch)) return mem; mem++;
533           case 18: if (unlikely(*mem == ch)) return mem; mem++;
534           case 17: if (unlikely(*mem == ch)) return mem; mem++;
535           case 16: if (unlikely(*mem == ch)) return mem; mem++;
536           case 15: if (unlikely(*mem == ch)) return mem; mem++;
537           case 14: if (unlikely(*mem == ch)) return mem; mem++;
538           case 13: if (unlikely(*mem == ch)) return mem; mem++;
539           case 12: if (unlikely(*mem == ch)) return mem; mem++;
540           case 11: if (unlikely(*mem == ch)) return mem; mem++;
541           case 10: if (unlikely(*mem == ch)) return mem; mem++;
542           case  9: if (unlikely(*mem == ch)) return mem; mem++;
543           case  8: if (unlikely(*mem == ch)) return mem; mem++;
544           case  7: if (unlikely(*mem == ch)) return mem; mem++;
545           case  6: if (unlikely(*mem == ch)) return mem; mem++;
546           case  5: if (unlikely(*mem == ch)) return mem; mem++;
547           case  4: if (unlikely(*mem == ch)) return mem; mem++;
548           case  3: if (unlikely(*mem == ch)) return mem; mem++;
549           case  2: if (unlikely(*mem == ch)) return mem; mem++;
550           case  1: if (unlikely(*mem == ch)) return mem; mem++;
551         } while (--blockCount > 0);
552       } /* switch */
553     } /* if */
554     return NULL;
555   } /* memchr_strelem */
556 
557 #endif
558 #else
559 
560 
561 
562 /**
563  *  Copy len bytes to Seed7 characters in a string.
564  *  This function works also correct if 'src' and 'dest' point
565  *  to the same address. In other words it works correct for:
566  *    memcpy_to_strelem(mem, (ustriType) mem, num);
567  *  @param dest Destination array with UTF-32 encoded characters.
568  *  @param src Source array with ISO-8859-1 encoded bytes.
569  *  @param len Number of bytes in 'src' and UTF-32 characters in 'dest'.
570  */
memcpy_to_strelem(register strElemType * const dest,register const const_ustriType src,memSizeType len)571 void memcpy_to_strelem (register strElemType *const dest,
572     register const const_ustriType src, memSizeType len)
573 
574   { /* memcpy_to_strelem */
575     while (len != 0) {
576       len--;
577       dest[len] = src[len];
578     } /* while */
579   } /* memcpy_to_strelem */
580 
581 
582 
583 /**
584  *  Fill len Seed7 characters with the character ch.
585  *  @param dest Destination array with UTF-32 encoded characters.
586  *  @param ch UTF-32 encoded character to be filled into 'dest'.
587  *  @param len Specifies how often 'ch' is filled into 'dest'.
588  */
memset_to_strelem(register strElemType * const dest,register const strElemType ch,memSizeType len)589 void memset_to_strelem (register strElemType *const dest,
590     register const strElemType ch, memSizeType len)
591 
592   { /* memset_to_strelem */
593     while (len != 0) { \
594       len--;
595       dest[len] = (strElemType) ch; \
596     } /* while */
597   } /* memset_to_strelem */
598 
599 
600 
601 /**
602  *  Copy len Seed7 characters to a byte string.
603  *  @param dest Destination array with ISO-8859-1 encoded bytes.
604  *  @param src Source array with UTF-32 encoded characters.
605  *  @param len Number of UTF-32 characters in 'src' and bytes in 'dest'.
606  *  @return TRUE if one of the characters does not fit into a byte,
607  *          FALSE otherwise.
608  */
memcpy_from_strelem(register const ustriType dest,register const strElemType * const src,memSizeType len)609 boolType memcpy_from_strelem (register const ustriType dest,
610     register const strElemType *const src, memSizeType len)
611 
612   {
613     register strElemType check = 0;
614 
615   /* memcpy_from_strelem */
616     while (len != 0) {
617       len--;
618       check |= src[len]
619       dest[len] = src[len];
620     } /* while */
621     return check >= 256;
622   } /* memcpy_from_strelem */
623 
624 
625 
626 #if !HAS_WMEMCHR || WCHAR_T_SIZE != 32
627 /**
628  *  Scan the first len Seed7 characters for the character ch.
629  *  @param mem Array with UTF-32 characters.
630  *  @param ch UTF-32 character to be searched in 'mem'.
631  *  @param len Number of UTF-32 characters in 'mem'.
632  *  @return a pointer to the matching character, or NULL if the
633  *          character does not occur in the given string area.
634  */
memchr_strelem(register const strElemType * mem,const strElemType ch,memSizeType len)635 const strElemType *memchr_strelem (register const strElemType *mem,
636     const strElemType ch, memSizeType len)
637 
638   { /* memchr_strelem */
639     for (; len > 0; mem++, len--) {
640       if (*mem == ch) {
641         return mem;
642       } /* if */
643     } /* for */
644     return NULL;
645   } /* memchr_strelem */
646 
647 #endif
648 #endif
649 
650 
651 
652 #if STACK_LIKE_ALLOC_FOR_OS_STRI
heapAllocOsStri(memSizeType len)653 os_striType heapAllocOsStri (memSizeType len)
654 
655   {
656     memSizeType size;
657     stackAllocType new_stack_alloc;
658     os_striType var;
659 
660   /* heapAllocOsStri */
661     logFunction(printf("heapAllocOsStri(" FMT_U_MEM ")\n", len););
662     if (len < STACK_ALLOC_SIZE) {
663       size = STACK_ALLOC_SIZE;
664     } else {
665       size = len;
666     } /* if */
667     if (unlikely(size > MAX_STACK_ALLOC ||
668         !ALLOC_HEAP(new_stack_alloc, stackAllocType, SIZ_STACK_ALLOC(size)))) {
669       var = NULL;
670     } else {
671       /* printf("new_stack_alloc=%08lx\n", new_stack_alloc); */
672       if (stack_alloc->curr_free == stack_alloc->start) {
673         new_stack_alloc->previous = stack_alloc->previous;
674         free(stack_alloc);
675       } else {
676         new_stack_alloc->previous = stack_alloc;
677       } /* if */
678       /* printf("previous=%08lx\n", new_stack_alloc->previous); */
679       new_stack_alloc->beyond = &new_stack_alloc->start[SIZ_OS_STRI(size)];
680       /* printf("beyond=%08lx\n", new_stack_alloc->beyond); */
681       new_stack_alloc->curr_free = new_stack_alloc->start;
682       stack_alloc = new_stack_alloc;
683       (void) POP_OS_STRI(var, SIZ_OS_STRI(len));
684     } /* if */
685     logFunction(printf("heapAllocOsStri(" FMT_U_MEM ") --> " FMT_X_MEM "\n",
686                        len, (memSizeType) var););
687     return var;
688   } /* heapAllocOsStri */
689 
690 
691 
heapFreeOsStri(const_os_striType var)692 void heapFreeOsStri (const_os_striType var)
693 
694   {
695     stackAllocType old_stack_alloc;
696 
697   /* heapFreeOsStri */
698     logFunction(printf("heapFreeOsStri(" FMT_X_MEM ")\n",
699                        (memSizeType) var););
700     old_stack_alloc = stack_alloc;
701     stack_alloc = old_stack_alloc->previous;
702     free(old_stack_alloc);
703   } /* heapFreeOsStri */
704 #endif
705 
706 
707 
708 /**
709  *  Convert an UTF-8 encoded string to an UTF-32 encoded string.
710  *  The source and destination strings are not '\0' terminated.
711  *  The memory for the destination dest_stri is not allocated.
712  *  @param dest_stri Destination of the UTF-32 encoded string.
713  *  @param dest_len Place to return the length of dest_stri.
714  *  @param ustri UTF-8 encoded string to be converted.
715  *  @param len Number of bytes in ustri.
716  *  @return the number of bytes in ustri that are left unconverted, or
717  *          0 if ustri has been successfully converted.
718  */
utf8_to_stri(strElemType * const dest_stri,memSizeType * const dest_len,const_ustriType ustri,memSizeType len)719 memSizeType utf8_to_stri (strElemType *const dest_stri,
720     memSizeType *const dest_len, const_ustriType ustri, memSizeType len)
721 
722   {
723     strElemType *stri;
724 
725   /* utf8_to_stri */
726     stri = dest_stri;
727     for (; len > 0; len--) {
728       if (*ustri <= 0x7F) {
729         *stri++ = (strElemType) *ustri++;
730       } else if (ustri[0] >= 0xC0 && ustri[0] <= 0xDF && len >= 2 &&
731                  ustri[1] >= 0x80 && ustri[1] <= 0xBF) {
732         /* ustri[0]   range 192 to 223 (leading bits 110.....) */
733         /* ustri[1]   range 128 to 191 (leading bits 10......) */
734         *stri++ = (strElemType) (ustri[0] & 0x1F) << 6 |
735                   (strElemType) (ustri[1] & 0x3F);
736         ustri += 2;
737         len--;
738       } else if (ustri[0] >= 0xE0 && ustri[0] <= 0xEF && len >= 3 &&
739                  ustri[1] >= 0x80 && ustri[1] <= 0xBF &&
740                  ustri[2] >= 0x80 && ustri[2] <= 0xBF) {
741         /* ustri[0]   range 224 to 239 (leading bits 1110....) */
742         /* ustri[1..] range 128 to 191 (leading bits 10......) */
743         *stri++ = (strElemType) (ustri[0] & 0x0F) << 12 |
744                   (strElemType) (ustri[1] & 0x3F) <<  6 |
745                   (strElemType) (ustri[2] & 0x3F);
746         ustri += 3;
747         len -= 2;
748       } else if (ustri[0] >= 0xF0 && ustri[0] <= 0xF7 && len >= 4 &&
749                  ustri[1] >= 0x80 && ustri[1] <= 0xBF &&
750                  ustri[2] >= 0x80 && ustri[2] <= 0xBF &&
751                  ustri[3] >= 0x80 && ustri[3] <= 0xBF) {
752         /* ustri[0]   range 240 to 247 (leading bits 11110...) */
753         /* ustri[1..] range 128 to 191 (leading bits 10......) */
754         *stri++ = (strElemType) (ustri[0] & 0x07) << 18 |
755                   (strElemType) (ustri[1] & 0x3F) << 12 |
756                   (strElemType) (ustri[2] & 0x3F) <<  6 |
757                   (strElemType) (ustri[3] & 0x3F);
758         ustri += 4;
759         len -= 3;
760       } else if (ustri[0] >= 0xF8 && ustri[0] <= 0xFB && len >= 5 &&
761                  ustri[1] >= 0x80 && ustri[1] <= 0xBF &&
762                  ustri[2] >= 0x80 && ustri[2] <= 0xBF &&
763                  ustri[3] >= 0x80 && ustri[3] <= 0xBF &&
764                  ustri[4] >= 0x80 && ustri[4] <= 0xBF) {
765         /* ustri[0]   range 248 to 251 (leading bits 111110..) */
766         /* ustri[1..] range 128 to 191 (leading bits 10......) */
767         *stri++ = (strElemType) (ustri[0] & 0x03) << 24 |
768                   (strElemType) (ustri[1] & 0x3F) << 18 |
769                   (strElemType) (ustri[2] & 0x3F) << 12 |
770                   (strElemType) (ustri[3] & 0x3F) <<  6 |
771                   (strElemType) (ustri[4] & 0x3F);
772         ustri += 5;
773         len -= 4;
774       } else if (ustri[0] >= 0xFC && ustri[0] <= 0xFF && len >= 6 &&
775                  ustri[1] >= 0x80 && ustri[1] <= 0xBF &&
776                  ustri[2] >= 0x80 && ustri[2] <= 0xBF &&
777                  ustri[3] >= 0x80 && ustri[3] <= 0xBF &&
778                  ustri[4] >= 0x80 && ustri[4] <= 0xBF &&
779                  ustri[5] >= 0x80 && ustri[5] <= 0xBF) {
780         /* ustri[0]   range 252 to 255 (leading bits 111111..) */
781         /* ustri[1..] range 128 to 191 (leading bits 10......) */
782         *stri++ = (strElemType) (ustri[0] & 0x03) << 30 |
783                   (strElemType) (ustri[1] & 0x3F) << 24 |
784                   (strElemType) (ustri[2] & 0x3F) << 18 |
785                   (strElemType) (ustri[3] & 0x3F) << 12 |
786                   (strElemType) (ustri[4] & 0x3F) <<  6 |
787                   (strElemType) (ustri[5] & 0x3F);
788         ustri += 6;
789         len -= 5;
790       } else {
791         /* ustri[0] not in range 0xC0 to 0xFF (192 to 255) */
792         /* or not enough continuation bytes found.         */
793         *dest_len = (memSizeType) (stri - dest_stri);
794         return len;
795       } /* if */
796     } /* for */
797     *dest_len = (memSizeType) (stri - dest_stri);
798     return 0;
799   } /* utf8_to_stri */
800 
801 
802 
803 /**
804  *  Get number of missing bytes in incomplete UTF-8 byte sequence.
805  *  The first byte of an UTF-8 byte sequence indicates the
806  *  number of bytes in the sequence. The function checks, if
807  *  the bytes after the first byte are UTF-8 continuation bytes.
808  *  @param ustri Incomplete UTF-8 byte sequence, to be examined.
809  *  @param len Length of incomplete UTF-8 byte sequence 'ustri'.
810  *  @return the number of bytes needed to get an UTF-8 character, or
811  *          0 if 'ustri' is not the start of a UTF-8 byte sequence.
812  */
utf8_bytes_missing(const const_ustriType ustri,const memSizeType len)813 memSizeType utf8_bytes_missing (const const_ustriType ustri, const memSizeType len)
814 
815   {
816     memSizeType result = 0;
817 
818   /* utf8_bytes_missing */
819     if (len >= 1 && *ustri > 0x7F) {
820       if (ustri[0] >= 0xC0 && ustri[0] <= 0xDF) {
821         /* ustri[0]   range 192 to 223 (leading bits 110.....) */
822         if (len == 1) {
823           result = 1;
824         } /* if */
825       } else if (ustri[0] >= 0xE0 && ustri[0] <= 0xEF) {
826         /* ustri[0]   range 224 to 239 (leading bits 1110....) */
827         if (len == 1) {
828           result = 2;
829         } else if (ustri[1] >= 0x80 && ustri[1] <= 0xBF) {
830           /* ustri[1]   range 128 to 191 (leading bits 10......) */
831           if (len == 2) {
832             result = 1;
833           } /* if */
834         } /* if */
835       } else if (ustri[0] >= 0xF0 && ustri[0] <= 0xF7) {
836         /* ustri[0]   range 240 to 247 (leading bits 11110...) */
837         if (len == 1) {
838           result = 3;
839         } else if (ustri[1] >= 0x80 && ustri[1] <= 0xBF) {
840           /* ustri[1]   range 128 to 191 (leading bits 10......) */
841           if (len == 2) {
842             result = 2;
843           } else if (ustri[2] >= 0x80 && ustri[2] <= 0xBF) {
844             if (len == 3) {
845               result = 1;
846             } /* if */
847           } /* if */
848         } /* if */
849       } else if (ustri[0] >= 0xF8 && ustri[0] <= 0xFB) {
850         /* ustri[0]   range 248 to 251 (leading bits 111110..) */
851         if (len == 1) {
852           result = 4;
853         } else if (ustri[1] >= 0x80 && ustri[1] <= 0xBF) {
854           /* ustri[1]   range 128 to 191 (leading bits 10......) */
855           if (len == 2) {
856             result = 3;
857           } else if (ustri[2] >= 0x80 && ustri[2] <= 0xBF) {
858             if (len == 3) {
859               result = 2;
860             } else if (ustri[3] >= 0x80 && ustri[3] <= 0xBF) {
861               if (len == 4) {
862                 result = 1;
863               } /* if */
864             } /* if */
865           } /* if */
866         } /* if */
867       } else if (ustri[0] >= 0xFC && ustri[0] <= 0xFF) {
868         /* ustri[0]   range 252 to 255 (leading bits 111111..) */
869         if (len == 1) {
870           result = 5;
871         } else if (ustri[1] >= 0x80 && ustri[1] <= 0xBF) {
872           /* ustri[1]   range 128 to 191 (leading bits 10......) */
873           if (len == 2) {
874             result = 4;
875           } else if (ustri[2] >= 0x80 && ustri[2] <= 0xBF) {
876             if (len == 3) {
877               result = 3;
878             } else if (ustri[3] >= 0x80 && ustri[3] <= 0xBF) {
879               if (len == 4) {
880                 result = 2;
881               } else if (ustri[4] >= 0x80 && ustri[4] <= 0xBF) {
882                 if (len == 5) {
883                   result = 1;
884                 } /* if */
885               } /* if */
886             } /* if */
887           } /* if */
888         } /* if */
889       } /* if */
890     } /* if */
891     return result;
892   } /* utf8_bytes_missing */
893 
894 
895 
896 /**
897  *  Convert an UTF-32 encoded string to an UTF-8 encoded string.
898  *  The source and destination strings are not '\0' terminated.
899  *  The memory for the destination out_stri is not allocated.
900  *  @param out_stri Destination of the UTF-8 encoded string.
901  *  @param strelem UTF-32 encoded string to be converted.
902  *  @param len Number of UTF-32 characters in strelem.
903  *  @return the length of the converted UTF-8 string.
904  */
stri_to_utf8(const ustriType out_stri,const strElemType * strelem,memSizeType len)905 memSizeType stri_to_utf8 (const ustriType out_stri,
906     const strElemType *strelem, memSizeType len)
907 
908   {
909     register ustriType ustri;
910     register strElemType ch;
911 
912   /* stri_to_utf8 */
913     ustri = out_stri;
914     for (; len > 0; strelem++, len--) {
915       ch = *strelem;
916       if (ch <= 0x7F) {
917         *ustri++ = (ucharType) ch;
918       } else if (ch <= 0x7FF) {
919         ustri[0] = (ucharType) (0xC0 | (ch >>  6));
920         ustri[1] = (ucharType) (0x80 |( ch        & 0x3F));
921         ustri += 2;
922       } else if (ch <= 0xFFFF) {
923         ustri[0] = (ucharType) (0xE0 | (ch >> 12));
924         ustri[1] = (ucharType) (0x80 |((ch >>  6) & 0x3F));
925         ustri[2] = (ucharType) (0x80 |( ch        & 0x3F));
926         ustri += 3;
927       } else if (ch <= 0x1FFFFF) {
928         ustri[0] = (ucharType) (0xF0 | (ch >> 18));
929         ustri[1] = (ucharType) (0x80 |((ch >> 12) & 0x3F));
930         ustri[2] = (ucharType) (0x80 |((ch >>  6) & 0x3F));
931         ustri[3] = (ucharType) (0x80 |( ch        & 0x3F));
932         ustri += 4;
933       } else if (ch <= 0x3FFFFFF) {
934         ustri[0] = (ucharType) (0xF8 | (ch >> 24));
935         ustri[1] = (ucharType) (0x80 |((ch >> 18) & 0x3F));
936         ustri[2] = (ucharType) (0x80 |((ch >> 12) & 0x3F));
937         ustri[3] = (ucharType) (0x80 |((ch >>  6) & 0x3F));
938         ustri[4] = (ucharType) (0x80 |( ch        & 0x3F));
939         ustri += 5;
940       } else {
941         ustri[0] = (ucharType) (0xFC | (ch >> 30));
942         ustri[1] = (ucharType) (0x80 |((ch >> 24) & 0x3F));
943         ustri[2] = (ucharType) (0x80 |((ch >> 18) & 0x3F));
944         ustri[3] = (ucharType) (0x80 |((ch >> 12) & 0x3F));
945         ustri[4] = (ucharType) (0x80 |((ch >>  6) & 0x3F));
946         ustri[5] = (ucharType) (0x80 |( ch        & 0x3F));
947         ustri += 6;
948       } /* if */
949     } /* for */
950     return (memSizeType) (ustri - out_stri);
951   } /* stri_to_utf8 */
952 
953 
954 
stri_to_os_utf8(register ustriType out_stri,register const strElemType * strelem,register memSizeType len,errInfoType * err_info)955 static inline boolType stri_to_os_utf8 (register ustriType out_stri,
956     register const strElemType *strelem, register memSizeType len,
957     errInfoType *err_info)
958 
959   {
960     register strElemType ch;
961 
962   /* stri_to_os_utf8 */
963     for (; len > 0; strelem++, len--) {
964       ch = *strelem;
965       if (ch <= 0x7F) {
966         if (unlikely(ch == '\0')) {
967           logError(printf("stri_to_os_utf8: Null character ('\\0;') in string.\n"););
968           *err_info = RANGE_ERROR;
969           return FALSE;
970         } else {
971           *out_stri++ = (ucharType) ch;
972         } /* if */
973       } else if (ch <= 0x7FF) {
974         out_stri[0] = (ucharType) (0xC0 | (ch >>  6));
975         out_stri[1] = (ucharType) (0x80 |( ch        & 0x3F));
976         out_stri += 2;
977       } else if (ch <= 0xFFFF) {
978         out_stri[0] = (ucharType) (0xE0 | (ch >> 12));
979         out_stri[1] = (ucharType) (0x80 |((ch >>  6) & 0x3F));
980         out_stri[2] = (ucharType) (0x80 |( ch        & 0x3F));
981         out_stri += 3;
982       } else if (ch <= 0x10FFFF) {
983         out_stri[0] = (ucharType) (0xF0 | (ch >> 18));
984         out_stri[1] = (ucharType) (0x80 |((ch >> 12) & 0x3F));
985         out_stri[2] = (ucharType) (0x80 |((ch >>  6) & 0x3F));
986         out_stri[3] = (ucharType) (0x80 |( ch        & 0x3F));
987         out_stri += 4;
988       } else {
989         logError(printf("stri_to_os_utf8: "
990                         "Non-Unicode character ('\\" FMT_U32 ";') in string.\n",
991                         ch););
992         *err_info = RANGE_ERROR;
993         return FALSE;
994       } /* if */
995     } /* for */
996     *out_stri = '\0';
997     return TRUE;
998   } /* stri_to_os_utf8 */
999 
1000 
1001 
1002 /**
1003  *  Copy a Seed7 UTF-32 string to an ISO-8859-1 encoded C string buffer.
1004  *  The buffer 'cstri' must be provided by the caller. The
1005  *  size of the 'cstri' buffer can be calculated (in bytes) with
1006  *  stri->size+1. If a fixed size 'cstri' buffer is used
1007  *  (e.g.: char out_buffer[BUF_SIZE];) the condition
1008  *    stri->size < BUF_SIZE
1009  *  must hold. The C string written to 'out_buf' is zero byte
1010  *  terminated. This function is intended to copy to temporary
1011  *  string buffers, that are used as parameters. This function
1012  *  is useful, if stri->size is somehow limited, such that
1013  *  a fixed size 'cstri' buffer can be used.
1014  *  @param cstri Caller provided buffer to which an ISO-8859-1
1015  *         encoded null terminated C string is written.
1016  *  @param stri Seed7 UTF-32 string to be converted.
1017  *  @result cstri if the function succeeds, and
1018  *          NULL if stri contains a null character
1019  *          or a character that is higher than the
1020  *          highest allowed ISO-8859-1 character (255).
1021  */
conv_to_cstri(cstriType cstri,const const_striType stri)1022 cstriType conv_to_cstri (cstriType cstri, const const_striType stri)
1023 
1024   {
1025     const strElemType *str;
1026     memSizeType pos;
1027 
1028   /* conv_to_cstri */
1029     str = stri->mem;
1030     for (pos = stri->size; pos != 0; ) {
1031       pos--;
1032       if (unlikely(str[pos] == 0 || str[pos] >= 256)) {
1033         logError(printf("conv_to_cstri: "
1034                         "Null character or non-ISO-8859-1 character "
1035                         "in string ('\\" FMT_U32 ";').\n",
1036                         str[pos]););
1037         return NULL;
1038       } /* if */
1039       cstri[pos] = (char) (ucharType) str[pos];
1040     } /* for */
1041     cstri[stri->size] = '\0';
1042     return cstri;
1043   } /* conv_to_cstri */
1044 
1045 
1046 
1047 /**
1048  *  Copy a Seed7 UTF-32 string to an UTF-8 encoded C string buffer.
1049  *  The buffer 'cstri' must be provided by the caller. The
1050  *  size of the 'cstri' buffer can be calculated (in bytes) with
1051  *  max_utf8_size(stri->size)+1. If a fixed size 'cstri'
1052  *  buffer is used (e.g.: char out_buffer[BUF_SIZE];) the condition
1053  *    stri->size < BUF_SIZE / MAX_UTF8_EXPANSION_FACTOR
1054  *  must hold. The C string written to 'out_buf' is zero byte
1055  *  terminated. This function is intended to copy to temporary
1056  *  string buffers, that are used as parameters. This function
1057  *  is useful, if stri->size is somehow limited, such that
1058  *  a fixed size 'cstri' buffer can be used.
1059  *  @param cstri Caller provided buffer to which an UTF-8 encoded
1060  *         null terminated C string is written.
1061  *  @param stri Seed7 UTF-32 string to be converted.
1062  *  @param err_info Unchanged if the function succeeds, and
1063  *                  RANGE_ERROR if stri contains a null character
1064  *                        or a character that is higher than the
1065  *                        highest allowed Unicode character (U+10FFFF).
1066  */
conv_to_cstri8(cstriType cstri,const const_striType stri,errInfoType * err_info)1067 void conv_to_cstri8 (cstriType cstri, const const_striType stri,
1068     errInfoType *err_info)
1069 
1070   { /* conv_to_cstri8 */
1071     stri_to_os_utf8((ustriType) cstri, stri->mem, stri->size, err_info);
1072   } /* conv_to_cstri8 */
1073 
1074 
1075 
1076 /**
1077  *  Convert an UTF-32 encoded string to an UTF-16 encoded string.
1078  *  The source and destination strings are not '\0' terminated.
1079  *  The memory for the destination out_wstri is not allocated.
1080  *  @param out_wstri Destination of the UTF-16 encoded string.
1081  *  @param strelem UTF-32 encoded string to be converted.
1082  *  @param len Number of UTF-32 characters in strelem.
1083  *  @param err_info Unchanged if the function succeeds, and
1084  *                  RANGE_ERROR if *strelem contains a character
1085  *                        that is higher than the highest allowed
1086  *                        Unicode character (U+10FFFF).
1087  *  @return the length of the converted UTF-16 string in characters.
1088  */
stri_to_utf16(const wstriType out_wstri,register const strElemType * strelem,memSizeType len,errInfoType * const err_info)1089 memSizeType stri_to_utf16 (const wstriType out_wstri,
1090     register const strElemType *strelem, memSizeType len,
1091     errInfoType *const err_info)
1092 
1093   {
1094     register strElemType ch;
1095     register wstriType wstri;
1096 
1097   /* stri_to_utf16 */
1098     wstri = out_wstri;
1099     for (; len > 0; wstri++, strelem++, len--) {
1100       ch = *strelem;
1101       if (likely(ch <= 0xFFFF)) {
1102         *wstri = (wcharType) ch;
1103       } else if (ch <= 0x10FFFF) {
1104         ch -= 0x10000;
1105         *wstri = (wcharType) (0xD800 | (ch >> 10));
1106         wstri++;
1107         *wstri = (wcharType) (0xDC00 | (ch & 0x3FF));
1108       } else {
1109         logError(printf("stri_to_utf16: Non-Unicode character "
1110                         "in string ('\\" FMT_U32 ";').\n",
1111                         ch););
1112         *err_info = RANGE_ERROR;
1113         len = 1;
1114       } /* if */
1115     } /* for */
1116     return (memSizeType) (wstri - out_wstri);
1117   } /* stri_to_utf16 */
1118 
1119 
1120 
memcpy_to_wstri(wstriType dest,const char * src,memSizeType len)1121 void memcpy_to_wstri (wstriType dest, const char *src, memSizeType len)
1122 
1123   { /* memcpy_to_wstri */
1124     for (; len > 0; src++, dest++, len--) {
1125       *dest = (wcharType) *src;
1126     } /* for */
1127   } /* memcpy_to_wstri */
1128 
1129 
1130 
1131 #ifdef OS_STRI_WCHAR
conv_to_os_stri(register os_striType os_stri,register const strElemType * strelem,memSizeType len,errInfoType * const err_info)1132 static inline boolType conv_to_os_stri (register os_striType os_stri,
1133     register const strElemType *strelem, memSizeType len,
1134     errInfoType *const err_info)
1135 
1136   {
1137     register strElemType ch;
1138     boolType okay = TRUE;
1139 
1140   /* conv_to_os_stri */
1141     logFunction(printf("conv_to_os_stri(*, \"%s\")\n",
1142                 striCharsAsUnquotedCStri(strelem, len)););
1143     for (; len > 0; os_stri++, strelem++, len--) {
1144       ch = *strelem;
1145       if (likely(ch <= 0xFFFF)) {
1146         if (unlikely(ch == '\0')) {
1147           logError(printf("conv_to_os_stri: Null character ('\\0;') in string.\n"););
1148           *err_info = RANGE_ERROR;
1149           okay = FALSE;
1150           len = 1;
1151         } else {
1152           *os_stri = (os_charType) ch;
1153         } /* if */
1154       } else if (ch <= 0x10FFFF) {
1155         ch -= 0x10000;
1156         *os_stri = (os_charType) (0xD800 | (ch >> 10));
1157         os_stri++;
1158         *os_stri = (os_charType) (0xDC00 | (ch & 0x3FF));
1159       } else {
1160         logError(printf("conv_to_os_stri: "
1161                         "Non-Unicode character ('\\" FMT_U32 ";') in string.\n",
1162                         ch););
1163         *err_info = RANGE_ERROR;
1164         okay = FALSE;
1165         len = 1;
1166       } /* if */
1167     } /* for */
1168     *os_stri = '\0';
1169     logFunction(printf("conv_to_os_stri --> %d (err_info=%d)\n",
1170                        okay, *err_info););
1171     return okay;
1172   } /* conv_to_os_stri */
1173 
1174 
1175 
1176 #elif defined OS_STRI_USES_CODE_PAGE
1177 
1178 static const unsigned char map_to_437_160[] = {
1179 /*  160 */  255,  173,  155,  156,  '?',  157,  '?',  '?',  '?',  '?',
1180 /*  170 */  166,  174,  170,  '?',  '?',  '?',  248,  241,  253,  '?',
1181 /*  180 */  '?',  230,  '?',  250,  '?',  '?',  167,  175,  172,  171,
1182 /*  190 */  '?',  168,  '?',  '?',  '?',  '?',  142,  143,  146,  128,
1183 /*  200 */  '?',  144,  '?',  '?',  '?',  '?',  '?',  '?',  '?',  165,
1184 /*  210 */  '?',  '?',  '?',  '?',  153,  '?',  '?',  '?',  '?',  '?',
1185 /*  220 */  154,  '?',  '?',  225,  133,  160,  131,  '?',  132,  134,
1186 /*  230 */  145,  135,  138,  130,  136,  137,  141,  161,  140,  139,
1187 /*  240 */  '?',  164,  149,  162,  147,  '?',  148,  246,  '?',  151,
1188 /*  250 */  163,  150,  129,  '?',  '?',  152};
1189 
1190 static const unsigned char map_to_437_915[] = {
1191 /*  910 */                                226,  '?',  '?',  '?',  '?',
1192 /*  920 */  233,  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1193 /*  930 */  '?',  228,  '?',  '?',  232,  '?',  '?',  234,  '?',  '?',
1194 /*  940 */  '?',  '?',  '?',  '?',  '?',  224,  '?',  '?',  235,  238,
1195 /*  950 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1196 /*  960 */  227,  '?',  '?',  229,  231,  '?',  237};
1197 
1198 static const unsigned char map_to_437_9472[] = {
1199 /* 9470 */              196,  '?',  179,  '?',  '?',  '?',  '?',  '?',
1200 /* 9480 */  '?',  '?',  '?',  '?',  218,  '?',  '?',  '?',  191,  '?',
1201 /* 9490 */  '?',  '?',  192,  '?',  '?',  '?',  217,  '?',  '?',  '?',
1202 /* 9500 */  195,  '?',  '?',  '?',  '?',  '?',  '?',  '?',  180,  '?',
1203 /* 9510 */  '?',  '?',  '?',  '?',  '?',  '?',  194,  '?',  '?',  '?',
1204 /* 9520 */  '?',  '?',  '?',  '?',  193,  '?',  '?',  '?',  '?',  '?',
1205 /* 9530 */  '?',  '?',  197,  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1206 /* 9540 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1207 /* 9550 */  '?',  '?',  205,  186,  213,  214,  201,  184,  183,  187,
1208 /* 9560 */  212,  211,  200,  190,  189,  188,  198,  199,  204,  181,
1209 /* 9570 */  182,  185,  209,  210,  203,  207,  208,  202,  216,  215,
1210 /* 9580 */  206,  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1211 /* 9590 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1212 /* 9600 */  223,  '?',  '?',  '?',  220,  '?',  '?',  '?',  219,  '?',
1213 /* 9610 */  '?',  '?',  221,  '?',  '?',  '?',  222,  176,  177,  178,
1214 /* 9620 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1215 /* 9630 */  '?',  '?',  254};
1216 
1217 static const unsigned char map_to_850_160[] = {
1218 /*  160 */  255,  173,  189,  156,  207,  190,  221,  245,  249,  184,
1219 /*  170 */  166,  174,  170,  240,  169,  238,  248,  241,  253,  252,
1220 /*  180 */  239,  230,  244,  250,  247,  251,  167,  175,  172,  171,
1221 /*  190 */  243,  168,  183,  181,  182,  199,  142,  143,  146,  128,
1222 /*  200 */  212,  144,  210,  211,  222,  214,  215,  216,  209,  165,
1223 /*  210 */  227,  224,  226,  229,  153,  158,  157,  235,  233,  234,
1224 /*  220 */  154,  237,  232,  225,  133,  160,  131,  198,  132,  134,
1225 /*  230 */  145,  135,  138,  130,  136,  137,  141,  161,  140,  139,
1226 /*  240 */  208,  164,  149,  162,  147,  228,  148,  246,  155,  151,
1227 /*  250 */  163,  150,  129,  236,  231,  152};
1228 
1229 static const unsigned char map_to_850_9472[] = {
1230 /* 9470 */              196,  '?',  179,  '?',  '?',  '?',  '?',  '?',
1231 /* 9480 */  '?',  '?',  '?',  '?',  218,  '?',  '?',  '?',  191,  '?',
1232 /* 9490 */  '?',  '?',  192,  '?',  '?',  '?',  217,  '?',  '?',  '?',
1233 /* 9500 */  195,  '?',  '?',  '?',  '?',  '?',  '?',  '?',  180,  '?',
1234 /* 9510 */  '?',  '?',  '?',  '?',  '?',  '?',  194,  '?',  '?',  '?',
1235 /* 9520 */  '?',  '?',  '?',  '?',  193,  '?',  '?',  '?',  '?',  '?',
1236 /* 9530 */  '?',  '?',  197,  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1237 /* 9540 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1238 /* 9550 */  '?',  '?',  205,  186,  '?',  '?',  201,  '?',  '?',  187,
1239 /* 9560 */  '?',  '?',  200,  '?',  '?',  188,  '?',  '?',  204,  '?',
1240 /* 9570 */  '?',  185,  '?',  '?',  203,  '?',  '?',  202,  '?',  '?',
1241 /* 9580 */  206,  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1242 /* 9590 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1243 /* 9600 */  223,  '?',  '?',  '?',  220,  '?',  '?',  '?',  219,  '?',
1244 /* 9610 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  176,  177,  178,
1245 /* 9620 */  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
1246 /* 9630 */  '?',  '?',  254};
1247 
1248 
1249 
conv_to_os_stri(os_striType os_stri,const strElemType * strelem,memSizeType len,errInfoType * err_info)1250 static inline boolType conv_to_os_stri (os_striType os_stri,
1251     const strElemType *strelem, memSizeType len, errInfoType *err_info)
1252 
1253   {
1254     unsigned char ch;
1255     boolType okay = TRUE;
1256 
1257   /* conv_to_os_stri */
1258     logFunction(printf("conv_to_os_stri(*, \"%s\")\n",
1259                 striCharsAsUnquotedCStri(strelem, len)););
1260     if (code_page == 437) {
1261       for (; len > 0; os_stri++, strelem++, len--) {
1262         if (*strelem <= 127) {
1263           if (unlikely(*strelem == '\0')) {
1264             logError(printf("conv_to_os_stri: Null character ('\\0;') in string.\n"););
1265             *err_info = RANGE_ERROR;
1266             okay = FALSE;
1267             len = 1;
1268           } else {
1269             *os_stri = (os_charType) *strelem;
1270           } /* if */
1271         } else {
1272           if (*strelem >= 160 && *strelem <= 255) {
1273             ch = map_to_437_160[*strelem - 160];
1274           } else if (*strelem >= 915 && *strelem <= 966) {
1275             ch = map_to_437_915[*strelem - 915];
1276           } else if (*strelem >= 9472 && *strelem <= 9632) {
1277             ch = map_to_437_9472[*strelem - 9472];
1278           } else {
1279             switch (*strelem) {
1280               case  402: ch = 159; break;
1281               case 8319: ch = 252; break;
1282               case 8359: ch = 158; break;
1283               case 8729: ch = 249; break;
1284               case 8730: ch = 251; break;
1285               case 8734: ch = 236; break;
1286               case 8745: ch = 239; break;
1287               case 8776: ch = 247; break;
1288               case 8801: ch = 240; break;
1289               case 8804: ch = 243; break;
1290               case 8805: ch = 242; break;
1291               case 8976: ch = 169; break;
1292               case 8992: ch = 244; break;
1293               case 8993: ch = 245; break;
1294               default:   ch = '?'; break;
1295             } /* switch */
1296           } /* if */
1297           *os_stri = (os_charType) ch;
1298           if (unlikely(ch == '?')) {
1299             *err_info = RANGE_ERROR;
1300             okay = FALSE;
1301             /* The conversion continues. The caller  */
1302             /* can decide to use the question marks. */
1303           } /* if */
1304         } /* if */
1305       } /* for */
1306     } else if (code_page == 850) {
1307       for (; len > 0; os_stri++, strelem++, len--) {
1308         if (*strelem <= 127) {
1309           if (unlikely(*strelem == '\0')) {
1310             logError(printf("conv_to_os_stri: Null character ('\\0;') in string.\n"););
1311             *err_info = RANGE_ERROR;
1312             okay = FALSE;
1313             len = 1;
1314           } else {
1315             *os_stri = (os_charType) *strelem;
1316           } /* if */
1317         } else {
1318           if (*strelem >= 160 && *strelem <= 255) {
1319             ch = map_to_850_160[*strelem - 160];
1320           } else if (*strelem >= 9472 && *strelem <= 9632) {
1321             ch = map_to_850_9472[*strelem - 9472];
1322           } else {
1323             switch (*strelem) {
1324               case 8215: ch = 242; break;
1325               case 305:  ch = 213; break;
1326               case 402:  ch = 159; break;
1327               default:   ch = '?'; break;
1328             } /* switch */
1329           } /* if */
1330           *os_stri = (os_charType) ch;
1331           if (unlikely(ch == '?')) {
1332             *err_info = RANGE_ERROR;
1333             okay = FALSE;
1334             /* The conversion continues. The caller  */
1335             /* can decide to use the question marks. */
1336           } /* if */
1337         } /* if */
1338       } /* for */
1339     } else {
1340       *err_info = RANGE_ERROR;
1341       okay = FALSE;
1342     } /* if */
1343     *os_stri = '\0';
1344     logFunction(printf("conv_to_os_stri --> %d (err_info=%d)\n",
1345                        okay, *err_info););
1346     return okay;
1347   } /* conv_to_os_stri */
1348 
1349 #elif defined OS_STRI_UTF8
1350 
1351 
1352 
conv_to_os_stri(const os_striType os_stri,const strElemType * const strelem,const memSizeType len,errInfoType * err_info)1353 static inline boolType conv_to_os_stri (const os_striType os_stri,
1354     const strElemType *const strelem, const memSizeType len,
1355     errInfoType *err_info)
1356 
1357   {
1358     boolType okay;
1359 
1360   /* conv_to_os_stri */
1361     logFunction(printf("conv_to_os_stri(*, \"%s\")\n",
1362                 striCharsAsUnquotedCStri(strelem, len)););
1363     okay = stri_to_os_utf8((ustriType) os_stri, strelem, len, err_info);
1364     logFunction(printf("conv_to_os_stri --> %d (err_info=%d)\n",
1365                        okay, *err_info););
1366     return okay;
1367   } /* conv_to_os_stri */
1368 
1369 #else
1370 
1371 
1372 
conv_to_os_stri(const os_striType os_stri,const strElemType * const strelem,memSizeType len,errInfoType * err_info)1373 static inline boolType conv_to_os_stri (const os_striType os_stri,
1374     const strElemType *const strelem, memSizeType len, errInfoType *err_info)
1375 
1376   {
1377     boolType okay = TRUE;
1378 
1379   /* conv_to_os_stri */
1380     logFunction(printf("conv_to_os_stri(*, \"%s\")\n",
1381                 striCharsAsUnquotedCStri(strelem, len)););
1382     while (len != 0) {
1383       len--;
1384       if (unlikely(strelem[len] == '\0' || strelem[len] >= 256)) {
1385         logError(printf("conv_to_os_stri: "
1386                         "Null character or non-ISO-8859-1 character "
1387                         "in string ('\\" FMT_U32 ";').\n",
1388                         str[len]););
1389         *err_info = RANGE_ERROR;
1390         okay = FALSE;
1391       } /* if */
1392       os_stri[len] = (os_charType) strelem[len];
1393     } /* while */
1394     *os_stri = '\0';
1395     logFunction(printf("conv_to_os_stri --> %d (err_info=%d)\n",
1396                        okay, *err_info););
1397     return okay;
1398   } /* conv_to_os_stri */
1399 
1400 #endif
1401 
1402 
1403 
wstri_expand(strElemType * const dest_stri,const_wstriType wstri,memSizeType len)1404 static memSizeType wstri_expand (strElemType *const dest_stri,
1405     const_wstriType wstri, memSizeType len)
1406 
1407   {
1408     strElemType *stri;
1409     wcharType ch1;
1410     wcharType ch2;
1411 
1412   /* wstri_expand */
1413     stri = dest_stri;
1414     for (; len > 0; stri++, wstri++, len--) {
1415       ch1 = *wstri;
1416       if (unlikely(ch1 >= 0xD800 && ch1 <= 0xDBFF)) {
1417         ch2 = wstri[1];
1418         if (likely(ch2 >= 0xDC00 && ch2 <= 0xDFFF)) {
1419           *stri = ((((strElemType) ch1 - 0xD800) << 10) +
1420                     ((strElemType) ch2 - 0xDC00) + 0x10000);
1421           wstri++;
1422           len--;
1423         } else {
1424           *stri = (strElemType) ch1;
1425         } /* if */
1426       } else {
1427         *stri = (strElemType) ch1;
1428       } /* if */
1429     } /* for */
1430     return (memSizeType) (stri - dest_stri);
1431   } /* wstri_expand */
1432 
1433 
1434 
1435 #if defined OS_STRI_WCHAR
1436 /**
1437  *  Convert an os_striType string with length to a Seed7 UTF-32 string.
1438  *  Many system calls return os_striType data with length. System calls
1439  *  are defined in "version.h" and "os_decls.h". They are prefixed
1440  *  with os_ and use strings of the type os_striType. Depending on the
1441  *  operating system os_striType can describe byte or wide char strings.
1442  *  The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
1443  *  @param os_stri Possibly binary string (may contain null characters).
1444  *  @param length Length of os_stri in characters.
1445  *  @return a Seed7 UTF-32 string, or
1446  *          NULL if an error occurred.
1447  */
conv_from_os_stri(const const_os_striType os_stri,memSizeType length)1448 striType conv_from_os_stri (const const_os_striType os_stri,
1449     memSizeType length)
1450 
1451   {
1452     memSizeType stri_size;
1453     striType resized_stri;
1454     striType stri;
1455 
1456   /* conv_from_os_stri */
1457     if (likely(ALLOC_STRI_CHECK_SIZE(stri, length))) {
1458       stri_size = wstri_expand(stri->mem, (const_wstriType) os_stri, length);
1459       stri->size = stri_size;
1460       if (stri_size != length) {
1461         REALLOC_STRI_SIZE_SMALLER(resized_stri, stri, length, stri_size);
1462         if (unlikely(resized_stri == NULL)) {
1463           FREE_STRI(stri, length);
1464           stri = NULL;
1465         } else {
1466           stri = resized_stri;
1467           COUNT3_STRI(length, stri_size);
1468         } /* if */
1469       } /* if */
1470     } /* if */
1471     return stri;
1472   } /* conv_from_os_stri */
1473 
1474 
1475 
1476 #elif defined OS_STRI_USES_CODE_PAGE
1477 
1478 static const strElemType map_from_437[] = {
1479 /*   0 */    0,    1,    2,    3,    4,    5,    6,    7,    8,    9,
1480 /*  10 */   10,   11,   12,   13,   14,   15,   16,   17,   18,   19,
1481 /*  20 */   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,
1482 /*  30 */   30,   31,  ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
1483 /*  40 */  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',  '0',  '1',
1484 /*  50 */  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',
1485 /*  60 */  '<',  '=',  '>',  '?',  '@',  'A',  'B',  'C',  'D',  'E',
1486 /*  70 */  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
1487 /*  80 */  'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',
1488 /*  90 */  'Z',  '[', '\\',  ']',  '^',  '_',  '`',  'a',  'b',  'c',
1489 /* 100 */  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',
1490 /* 110 */  'n',  'o',  'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
1491 /* 120 */  'x',  'y',  'z',  '{',  '|',  '}',  '~',  127,  199,  252,
1492 /* 130 */  233,  226,  228,  224,  229,  231,  234,  235,  232,  239,
1493 /* 140 */  238,  236,  196,  197,  201,  230,  198,  244,  246,  242,
1494 /* 150 */  251,  249,  255,  214,  220,  162,  163,  165, 8359,  402,
1495 /* 160 */  225,  237,  243,  250,  241,  209,  170,  186,  191, 8976,
1496 /* 170 */  172,  189,  188,  161,  171,  187, 9617, 9618, 9619, 9474,
1497 /* 180 */ 9508, 9569, 9570, 9558, 9557, 9571, 9553, 9559, 9565, 9564,
1498 /* 190 */ 9563, 9488, 9492, 9524, 9516, 9500, 9472, 9532, 9566, 9567,
1499 /* 200 */ 9562, 9556, 9577, 9574, 9568, 9552, 9580, 9575, 9576, 9572,
1500 /* 210 */ 9573, 9561, 9560, 9554, 9555, 9579, 9578, 9496, 9484, 9608,
1501 /* 220 */ 9604, 9612, 9616, 9600,  945,  223,  915,  960,  931,  963,
1502 /* 230 */  181,  964,  934,  920,  937,  948, 8734,  966,  949, 8745,
1503 /* 240 */ 8801,  177, 8805, 8804, 8992, 8993,  247, 8776,  176, 8729,
1504 /* 250 */  183, 8730, 8319,  178, 9632,  160};
1505 
1506 static const strElemType map_from_850[] = {
1507 /*   0 */    0,    1,    2,    3,    4,    5,    6,    7,    8,    9,
1508 /*  10 */   10,   11,   12,   13,   14,   15,   16,   17,   18,   19,
1509 /*  20 */   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,
1510 /*  30 */   30,   31,  ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
1511 /*  40 */  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',  '0',  '1',
1512 /*  50 */  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',
1513 /*  60 */  '<',  '=',  '>',  '?',  '@',  'A',  'B',  'C',  'D',  'E',
1514 /*  70 */  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
1515 /*  80 */  'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',
1516 /*  90 */  'Z',  '[', '\\',  ']',  '^',  '_',  '`',  'a',  'b',  'c',
1517 /* 100 */  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',
1518 /* 110 */  'n',  'o',  'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
1519 /* 120 */  'x',  'y',  'z',  '{',  '|',  '}',  '~',  127,  199,  252,
1520 /* 130 */  233,  226,  228,  224,  229,  231,  234,  235,  232,  239,
1521 /* 140 */  238,  236,  196,  197,  201,  230,  198,  244,  246,  242,
1522 /* 150 */  251,  249,  255,  214,  220,  248,  163,  216,  215,  402,
1523 /* 160 */  225,  237,  243,  250,  241,  209,  170,  186,  191,  174,
1524 /* 170 */  172,  189,  188,  161,  171,  187, 9617, 9618, 9619, 9474,
1525 /* 180 */ 9508,  193,  194,  192,  169, 9571, 9553, 9559, 9565,  162,
1526 /* 190 */  165, 9488, 9492, 9524, 9516, 9500, 9472, 9532,  227,  195,
1527 /* 200 */ 9562, 9556, 9577, 9574, 9568, 9552, 9580,  164,  240,  208,
1528 /* 210 */  202,  203,  200,  305,  205,  206,  207, 9496, 9484, 9608,
1529 /* 220 */ 9604,  166,  204, 9600,  211,  223,  212,  210,  245,  213,
1530 /* 230 */  181,  254,  222,  218,  219,  217,  253,  221,  175,  180,
1531 /* 240 */  173,  177, 8215,  190,  182,  167,  247,  184,  176,  168,
1532 /* 250 */  183,  185,  179,  178, 9632,  160};
1533 
1534 
1535 
1536 /**
1537  *  Convert an os_striType string with length to a Seed7 UTF-32 string.
1538  *  Many system calls return os_striType data with length. System calls
1539  *  are defined in "version.h" and "os_decls.h". They are prefixed
1540  *  with os_ and use strings of the type os_striType. Depending on the
1541  *  operating system os_striType can describe byte or wide char strings.
1542  *  The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
1543  *  @param os_stri Possibly binary string (may contain null characters).
1544  *  @param length Length of os_stri in characters.
1545  *  @return a Seed7 UTF-32 string, or
1546  *          NULL if an error occurred.
1547  */
conv_from_os_stri(const const_os_striType os_stri,memSizeType length)1548 striType conv_from_os_stri (const const_os_striType os_stri,
1549     memSizeType length)
1550 
1551   {
1552     memSizeType pos;
1553     striType stri;
1554 
1555   /* conv_from_os_stri */
1556     if (likely(ALLOC_STRI_CHECK_SIZE(stri, length))) {
1557       stri->size = length;
1558       if (code_page == 437) {
1559         for (pos = 0; pos < length; pos++) {
1560           stri->mem[pos] = map_from_437[(unsigned char) os_stri[pos]];
1561         } /* for */
1562       } else if (code_page == 850) {
1563         for (pos = 0; pos < length; pos++) {
1564           stri->mem[pos] = map_from_850[(unsigned char) os_stri[pos]];
1565         } /* for */
1566       } else {
1567         FREE_STRI(stri, length);
1568         stri = NULL;
1569       } /* if */
1570     } /* if */
1571     return stri;
1572   } /* conv_from_os_stri */
1573 
1574 #elif defined OS_STRI_UTF8
1575 
1576 
1577 
1578 /**
1579  *  Convert an os_striType string with length to a Seed7 UTF-32 string.
1580  *  Many system calls return os_striType data with length. System calls
1581  *  are defined in "version.h" and "os_decls.h". They are prefixed
1582  *  with os_ and use strings of the type os_striType. Depending on the
1583  *  operating system os_striType can describe byte or wide char strings.
1584  *  The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
1585  *  @param os_stri Possibly binary string (may contain null characters).
1586  *  @param length Length of os_stri in characters.
1587  *  @return a Seed7 UTF-32 string, or
1588  *          NULL if an error occurred.
1589  */
conv_from_os_stri(const const_os_striType os_stri,memSizeType length)1590 striType conv_from_os_stri (const const_os_striType os_stri,
1591     memSizeType length)
1592 
1593   {
1594     memSizeType stri_size;
1595     striType resized_stri;
1596     striType stri;
1597 
1598   /* conv_from_os_stri */
1599     if (likely(ALLOC_STRI_CHECK_SIZE(stri, length))) {
1600       if (likely(utf8_to_stri(stri->mem, &stri_size, (const_ustriType) os_stri, length) == 0)) {
1601         stri->size = stri_size;
1602         if (stri_size != length) {
1603           REALLOC_STRI_SIZE_SMALLER(resized_stri, stri, length, stri_size);
1604           if (unlikely(resized_stri == NULL)) {
1605             FREE_STRI(stri, length);
1606             stri = NULL;
1607           } else {
1608             stri = resized_stri;
1609             COUNT3_STRI(length, stri_size);
1610           } /* if */
1611         } /* if */
1612       } else {
1613         /* Assume that os_stri is encoded in Latin-1 instead of UTF-8. */
1614         stri->size = length;
1615         memcpy_to_strelem(stri->mem, (const_ustriType) os_stri, length);
1616       } /* if */
1617     } /* if */
1618     return stri;
1619   } /* conv_from_os_stri */
1620 
1621 #else
1622 
1623 
1624 
1625 /**
1626  *  Convert an os_striType string with length to a Seed7 UTF-32 string.
1627  *  Many system calls return os_striType data with length. System calls
1628  *  are defined in "version.h" and "os_decls.h". They are prefixed
1629  *  with os_ and use strings of the type os_striType. Depending on the
1630  *  operating system os_striType can describe byte or wide char strings.
1631  *  The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
1632  *  @param os_stri Possibly binary string (may contain null characters).
1633  *  @param length Length of os_stri in characters.
1634  *  @return a Seed7 UTF-32 string, or
1635  *          NULL if an error occurred.
1636  */
conv_from_os_stri(const const_os_striType os_stri,memSizeType length)1637 striType conv_from_os_stri (const const_os_striType os_stri,
1638     memSizeType length)
1639 
1640   {
1641     striType stri;
1642 
1643   /* conv_from_os_stri */
1644     if (likely(ALLOC_STRI_CHECK_SIZE(stri, length))) {
1645       memcpy_to_strelem(stri->mem, (const_ustriType) os_stri, length);
1646       stri->size = length;
1647     } /* if */
1648     return stri;
1649   } /* conv_from_os_stri */
1650 
1651 #endif
1652 
1653 
1654 
1655 /**
1656  *  Create an ISO-8859-1 encoded C string from a Seed7 UTF-32 string.
1657  *  The memory for the zero byte terminated C string is allocated.
1658  *  The C string result must be freed with the macro free_cstri().
1659  *  @param stri Seed7 UTF-32 string to be converted.
1660  *  @param err_info Unchanged if the function succeeds, and
1661  *                  MEMORY_ERROR if the memory allocation failed, and
1662  *                  RANGE_ERROR if stri contains a null character
1663  *                        or a character that is higher than the
1664  *                        highest allowed ISO-8859-1 character (255).
1665  *  @return an ISO-8859-1 encoded null terminated C string, or
1666  *          NULL if the memory allocation failed or the
1667  *          conversion failed (the error is indicated by err_info).
1668  */
stri_to_cstri(const const_striType stri,errInfoType * err_info)1669 cstriType stri_to_cstri (const const_striType stri, errInfoType *err_info)
1670 
1671   {
1672     const strElemType *str;
1673     memSizeType pos;
1674     cstriType cstri;
1675 
1676   /* stri_to_cstri */
1677     if (unlikely(!ALLOC_CSTRI(cstri, stri->size))) {
1678       *err_info = MEMORY_ERROR;
1679     } else {
1680       str = stri->mem;
1681       for (pos = stri->size; pos != 0; ) {
1682         pos--;
1683         if (unlikely(str[pos] == 0 || str[pos] >= 256)) {
1684           UNALLOC_CSTRI(cstri, stri->size);
1685           logError(printf("stri_to_cstri: "
1686                           "Null character or non-ISO-8859-1 character "
1687                           "in string ('\\" FMT_U32 ";').\n",
1688                           str[pos]););
1689           *err_info = RANGE_ERROR;
1690           return NULL;
1691         } /* if */
1692         cstri[pos] = (char) (ucharType) str[pos];
1693       } /* for */
1694       cstri[stri->size] = '\0';
1695     } /* if */
1696     return cstri;
1697   } /* stri_to_cstri */
1698 
1699 
1700 
1701 /**
1702  *  Create an UTF-8 encoded C string from a Seed7 UTF-32 string.
1703  *  The memory for the zero byte terminated C string is allocated.
1704  *  The C string result must be freed with the macro free_cstri8().
1705  *  This function is intended to create temporary strings, that
1706  *  are used as parameters. To get good performance the allocated
1707  *  memory for the C string is oversized.
1708  *  @param stri Seed7 UTF-32 string to be converted.
1709  *  @param err_info Unchanged if the function succeeds, and
1710  *                  MEMORY_ERROR if the memory allocation failed, and
1711  *                  RANGE_ERROR if stri contains a null character
1712  *                        or a character that is higher than the
1713  *                        highest allowed Unicode character (U+10FFFF).
1714  *  @return an UTF-8 encoded null terminated C string, or
1715  *          NULL if the memory allocation failed or the
1716  *          conversion failed (the error is indicated by err_info).
1717  */
stri_to_cstri8(const const_striType stri,errInfoType * err_info)1718 cstriType stri_to_cstri8 (const const_striType stri, errInfoType *err_info)
1719 
1720   {
1721     cstriType cstri;
1722 
1723   /* stri_to_cstri8 */
1724     if (unlikely(stri->size > MAX_CSTRI_LEN / MAX_UTF8_EXPANSION_FACTOR ||
1725                  !ALLOC_CSTRI(cstri, max_utf8_size(stri->size)))) {
1726       *err_info = MEMORY_ERROR;
1727       cstri = NULL;
1728     } else {
1729       if (unlikely(!stri_to_os_utf8((ustriType) cstri, stri->mem,
1730                                     stri->size, err_info))) {
1731         free_cstri8(cstri, stri);
1732         cstri = NULL;
1733       } /* if */
1734     } /* if */
1735     return cstri;
1736   } /* stri_to_cstri8 */
1737 
1738 
1739 
1740 /**
1741  *  Create an UTF-8 encoded C string buffer from a Seed7 UTF-32 string.
1742  *  The memory for the zero byte terminated C string is allocated.
1743  *  Zero bytes inside the string are copied to the C string.
1744  *  The C string result must be freed with the macro free_cstri8().
1745  *  This function is intended to create temporary strings, that
1746  *  are used as parameters. To get good performance the allocated
1747  *  memory for the C string is oversized.
1748  *  @param stri Seed7 UTF-32 string to be converted.
1749  *  @param length Place to return the length of the result (without '\0').
1750  *  @return an UTF-8 encoded null terminated C string, or
1751  *          NULL if the memory allocation failed.
1752  */
stri_to_cstri8_buf(const const_striType stri,memSizeType * length)1753 cstriType stri_to_cstri8_buf (const const_striType stri, memSizeType *length)
1754 
1755   {
1756     cstriType cstri;
1757 
1758   /* stri_to_cstri8_buf */
1759     if (unlikely(stri->size > MAX_CSTRI_LEN / MAX_UTF8_EXPANSION_FACTOR ||
1760                  !ALLOC_CSTRI(cstri, max_utf8_size(stri->size)))) {
1761       cstri = NULL;
1762     } else {
1763       *length = stri_to_utf8((ustriType) cstri, stri->mem, stri->size);
1764       cstri[*length] = '\0';
1765     } /* if */
1766     return cstri;
1767   } /* stri_to_cstri8_buf */
1768 
1769 
1770 
1771 /**
1772  *  Create an ISO-8859-1 encoded bstring from a Seed7 UTF-32 string.
1773  *  The memory for the bstring is allocated. No zero byte is added
1774  *  to the end of the bstring. No special action is done, if the
1775  *  UTF-32 string contains a null character.
1776  *  @param stri Seed7 UTF-32 string to be converted.
1777  *  @param err_info Unchanged if the function succeeds, and
1778  *                  MEMORY_ERROR if the memory allocation failed, and
1779  *                  RANGE_ERROR if stri contains a character
1780  *                        that is higher than the highest
1781  *                        allowed ISO-8859-1 character (255).
1782  *  @return an ISO-8859-1 encoded bstring, or
1783  *          NULL if the memory allocation failed or the
1784  *          conversion failed (the error is indicated by err_info).
1785  */
stri_to_bstri(const const_striType stri,errInfoType * err_info)1786 bstriType stri_to_bstri (const const_striType stri, errInfoType *err_info)
1787 
1788   {
1789     bstriType bstri;
1790 
1791   /* stri_to_bstri */
1792     if (unlikely(!ALLOC_BSTRI_SIZE_OK(bstri, stri->size))) {
1793       *err_info = MEMORY_ERROR;
1794     } else {
1795       bstri->size = stri->size;
1796       if (unlikely(memcpy_from_strelem(bstri->mem, stri->mem, stri->size))) {
1797         FREE_BSTRI(bstri, bstri->size);
1798         *err_info = RANGE_ERROR;
1799         return NULL;
1800       } /* if */
1801     } /* if */
1802     return bstri;
1803   } /* stri_to_bstri */
1804 
1805 
1806 
1807 /**
1808  *  Create an UTF-8 encoded bstring from a Seed7 UTF-32 string.
1809  *  The memory for the bstring is allocated. No zero byte is added
1810  *  to the end of the bstring. No special action is done, if
1811  *  the original string contains a null character.
1812  *  @param stri Seed7 UTF-32 string to be converted.
1813  *  @return an UTF-8 encoded bstring, or
1814  *          NULL if the memory allocation failed.
1815  */
stri_to_bstri8(const const_striType stri)1816 bstriType stri_to_bstri8 (const const_striType stri)
1817 
1818   {
1819     bstriType resized_bstri;
1820     bstriType bstri;
1821 
1822   /* stri_to_bstri8 */
1823     if (unlikely(stri->size > MAX_BSTRI_LEN / MAX_UTF8_EXPANSION_FACTOR)) {
1824       bstri = NULL;
1825     } else if (likely(ALLOC_BSTRI_SIZE_OK(bstri, max_utf8_size(stri->size)))) {
1826       bstri->size = stri_to_utf8(bstri->mem, stri->mem, stri->size);
1827       REALLOC_BSTRI_SIZE_OK(resized_bstri, bstri, max_utf8_size(stri->size), bstri->size);
1828       if (unlikely(resized_bstri == NULL)) {
1829         FREE_BSTRI(bstri, max_utf8_size(stri->size));
1830         bstri = NULL;
1831       } else {
1832         bstri = resized_bstri;
1833         COUNT3_BSTRI(max_utf8_size(stri->size), bstri->size);
1834       } /* if */
1835     } /* if */
1836     return bstri;
1837   } /* stri_to_bstri8 */
1838 
1839 
1840 
1841 #ifdef CONSOLE_WCHAR
1842 /**
1843  *  Create an UTF-16 encoded bstring from a Seed7 UTF-32 string.
1844  *  The memory for the bstring is allocated. No zero byte is added
1845  *  to the end of the bstring. No special action is done, if
1846  *  the original string contains a null character.
1847  *  @param stri Seed7 UTF-32 string to be converted.
1848  *  @return an UTF-8 encoded bstring, or
1849  *          NULL if the memory allocation failed.
1850  */
stri_to_bstriw(const const_striType stri,errInfoType * err_info)1851 bstriType stri_to_bstriw (const const_striType stri, errInfoType *err_info)
1852 
1853   {
1854     memSizeType wstri_size;
1855     bstriType resized_bstri;
1856     bstriType bstri;
1857 
1858   /* stri_to_bstriw */
1859     if (stri->size > ((MAX_BSTRI_LEN / sizeof(os_charType)) / SURROGATE_PAIR_FACTOR)) {
1860       *err_info = MEMORY_ERROR;
1861       bstri = NULL;
1862     } else if (unlikely(!ALLOC_BSTRI_SIZE_OK(bstri,
1863         stri->size * SURROGATE_PAIR_FACTOR * sizeof(os_charType)))) {
1864       *err_info = MEMORY_ERROR;
1865     } else {
1866       wstri_size = stri_to_utf16((wstriType) bstri->mem, stri->mem, stri->size, err_info);
1867       if (unlikely(*err_info != OKAY_NO_ERROR)) {
1868         FREE_BSTRI(bstri, stri->size * SURROGATE_PAIR_FACTOR * sizeof(os_charType));
1869         bstri = NULL;
1870       } else {
1871         REALLOC_BSTRI_SIZE_OK(resized_bstri, bstri,
1872             stri->size * SURROGATE_PAIR_FACTOR * sizeof(os_charType),
1873             wstri_size * sizeof(os_charType));
1874         if (resized_bstri == NULL) {
1875           FREE_BSTRI(bstri, stri->size * SURROGATE_PAIR_FACTOR * sizeof(os_charType));
1876           bstri = NULL;
1877         } else {
1878           bstri = resized_bstri;
1879           COUNT3_BSTRI(stri->size * SURROGATE_PAIR_FACTOR * sizeof(os_charType),
1880               wstri_size * sizeof(os_charType));
1881           bstri->size = wstri_size * sizeof(os_charType);
1882         } /* if */
1883       } /* if */
1884     } /* if */
1885     return bstri;
1886   } /* stri_to_bstriw */
1887 #endif
1888 
1889 
1890 
1891 #ifdef OUT_OF_ORDER
stri_to_os_bstri(const_striType stri)1892 bstriType stri_to_os_bstri (const_striType stri)
1893 
1894   {
1895     bstriType bstri;
1896 
1897   /* stri_to_os_bstri */
1898     if (unlikely(stri->size > MAX_OS_BSTRI_SIZE)) {
1899       *err_info = MEMORY_ERROR;
1900       result = NULL;
1901     } else if (unlikely(!ALLOC_BSTRI_SIZE_OK(bstri, OS_BSTRI_SIZE(stri->size)))) {
1902       *err_info = MEMORY_ERROR;
1903     } else if (unlikely(!conv_to_os_stri((os_striType) bstri->mem, stri->mem,
1904                                          stri->size, err_info))) {
1905       FREE_BSTRI(bstri, OS_BSTRI_SIZE(stri->size));
1906       result = NULL;
1907     } /* if */
1908     return bstri;
1909   } /* stri_to_os_bstri */
1910 #endif
1911 
1912 
1913 
1914 /**
1915  *  Create an UTF-16 encoded wide string buffer from a Seed7 UTF-32 string.
1916  *  The memory for the zero byte terminated wide string is allocated.
1917  *  The wide string result must be freed with the macro free_wstri().
1918  *  This function is intended to create temporary strings, that
1919  *  are used as parameters. To get good performance the allocated
1920  *  memory for the wide string is oversized.
1921  *  @param stri Seed7 UTF-32 string to be converted.
1922  *  @param length Place to return the character length of the result (without '\0').
1923  *  @param err_info Unchanged if the function succeeds, and
1924  *                  MEMORY_ERROR if the memory allocation failed, and
1925  *                  RANGE_ERROR if stri contains a character
1926  *                        that is higher than the highest
1927  *                        allowed Unicode character (U+10FFFF).
1928  *  @return an UTF-16 encoded null terminated wide string, or
1929  *          NULL if the memory allocation failed or the
1930  *          conversion failed (the error is indicated by err_info).
1931  */
stri_to_wstri_buf(const const_striType stri,memSizeType * length,errInfoType * err_info)1932 wstriType stri_to_wstri_buf (const const_striType stri, memSizeType *length,
1933       errInfoType *err_info)
1934 
1935   {
1936     wstriType wstri;
1937 
1938   /* stri_to_wstri_buf */
1939     if (unlikely(stri->size > MAX_WSTRI_LEN / SURROGATE_PAIR_FACTOR ||
1940                  !ALLOC_WSTRI(wstri, SURROGATE_PAIR_FACTOR * stri->size))) {
1941       *err_info = MEMORY_ERROR;
1942       wstri = NULL;
1943     } else {
1944       *length = stri_to_utf16(wstri, stri->mem, stri->size, err_info);
1945       wstri[*length] = '\0';
1946     } /* if */
1947     return wstri;
1948   } /* stri_to_wstri_buf */
1949 
1950 
1951 
1952 /**
1953  *  Copy an ISO-8859-1 (Latin-1) encoded C string to a Seed7 string.
1954  *  The memory for the UTF-32 encoded Seed7 string is allocated.
1955  *  @param cstri Null terminated ISO-8859-1 encoded C string.
1956  *  @return an UTF-32 encoded Seed7 string, or
1957  *          NULL if the memory allocation failed.
1958  */
cstri_to_stri(const_cstriType cstri)1959 striType cstri_to_stri (const_cstriType cstri)
1960 
1961   {
1962     memSizeType length;
1963     striType stri;
1964 
1965   /* cstri_to_stri */
1966     length = strlen(cstri);
1967     if (likely(ALLOC_STRI_CHECK_SIZE(stri, length))) {
1968       stri->size = length;
1969       memcpy_to_strelem(stri->mem, (const_ustriType) cstri, length);
1970     } /* if */
1971     return stri;
1972   } /* cstri_to_stri */
1973 
1974 
1975 
1976 /**
1977  *  Copy an ISO-8859-1 (Latin-1) encoded C string buffer to a Seed7 string.
1978  *  The memory for the UTF-32 encoded Seed7 string is allocated.
1979  *  @param cstri ISO-8859-1 encoded C string buffer (not null terminated).
1980  *  @param length Byte length of the ISO-8859-1 encoded C string buffer.
1981  *  @return an UTF-32 encoded Seed7 string, or
1982  *          NULL if the memory allocation failed.
1983  */
cstri_buf_to_stri(const_cstriType cstri,memSizeType length)1984 striType cstri_buf_to_stri (const_cstriType cstri, memSizeType length)
1985 
1986   {
1987     striType stri;
1988 
1989   /* cstri_buf_to_stri */
1990     if (likely(ALLOC_STRI_CHECK_SIZE(stri, length))) {
1991       stri->size = length;
1992       memcpy_to_strelem(stri->mem, (const_ustriType) cstri, length);
1993     } /* if */
1994     return stri;
1995   } /* cstri_buf_to_stri */
1996 
1997 
1998 
1999 /**
2000  *  Copy an UTF-8 encoded C string to a Seed7 string.
2001  *  The memory for the UTF-32 encoded Seed7 string is allocated.
2002  *  @param cstri Null terminated UTF-8 encoded C string.
2003  *  @param err_info Unchanged if the function succeeds, and
2004  *                  MEMORY_ERROR if the memory allocation failed, and
2005  *                  RANGE_ERROR if the conversion failed.
2006  *  @return an UTF-32 encoded Seed7 string, or
2007  *          NULL if the memory allocation failed or
2008  *          illegal UTF-8 encodings are used.
2009  */
cstri8_to_stri(const_cstriType cstri,errInfoType * err_info)2010 striType cstri8_to_stri (const_cstriType cstri, errInfoType *err_info)
2011 
2012   {
2013     memSizeType length;
2014     memSizeType stri_size;
2015     striType resized_stri;
2016     striType stri;
2017 
2018   /* cstri8_to_stri */
2019     length = strlen(cstri);
2020     if (unlikely(!ALLOC_STRI_CHECK_SIZE(stri, length))) {
2021       *err_info = MEMORY_ERROR;
2022     } else {
2023       if (likely(utf8_to_stri(stri->mem, &stri_size, (const_ustriType) cstri, length) == 0)) {
2024         stri->size = stri_size;
2025         if (stri_size != length) {
2026           REALLOC_STRI_SIZE_SMALLER(resized_stri, stri, length, stri_size);
2027           if (unlikely(resized_stri == NULL)) {
2028             FREE_STRI(stri, length);
2029             *err_info = MEMORY_ERROR;
2030             stri = NULL;
2031           } else {
2032             stri = resized_stri;
2033             COUNT3_STRI(length, stri_size);
2034           } /* if */
2035         } /* if */
2036       } else {
2037         FREE_STRI(stri, length);
2038         *err_info = RANGE_ERROR;
2039         stri = NULL;
2040       } /* if */
2041     } /* if */
2042     return stri;
2043   } /* cstri8_to_stri */
2044 
2045 
2046 
2047 /**
2048  *  Copy an UTF-8 encoded C string buffer to a Seed7 string.
2049  *  The memory for the UTF-32 encoded Seed7 string is allocated.
2050  *  @param cstri UTF-8 encoded C string buffer (not null terminated).
2051  *  @param length Byte length of the UTF-8 encoded C string buffer.
2052  *  @param err_info Unchanged if the function succeeds, and
2053  *                  MEMORY_ERROR if the memory allocation failed, and
2054  *                  RANGE_ERROR if the conversion failed.
2055  *  @return an UTF-32 encoded Seed7 string, or
2056  *          NULL if the memory allocation failed or
2057  *          illegal UTF-8 encodings are used.
2058  */
cstri8_buf_to_stri(const_cstriType cstri,memSizeType length,errInfoType * err_info)2059 striType cstri8_buf_to_stri (const_cstriType cstri, memSizeType length,
2060     errInfoType *err_info)
2061 
2062   {
2063     memSizeType stri_size;
2064     striType resized_stri;
2065     striType stri;
2066 
2067   /* cstri8_buf_to_stri */
2068     if (unlikely(!ALLOC_STRI_CHECK_SIZE(stri, length))) {
2069       *err_info = MEMORY_ERROR;
2070     } else {
2071       if (likely(utf8_to_stri(stri->mem, &stri_size, (const_ustriType) cstri, length) == 0)) {
2072         stri->size = stri_size;
2073         if (stri_size != length) {
2074           REALLOC_STRI_SIZE_SMALLER(resized_stri, stri, length, stri_size);
2075           if (unlikely(resized_stri == NULL)) {
2076             FREE_STRI(stri, length);
2077             *err_info = MEMORY_ERROR;
2078             stri = NULL;
2079           } else {
2080             stri = resized_stri;
2081             COUNT3_STRI(length, stri_size);
2082           } /* if */
2083         } /* if */
2084       } else {
2085         FREE_STRI(stri, length);
2086         *err_info = RANGE_ERROR;
2087         stri = NULL;
2088       } /* if */
2089     } /* if */
2090     return stri;
2091   } /* cstri8_buf_to_stri */
2092 
2093 
2094 
2095 /**
2096  *  Copy an UTF-8 or ISO-8859-1 encoded C string to a Seed7 string.
2097  *  The memory for the UTF-32 encoded Seed7 string is allocated.
2098  *  @param cstri Null terminated UTF-8 or ISO-8859-1 encoded C string.
2099  *  @return an UTF-32 encoded Seed7 string, or
2100  *          NULL if the memory allocation failed.
2101  */
cstri8_or_cstri_to_stri(const_cstriType cstri)2102 striType cstri8_or_cstri_to_stri (const_cstriType cstri)
2103 
2104   {
2105     errInfoType err_info = OKAY_NO_ERROR;
2106     striType stri;
2107 
2108   /* cstri8_or_cstri_to_stri */
2109     stri = cstri8_to_stri(cstri, &err_info);
2110     if (stri == NULL) {
2111       stri = cstri_to_stri(cstri);
2112     } /* if */
2113     return stri;
2114   } /* cstri8_or_cstri_to_stri */
2115 
2116 
2117 
2118 /**
2119  *  Copy an UTF-16 encoded wide string buffer to a Seed7 string.
2120  *  The memory for the UTF-32 encoded Seed7 string is allocated.
2121  *  @param wstri UTF-16 encoded wide string buffer (not null terminated).
2122  *  @param length Character length of the UTF-16 encoded wide string buffer.
2123  *  @param err_info Unchanged if the function succeeds, and
2124  *                  MEMORY_ERROR if the memory allocation failed.
2125  *  @return an UTF-32 encoded Seed7 string, or
2126  *          NULL if the memory allocation failed.
2127  */
wstri_buf_to_stri(const_wstriType wstri,memSizeType length,errInfoType * err_info)2128 striType wstri_buf_to_stri (const_wstriType wstri, memSizeType length,
2129     errInfoType *err_info)
2130 
2131   {
2132     memSizeType stri_size;
2133     striType resized_stri;
2134     striType stri;
2135 
2136   /* wstri_buf_to_stri */
2137     if (unlikely(!ALLOC_STRI_CHECK_SIZE(stri, length))) {
2138       *err_info = MEMORY_ERROR;
2139     } else {
2140       stri_size = wstri_expand(stri->mem, wstri, length);
2141       stri->size = stri_size;
2142       if (stri_size != length) {
2143         REALLOC_STRI_SIZE_SMALLER(resized_stri, stri, length, stri_size);
2144         if (unlikely(resized_stri == NULL)) {
2145           FREE_STRI(stri, length);
2146           *err_info = MEMORY_ERROR;
2147           stri = NULL;
2148         } else {
2149           stri = resized_stri;
2150           COUNT3_STRI(length, stri_size);
2151         } /* if */
2152       } /* if */
2153     } /* if */
2154     return stri;
2155   } /* wstri_buf_to_stri */
2156 
2157 
2158 
2159 /**
2160  *  Copy a wide string with length to a null terminated C string.
2161  *  This function is used to convert (ASCII) date and time values.
2162  *  @param cstri Destination of the null terminated string.
2163  *  @param wstri Source wide char string to be copied.
2164  *  @param length Length of wstri measured in wide characters.
2165  *  @return OKAY_NO_ERROR if the conversion succeeded, or
2166  *          RANGE_ERROR if non-ASCII characters were found.
2167  */
conv_wstri_buf_to_cstri(cstriType cstri,const_wstriType wstri,memSizeType length)2168 errInfoType conv_wstri_buf_to_cstri (cstriType cstri, const_wstriType wstri,
2169     memSizeType length)
2170 
2171   {
2172     ustriType ustri;
2173     wcharType ch;
2174     errInfoType err_info = OKAY_NO_ERROR;
2175 
2176   /* conv_wstri_buf_to_cstri */
2177     ustri = (ustriType) cstri;
2178     for (; length > 0; ustri++, wstri++, length--) {
2179       ch = *wstri;
2180       if (likely(ch <= 0xFF)) {
2181         *ustri = (ucharType) ch;
2182       } else {
2183         err_info = RANGE_ERROR;
2184       } /* if */
2185     } /* if */
2186     *ustri = '\0';
2187     return err_info;
2188   } /* conv_wstri_buf_to_cstri */
2189 
2190 
2191 
2192 /**
2193  *  Convert a Seed7 UTF-32 string to a null terminated os_striType string.
2194  *  The memory for the null terminated os_striType string is allocated.
2195  *  The os_striType result is allocated with the macro os_stri_alloc()
2196  *  and it must be freed with the macro os_stri_free(). Strings allocated
2197  *  with os_stri_alloc() must be freed in the reverse order of their
2198  *  creation. This allows that allocations work in a stack like manner.
2199  *  Many system calls have parameters with null terminated os_striType
2200  *  strings. System calls are defined in "version.h" and "os_decls.h".
2201  *  They are prefixed with os_ and use strings of the type os_striType.
2202  *  Depending on the operating system os_striType can describe byte or
2203  *  wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or
2204  *  it can use a code page.
2205  *  @param stri Seed7 UTF-32 string to be converted.
2206  *  @param err_info Unchanged if the function succeeds, and
2207  *                  MEMORY_ERROR if the memory allocation failed, and
2208  *                  RANGE_ERROR if the conversion failed.
2209  *  @return a null terminated os_striType value used by system calls, or
2210  *          NULL if an error occurred.
2211  */
stri_to_os_stri(const_striType stri,errInfoType * err_info)2212 os_striType stri_to_os_stri (const_striType stri, errInfoType *err_info)
2213 
2214   {
2215     os_striType result;
2216 
2217   /* stri_to_os_stri */
2218     if (unlikely(stri->size > MAX_OS_STRI_SIZE)) {
2219       *err_info = MEMORY_ERROR;
2220       result = NULL;
2221     } else if (unlikely(!os_stri_alloc(result, OS_STRI_SIZE(stri->size)))) {
2222       *err_info = MEMORY_ERROR;
2223     } else if (unlikely(!conv_to_os_stri(result, stri->mem,
2224                                          stri->size, err_info))) {
2225       os_stri_free(result);
2226       result = NULL;
2227     } /* if */
2228     return result;
2229   } /* stri_to_os_stri */
2230 
2231 
2232 
2233 /**
2234  *  Convert a null terminated os_striType string to a Seed7 UTF-32 string.
2235  *  Many system calls return null terminated os_striType strings. System
2236  *  calls are defined in "version.h" and "os_decls.h". They are prefixed
2237  *  with os_ and use strings of the type os_striType. Depending on the
2238  *  operating system os_striType can describe byte or wide char strings.
2239  *  The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.
2240  *  @param os_stri null terminated os_striType string to be converted.
2241  *  @param err_info Unchanged if the function succeeds, and
2242  *                  MEMORY_ERROR if the memory allocation failed.
2243  *  @return a Seed7 UTF-32 string, or
2244  *          NULL if an error occurred.
2245  */
os_stri_to_stri(const const_os_striType os_stri,errInfoType * err_info)2246 striType os_stri_to_stri (const const_os_striType os_stri, errInfoType *err_info)
2247 
2248   {
2249     striType stri;
2250 
2251   /* os_stri_to_stri */
2252     logFunction(printf("os_stri_to_stri(\"" FMT_S_OS "\", *)\n", os_stri););
2253     stri = conv_from_os_stri(os_stri, os_stri_strlen(os_stri));
2254     if (unlikely(stri == NULL)) {
2255       *err_info = MEMORY_ERROR;
2256     } /* if */
2257     return stri;
2258   } /* os_stri_to_stri */
2259 
2260 
2261 
stri_to_standard_path(const striType stri)2262 striType stri_to_standard_path (const striType stri)
2263 
2264   {
2265     memSizeType pathLength;
2266     striType resized_stdPath;
2267     striType stdPath;
2268 
2269   /* stri_to_standard_path */
2270     stdPath = stri;
2271     if (stdPath != NULL) {
2272       pathLength = stdPath->size;
2273 #if PATH_DELIMITER != '/'
2274       {
2275         memSizeType pos;
2276 
2277         for (pos = 0; pos < pathLength; pos++) {
2278           if (stdPath->mem[pos] == PATH_DELIMITER) {
2279             stdPath->mem[pos] = (strElemType) '/';
2280           } /* if */
2281         } /* for */
2282       }
2283 #endif
2284 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2285       if (pathLength >= 2 && stdPath->mem[1] == ':' &&
2286           ((stdPath->mem[0] >= 'a' && stdPath->mem[0] <= 'z') ||
2287            (stdPath->mem[0] >= 'A' && stdPath->mem[0] <= 'Z'))) {
2288         stdPath->mem[1] = (strElemType) tolower((int) stdPath->mem[0]);
2289         stdPath->mem[0] = (strElemType) '/';
2290         if (pathLength >= 3) {
2291           if (stdPath->mem[2] != '/') {
2292             if (likely(ALLOC_STRI_CHECK_SIZE(stdPath, pathLength + 1))) {
2293               /* Stri points to the old stdPath. */
2294               stdPath->mem[0] = stri->mem[0];
2295               stdPath->mem[1] = stri->mem[1];
2296               stdPath->mem[2] = (strElemType) '/';
2297               memcpy(&stdPath->mem[3], &stri->mem[2],
2298                      (pathLength - 2) * sizeof(strElemType));
2299               FREE_STRI(stri, pathLength);
2300               pathLength++;
2301               stdPath->size = pathLength;
2302             } /* if */
2303           } /* if */
2304         } /* if */
2305       } /* if */
2306 #endif
2307       if (likely(stdPath != NULL)) {
2308         {
2309           memSizeType pos;
2310           memSizeType pos2;
2311 
2312           for (pos = 0; pos < stdPath->size; pos++) {
2313             if (stdPath->mem[pos] == '/') {
2314               pos2 = pos + 1;
2315               while (pos2 < stdPath->size && stdPath->mem[pos2] == '/') {
2316                 pos2++;
2317               } /* while */
2318               if (pos2 > pos + 1) {
2319                 if (pos2 < stdPath->size) {
2320                   memmove(&stdPath->mem[pos + 1], &stdPath->mem[pos2],
2321                           (stdPath->size - pos2) * sizeof(strElemType));
2322                 } /* if */
2323                 stdPath->size -= pos2 - pos - 1;
2324               } /* if */
2325             } /* if */
2326           } /* for */
2327         }
2328         if (stdPath->size > 1 &&
2329                stdPath->mem[stdPath->size - 1] == (charType) '/') {
2330           stdPath->size--;
2331         } /* if */
2332         if (unlikely(stdPath->size != pathLength)) {
2333           REALLOC_STRI_SIZE_SMALLER(resized_stdPath, stdPath, pathLength, stdPath->size);
2334           if (unlikely(resized_stdPath == NULL)) {
2335             FREE_STRI(stdPath, pathLength);
2336             stdPath = NULL;
2337           } else {
2338             stdPath = resized_stdPath;
2339             COUNT3_STRI(pathLength, stdPath->size);
2340           } /* if */
2341         } /* if */
2342       } /* if */
2343     } /* if */
2344     return stdPath;
2345   } /* stri_to_standard_path */
2346 
2347 
2348 
2349 /**
2350  *  Convert a path returned by a system call to a Seed7 standard path.
2351  *  System calls are defined in "version.h" and "os_decls.h". They are
2352  *  prefixed with os_ and use system paths of the type os_striType.
2353  *  Depending on the operating system os_striType can describe byte or
2354  *  wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or
2355  *  it can use a code page. Beyond the conversion from os_striType a
2356  *  mapping from drive letters might take place on some operating
2357  *  systems.
2358  *  @param os_path null terminated os_striType path to be converted.
2359  *  @param err_info Unchanged if the function succeeds, and
2360  *                  MEMORY_ERROR if the memory allocation failed.
2361  *  @return an UTF-32 encoded Seed7 standard path, or
2362  *          NULL if the memory allocation failed.
2363  */
cp_from_os_path(const_os_striType os_path,errInfoType * err_info)2364 striType cp_from_os_path (const_os_striType os_path, errInfoType *err_info)
2365 
2366   {
2367     striType stdPath;
2368 
2369   /* cp_from_os_path */
2370 #if defined USE_EXTENDED_LENGTH_PATH && USE_EXTENDED_LENGTH_PATH
2371     if (memcmp(os_path, PATH_PREFIX, PREFIX_LEN * sizeof(os_charType)) == 0) {
2372       /* For extended path omit the prefix. */
2373       os_path = &os_path[PREFIX_LEN];
2374     } /* if */
2375 #endif
2376     stdPath = os_stri_to_stri(os_path, err_info);
2377     if (likely(stdPath != NULL)) {
2378       stdPath = stri_to_standard_path(stdPath);
2379       if (unlikely(stdPath == NULL)) {
2380         *err_info = MEMORY_ERROR;
2381       } /* if */
2382     } /* if */
2383     return stdPath;
2384   } /* cp_from_os_path */
2385 
2386 
2387 
2388 #ifdef MAP_LONG_FILE_NAMES_TO_SHORT
isShortFileName(os_striType fileName)2389 static boolType isShortFileName (os_striType fileName)
2390 
2391   {
2392     os_charType ch;
2393     int pos = 0;
2394     int dotPos = -1;
2395     boolType shortFileName = TRUE;
2396 
2397   /* isShortFileName */
2398     ch = fileName[0];
2399     do {
2400       switch (ch) {
2401         case '!':  case '#':  case '$':  case '%':  case '&':
2402         case '\'': case '(':  case ')':  case '-':
2403         case '0':  case '1':  case '2':  case '3':  case '4':
2404         case '5':  case '6':  case '7':  case '8':  case '9':
2405         case '@':
2406         case 'A':  case 'B':  case 'C':  case 'D':  case 'E':
2407         case 'F':  case 'G':  case 'H':  case 'I':  case 'J':
2408         case 'K':  case 'L':  case 'M':  case 'N':  case 'O':
2409         case 'P':  case 'Q':  case 'R':  case 'S':  case 'T':
2410         case 'U':  case 'V':  case 'W':  case 'X':  case 'Y':
2411         case 'Z':
2412         case '^':  case '_':  case '`':
2413         case 'a':  case 'b':  case 'c':  case 'd':  case 'e':
2414         case 'f':  case 'g':  case 'h':  case 'i':  case 'j':
2415         case 'k':  case 'l':  case 'm':  case 'n':  case 'o':
2416         case 'p':  case 'q':  case 'r':  case 's':  case 't':
2417         case 'u':  case 'v':  case 'w':  case 'x':  case 'y':
2418         case 'z':
2419         case '{':  case '}':  case '~':
2420           /* Characters allowed in 8.3 file names. */
2421           break;
2422         case '.':
2423           if (dotPos == -1) {
2424             dotPos = pos;
2425           } else {
2426             shortFileName = FALSE;
2427           } /* if */
2428           break;
2429         default:
2430           shortFileName = FALSE;
2431           break;
2432       } /* switch */
2433       pos++;
2434       ch = fileName[pos];
2435     } while (ch != PATH_DELIMITER && ch != '\0');
2436     if (dotPos == -1) {
2437       if (pos >= 8) {
2438         shortFileName = FALSE;
2439       } /* if */
2440     } else {
2441       if (dotPos == 0 || dotPos > 8 || pos - dotPos > 4) {
2442         shortFileName = FALSE;
2443       } /* if */
2444     } /* if */
2445     return shortFileName;
2446   } /* isShortFileName */
2447 
2448 
2449 
findDot(os_striType name)2450 static boolType findDot (os_striType name)
2451 
2452   {
2453     os_charType ch;
2454     int pos = 0;
2455     boolType found = FALSE;
2456 
2457   /* findDot */
2458     ch = name[0];
2459     while (ch != PATH_DELIMITER && ch != '\0' && !found) {
2460       if (ch == '.') {
2461         found = TRUE;
2462       } /* if */
2463       pos++;
2464       ch = name[pos];
2465     } /* while */
2466     return found;
2467   } /* findDot */
2468 
2469 
2470 
toShortFileName(os_striType dest,os_striType * sourceAddr)2471 static os_striType toShortFileName (os_striType dest, os_striType *sourceAddr)
2472 
2473   {
2474     os_striType source;
2475     os_charType ch;
2476     int sourcePos = 0;
2477     int destPos = 0;
2478     int dotPos = -1;
2479     boolType writeToDest = TRUE;
2480 
2481   /* toShortFileName */
2482     source = *sourceAddr;
2483     ch = source[0];
2484     while (ch != PATH_DELIMITER && ch != '\0') {
2485       switch (ch) {
2486         case '!':  case '#':  case '$':  case '%':  case '&':
2487         case '\'': case '(':  case ')':  case '-':
2488         case '0':  case '1':  case '2':  case '3':  case '4':
2489         case '5':  case '6':  case '7':  case '8':  case '9':
2490         case '@':
2491         case 'A':  case 'B':  case 'C':  case 'D':  case 'E':
2492         case 'F':  case 'G':  case 'H':  case 'I':  case 'J':
2493         case 'K':  case 'L':  case 'M':  case 'N':  case 'O':
2494         case 'P':  case 'Q':  case 'R':  case 'S':  case 'T':
2495         case 'U':  case 'V':  case 'W':  case 'X':  case 'Y':
2496         case 'Z':
2497         case '^':  case '_':  case '`':
2498         case '{':  case '}':  case '~':
2499           if (writeToDest) {
2500             dest[destPos] = ch;
2501             destPos++;
2502           } /* if */
2503           break;
2504         case 'a':  case 'b':  case 'c':  case 'd':  case 'e':
2505         case 'f':  case 'g':  case 'h':  case 'i':  case 'j':
2506         case 'k':  case 'l':  case 'm':  case 'n':  case 'o':
2507         case 'p':  case 'q':  case 'r':  case 's':  case 't':
2508         case 'u':  case 'v':  case 'w':  case 'x':  case 'y':
2509         case 'z':
2510           if (writeToDest) {
2511             dest[destPos] = (os_charType) toupper((char) ch);
2512             destPos++;
2513           } /* if */
2514           break;
2515         case '+':  case ',':  case ';':  case '=':  case '[':
2516         case ']':
2517           if (writeToDest) {
2518             dest[destPos] = '_';
2519             destPos++;
2520           } /* if */
2521           break;
2522         case '.':
2523           if (!findDot(&source[sourcePos + 1])) {
2524             if (!writeToDest) {
2525               dest[destPos] = '~';
2526               destPos++;
2527               dest[destPos] = '1';
2528               destPos++;
2529               writeToDest = TRUE;
2530             } /* if */
2531             dotPos = destPos;
2532             dest[destPos] = '.';
2533             destPos++;
2534           } /* if */
2535           break;
2536         default:
2537           /* Ignore other characters */
2538           break;
2539       } /* switch */
2540       if (dotPos == -1) {
2541         if (destPos >= 6) {
2542           writeToDest = FALSE;
2543         } /* if */
2544       } else {
2545         if (destPos - dotPos >= 4) {
2546           writeToDest = FALSE;
2547         } /* if */
2548       } /* if */
2549       sourcePos++;
2550       ch = source[sourcePos];
2551     } /* while */
2552     if (dotPos == -1) {
2553       if (!writeToDest) {
2554         dest[destPos] = '~';
2555         destPos++;
2556         dest[destPos] = '1';
2557         destPos++;
2558       } /* if */
2559     } /* if */
2560     *sourceAddr = &source[sourcePos];
2561     return &dest[destPos];
2562   } /* toShortFileName */
2563 
2564 
2565 
copyFileName(os_striType dest,os_striType * sourceAddr)2566 static os_striType copyFileName (os_striType dest, os_striType *sourceAddr)
2567 
2568   {
2569     os_striType source;
2570     os_charType ch;
2571 
2572   /* copyFileName */
2573     source = *sourceAddr;
2574     ch = *source;
2575     while (ch != PATH_DELIMITER && ch != '\0') {
2576       *dest = ch;
2577       dest++;
2578       source++;
2579       ch = *source;
2580     } /* while */
2581     *sourceAddr = source;
2582     return dest;
2583   } /* copyFileName */
2584 
2585 
2586 
mapLongFileNamesToShort(os_striType path)2587 static void mapLongFileNamesToShort (os_striType path)
2588 
2589   {
2590     os_striType source;
2591     os_striType dest;
2592 
2593   /* mapLongFileNamesToShort */
2594     logFunction(printf("mapLongFileNamesToShort(\"" FMT_S_OS "\")\n", path););
2595     /* Start after the the colon of the device letter ( e.g.: A: ) */
2596     source = &path[PREFIX_LEN + 2];
2597     dest = source;
2598     while (*source == PATH_DELIMITER) {
2599       source++;
2600       *dest = PATH_DELIMITER;
2601       dest++;
2602       if (isShortFileName(source)) {
2603         dest = copyFileName(dest, &source);
2604       } else {
2605         dest = toShortFileName(dest, &source);
2606       } /* if */
2607     } /* while */
2608     *dest = '\0';
2609     logFunction(printf("mapLongFileNamesToShort --> \"" FMT_S_OS "\"\n", path););
2610   } /* mapLongFileNamesToShort */
2611 #endif
2612 
2613 
2614 
2615 #if OS_PATH_HAS_DRIVE_LETTERS
2616 #if EMULATE_ROOT_CWD
setEmulatedCwdToRoot(void)2617 void setEmulatedCwdToRoot (void)
2618 
2619   { /* setEmulatedCwdToRoot */
2620     logFunction(printf("setEmulatedCwdToRoot\n"););
2621     if (current_emulated_cwd != NULL &&
2622         current_emulated_cwd != emulated_root) {
2623       FREE_OS_STRI((os_striType) current_emulated_cwd);
2624     } /* if */
2625     current_emulated_cwd = emulated_root;
2626     logFunction(printf("setEmulatedCwdToRoot --> current_emulated_cwd=\"" FMT_S_OS "\"\n",
2627                         current_emulated_cwd););
2628   } /* setEmulatedCwdToRoot */
2629 
2630 
2631 
setEmulatedCwd(os_striType os_path,errInfoType * err_info)2632 void setEmulatedCwd (os_striType os_path, errInfoType *err_info)
2633 
2634   {
2635     memSizeType cwd_len;
2636     os_striType new_cwd;
2637     memSizeType position;
2638 
2639   /* setEmulatedCwd */
2640     logFunction(printf("setEmulatedCwd(\"" FMT_S_OS "\")\n", os_path););
2641 #if USE_EXTENDED_LENGTH_PATH
2642     if (memcmp(os_path, PATH_PREFIX, PREFIX_LEN * sizeof(os_charType)) == 0) {
2643       /* For extended path omit the prefix. */
2644       os_path = &os_path[PREFIX_LEN];
2645     } /* if */
2646 #endif
2647     cwd_len = os_stri_strlen(os_path);
2648     if (unlikely(!ALLOC_OS_STRI(new_cwd, cwd_len))) {
2649       *err_info = MEMORY_ERROR;
2650     } else {
2651       memcpy(new_cwd, os_path, (cwd_len + NULL_TERMINATION_LEN) * sizeof(os_charType));
2652       position = os_stri_strlen(new_cwd);
2653       if (position >= 2 && new_cwd[position - 1] == OS_PATH_DELIMITER) {
2654         new_cwd[position - 1] = '\0';
2655       } /* if */
2656       if (((new_cwd[0] >= 'a' && new_cwd[0] <= 'z') ||
2657            (new_cwd[0] >= 'A' && new_cwd[0] <= 'Z')) &&
2658           new_cwd[1] == ':') {
2659         new_cwd[1] = (os_charType) tolower(new_cwd[0]);
2660         new_cwd[0] = OS_PATH_DELIMITER;
2661       } /* if */
2662       if (current_emulated_cwd != NULL &&
2663           current_emulated_cwd != emulated_root) {
2664         FREE_OS_STRI((os_striType) current_emulated_cwd);
2665       } /* if */
2666       current_emulated_cwd = new_cwd;
2667     } /* if */
2668     logFunction(printf("setEmulatedCwd --> current_emulated_cwd=\"" FMT_S_OS "\"\n",
2669                         current_emulated_cwd););
2670   } /* setEmulatedCwd */
2671 
2672 
2673 
append_path(const const_os_striType absolutePath,const strElemType * const relativePathChars,memSizeType relativePathSize,int * path_info,errInfoType * err_info)2674 static os_striType append_path (const const_os_striType absolutePath,
2675     const strElemType *const relativePathChars,
2676     memSizeType relativePathSize, int *path_info, errInfoType *err_info)
2677 
2678   {
2679     memSizeType abs_path_length;
2680     memSizeType result_len;
2681     os_striType abs_path_end;
2682     const_os_striType rel_path_start;
2683     os_striType result;
2684 
2685   /* append_path */
2686     logFunction(printf("append_path(\"" FMT_S_OS "\", \"%s\")\n",
2687                        absolutePath,
2688                        striCharsAsUnquotedCStri(relativePathChars,
2689                                                 relativePathSize)););
2690     /* absolutePath[0] is always '/'. */
2691     if (absolutePath[1] == '\0') {
2692       abs_path_length = 0;
2693     } else {
2694       abs_path_length = os_stri_strlen(absolutePath);
2695     } /* if */
2696     result_len = PREFIX_LEN + abs_path_length +
2697                  OS_STRI_SIZE(relativePathSize) + 3;
2698     if (unlikely(!os_stri_alloc(result, result_len))) {
2699       *err_info = MEMORY_ERROR;
2700     } else {
2701 #if USE_EXTENDED_LENGTH_PATH
2702       memcpy(result, PATH_PREFIX, PREFIX_LEN * sizeof(os_charType));
2703 #endif
2704       memcpy(&result[PREFIX_LEN], absolutePath,
2705              abs_path_length * sizeof(os_charType));
2706       abs_path_length += PREFIX_LEN;
2707       result[abs_path_length] = OS_PATH_DELIMITER;
2708       /* Leave one char free between absolute and relative path. */
2709       if (unlikely(!conv_to_os_stri(&result[abs_path_length + 2],
2710           relativePathChars, relativePathSize, err_info))) {
2711         os_stri_free(result);
2712         result = NULL;
2713       } else {
2714         abs_path_end = &result[abs_path_length];
2715         rel_path_start = &result[abs_path_length + 2];
2716         while (*rel_path_start != '\0') {
2717           if (rel_path_start[0] == '.' && rel_path_start[1] == '.' &&
2718               (rel_path_start[2] == '/' || rel_path_start[2] == '\0')) {
2719             rel_path_start += 2;
2720             if (abs_path_end > &result[PREFIX_LEN]) {
2721               do {
2722                 abs_path_end--;
2723               } while (*abs_path_end != OS_PATH_DELIMITER);
2724             } /* if */
2725           } else if (rel_path_start[0] == '.' &&
2726               (rel_path_start[1] == '/' || rel_path_start[1] == '\0')) {
2727             rel_path_start++;
2728           } else if (*rel_path_start == '/') {
2729             rel_path_start++;
2730           } else {
2731             do {
2732               abs_path_end++;
2733               *abs_path_end = *rel_path_start;
2734               rel_path_start++;
2735             } while (*rel_path_start != '/' && *rel_path_start != '\0');
2736             abs_path_end++;
2737             *abs_path_end = OS_PATH_DELIMITER;
2738           } /* if */
2739         } /* while */
2740         if (unlikely(abs_path_end == &result[PREFIX_LEN])) {
2741           *err_info = RANGE_ERROR;
2742           *path_info = PATH_IS_EMULATED_ROOT;
2743           os_stri_free(result);
2744           result = NULL;
2745         } else {
2746           *abs_path_end = '\0';
2747           if (likely(result[PREFIX_LEN + 1] >= 'a' &&
2748                      result[PREFIX_LEN + 1] <= 'z')) {
2749             if (result[PREFIX_LEN + 2] == '\0') {
2750               /* "/c"   is mapped to "c:\"  */
2751               result[PREFIX_LEN + 0] = result[PREFIX_LEN + 1];
2752               result[PREFIX_LEN + 1] = ':';
2753               result[PREFIX_LEN + 2] = '\\';
2754               result[PREFIX_LEN + 3] = '\0';
2755             } else if (unlikely(result[PREFIX_LEN + 2] != OS_PATH_DELIMITER)) {
2756               /* "/cd"  cannot be mapped to a drive letter. */
2757               logError(printf("append_path(\"" FMT_S_OS "\"): "
2758                               "\"/cd\" cannot be mapped to a drive letter.\n",
2759                               absolutePath););
2760               *err_info = RANGE_ERROR;
2761               *path_info = PATH_NOT_MAPPED;
2762               os_stri_free(result);
2763               result = NULL;
2764             } else {
2765               /* "/c/d" is mapped to "c:\d" */
2766               result[PREFIX_LEN + 0] = result[PREFIX_LEN + 1];
2767               result[PREFIX_LEN + 1] = ':';
2768               result[PREFIX_LEN + 2] = '\\';
2769             } /* if */
2770           } else {
2771             /* "/C"  cannot be mapped to a drive letter. */
2772             logError(printf("append_path(\"" FMT_S_OS "\"): "
2773                             "\"/C\" cannot be mapped to a drive letter.\n",
2774                             absolutePath););
2775             *err_info = RANGE_ERROR;
2776             *path_info = PATH_NOT_MAPPED;
2777             os_stri_free(result);
2778             result = NULL;
2779           } /* if */
2780         } /* if */
2781       } /* if */
2782     } /* if */
2783     logFunction(printf("append_path(\"" FMT_S_OS "\") --> "
2784                        "\"" FMT_S_OS "\", path_info=%d, err_info=%d\n",
2785                        absolutePath, result, *path_info, *err_info););
2786     return result;
2787   } /* append_path */
2788 
2789 #else
2790 
2791 
2792 
map_to_drive_letter(const strElemType * const pathChars,memSizeType pathSize,int * path_info,errInfoType * err_info)2793 static os_striType map_to_drive_letter (const strElemType *const pathChars,
2794     memSizeType pathSize, int *path_info, errInfoType *err_info)
2795 
2796   {
2797     os_striType result;
2798 
2799   /* map_to_drive_letter */
2800     if (unlikely(pathSize == 0)) {
2801       /* "/"    cannot be mapped to a drive letter */
2802       *err_info = RANGE_ERROR;
2803       *path_info = PATH_IS_EMULATED_ROOT;
2804       result = NULL;
2805     } else if (likely(pathChars[0] >= 'a' && pathChars[0] <= 'z')) {
2806       if (pathSize == 1) {
2807         /* "/c"   is mapped to "c:\"  */
2808         if (unlikely(!os_stri_alloc(result, 3))) {
2809           *err_info = MEMORY_ERROR;
2810         } else {
2811           result[0] = (os_charType) pathChars[0];
2812           result[1] = ':';
2813           result[2] = '\\';
2814           result[3] = '\0';
2815         } /* if */
2816       } else if (unlikely(pathChars[1] != '/')) {
2817         /* "/cd"  cannot be mapped to a drive letter */
2818         *err_info = RANGE_ERROR;
2819         *path_info = PATH_NOT_MAPPED;
2820         result = NULL;
2821       } else {
2822         /* "/c/d" is mapped to "c:\d" */
2823         if (unlikely(!os_stri_alloc(result, OS_STRI_SIZE(pathSize - 2) + 3))) {
2824           *err_info = MEMORY_ERROR;
2825         } else {
2826           result[0] = (os_charType) pathChars[0];
2827           result[1] = ':';
2828           result[2] = '\\';
2829           if (unlikely(!conv_to_os_stri(&result[3], &pathChars[2],
2830                                         pathSize - 2, err_info))) {
2831             os_stri_free(result);
2832             result = NULL;
2833           } /* if */
2834         } /* if */
2835       } /* if */
2836     } else {
2837       /* "/C"  cannot be mapped to a drive letter */
2838       *err_info = RANGE_ERROR;
2839       *path_info = PATH_NOT_MAPPED;
2840       result = NULL;
2841     } /* if */
2842     return result;
2843   } /* map_to_drive_letter */
2844 
2845 #endif
2846 
2847 
2848 
2849 /**
2850  *  Convert a Seed7 standard path to a path used by system calls.
2851  *  The memory for the null terminated os_striType path is allocated.
2852  *  The os_striType result is allocated with the macro os_stri_alloc()
2853  *  and it must be freed with the macro os_stri_free(). Strings allocated
2854  *  with os_stri_alloc() must be freed in the reverse order of their
2855  *  creation. This allows that allocations work in a stack like manner.
2856  *  System calls are defined in "version.h" and "os_decls.h". They are
2857  *  prefixed with os_ and use system paths of the type os_striType.
2858  *  Depending on the operating system os_striType can describe byte or
2859  *  wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or
2860  *  it can use a code page. Beyond the conversion to os_striType a
2861  *  mapping to drive letters might take place on some operating systems.
2862  *  @param std_path UTF-32 encoded Seed7 standard path to be converted.
2863  *  @param path_info Unchanged if the function succeeds, and
2864  *                   PATH_IS_EMULATED_ROOT if the path is "/", and
2865  *                   PATH_NOT_MAPPED if the path cannot be mapped.
2866  *  @param err_info Unchanged if the function succeeds, and
2867  *                  MEMORY_ERROR if the memory allocation failed, and
2868  *                  RANGE_ERROR if the path is not a standard path.
2869  *  @return a null terminated os_striType path used by system calls, or
2870  *          NULL if an error occurred.
2871  */
cp_to_os_path(const_striType std_path,int * path_info,errInfoType * err_info)2872 os_striType cp_to_os_path (const_striType std_path, int *path_info,
2873     errInfoType *err_info)
2874 
2875   {
2876     os_striType result;
2877 
2878   /* cp_to_os_path */
2879     logFunction(printf("cp_to_os_path(\"%s\", %d)\n",
2880                        striAsUnquotedCStri(std_path), *err_info););
2881 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2882 #if FORBID_DRIVE_LETTERS
2883     if (unlikely(std_path->size >= 2 && (std_path->mem[std_path->size - 1] == '/' ||
2884                  (std_path->mem[1] == ':' &&
2885                  ((std_path->mem[0] >= 'a' && std_path->mem[0] <= 'z') ||
2886                   (std_path->mem[0] >= 'A' && std_path->mem[0] <= 'Z')))))) {
2887 #else
2888     if (unlikely(std_path->size >= 2 && std_path->mem[std_path->size - 1] == '/')) {
2889 #endif
2890 #else
2891     if (unlikely(std_path->size >= 2 && std_path->mem[std_path->size - 1] == '/' &&
2892                  (std_path->size != 3 || std_path->mem[1] != ':' ||
2893                  ((std_path->mem[0] < 'a' || std_path->mem[0] > 'z') &&
2894                   (std_path->mem[0] < 'A' || std_path->mem[0] > 'Z'))))) {
2895 #endif
2896       logError(printf("cp_to_os_path(\"%s\"): Path with drive letters or not legal.",
2897                       striAsUnquotedCStri(std_path)););
2898       *err_info = RANGE_ERROR;
2899       result = NULL;
2900     } else if (unlikely(memchr_strelem(std_path->mem, '\\', std_path->size) != NULL)) {
2901       logError(printf("cp_to_os_path(\"%s\"): Path contains a backslash.",
2902                       striAsUnquotedCStri(std_path)););
2903       *err_info = RANGE_ERROR;
2904       result = NULL;
2905     } else if (std_path->size == 0) {
2906       if (unlikely(!os_stri_alloc(result, 0))) {
2907         *err_info = MEMORY_ERROR;
2908       } else {
2909         result[0] = '\0';
2910       } /* if */
2911     } else {
2912 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2913       if (std_path->size >= 1 && std_path->mem[0] == '/') {
2914         /* Absolute path: Try to map the path to a drive letter */
2915 #if EMULATE_ROOT_CWD
2916         result = append_path(emulated_root, &std_path->mem[1], std_path->size - 1,
2917                              path_info, err_info);
2918 #else
2919         result = map_to_drive_letter(&std_path->mem[1], std_path->size - 1, err_info);
2920 #endif
2921       } else {
2922 #if EMULATE_ROOT_CWD
2923         result = append_path(current_emulated_cwd, std_path->mem, std_path->size,
2924                              path_info, err_info);
2925 #else
2926         if (unlikely(!os_stri_alloc(result, OS_STRI_SIZE(std_path->size)))) {
2927           *err_info = MEMORY_ERROR;
2928         } else if (unlikely(!conv_to_os_stri(result, std_path->mem,
2929                                              std_path->size, err_info))) {
2930           os_stri_free(result);
2931           result = NULL;
2932         } /* if */
2933 #endif
2934       } /* if */
2935 #else
2936       if (unlikely(!os_stri_alloc(result, OS_STRI_SIZE(std_path->size)))) {
2937         *err_info = MEMORY_ERROR;
2938       } else if (unlikely(!conv_to_os_stri(result, std_path->mem,
2939                                            std_path->size, err_info))) {
2940         os_stri_free(result);
2941         result = NULL;
2942       } /* if */
2943 #endif
2944     } /* if */
2945 #ifdef MAP_LONG_FILE_NAMES_TO_SHORT
2946     if (result != NULL) {
2947       mapLongFileNamesToShort(result);
2948     } /* if */
2949 #endif
2950     logFunction(printf("cp_to_os_path(\"%s\", %d) --> \"" FMT_S_OS "\"\n",
2951                        striAsUnquotedCStri(std_path), *err_info, result););
2952     return result;
2953   } /* cp_to_os_path */
2954 
2955 #else
2956 
2957 
2958 
2959 /**
2960  *  Convert a Seed7 standard path to a path used by system calls.
2961  *  The memory for the null terminated os_striType path is allocated.
2962  *  The os_striType result is allocated with the macro os_stri_alloc()
2963  *  and it must be freed with the macro os_stri_free(). Strings allocated
2964  *  with os_stri_alloc() must be freed in the reverse order of their
2965  *  creation. This allows that allocations work in a stack like manner.
2966  *  System calls are defined in "version.h" and "os_decls.h". They are
2967  *  prefixed with os_ and use system paths of the type os_striType.
2968  *  Depending on the operating system os_striType can describe byte or
2969  *  wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or
2970  *  it can use a code page. Beyond the conversion to os_striType a
2971  *  mapping to drive letters might take place on some operating systems.
2972  *  @param std_path UTF-32 encoded Seed7 standard path to be converted.
2973  *  @param path_info Unchanged if the function succeeds, and
2974  *                   PATH_IS_EMULATED_ROOT if the path is "/", and
2975  *                   PATH_NOT_MAPPED if the path cannot be mapped.
2976  *  @param err_info Unchanged if the function succeeds, and
2977  *                  MEMORY_ERROR if the memory allocation failed, and
2978  *                  RANGE_ERROR if the path is not a standard path.
2979  *  @return a null terminated os_striType path used by system calls, or
2980  *          NULL if an error occurred.
2981  */
2982 os_striType cp_to_os_path (const_striType std_path, int *path_info,
2983     errInfoType *err_info)
2984 
2985   {
2986     os_striType result;
2987 
2988   /* cp_to_os_path */
2989     logFunction(printf("cp_to_os_path(\"%s\", *)\n",
2990                        striAsUnquotedCStri(std_path)););
2991     if (unlikely(std_path->size >= 2 && std_path->mem[std_path->size - 1] == '/')) {
2992       *err_info = RANGE_ERROR;
2993       result = NULL;
2994     } else if (unlikely(std_path->size > MAX_OS_STRI_SIZE ||
2995                         !os_stri_alloc(result, OS_STRI_SIZE(std_path->size)))) {
2996       *err_info = MEMORY_ERROR;
2997       result = NULL;
2998     } else if (unlikely(!conv_to_os_stri(result, std_path->mem,
2999                                          std_path->size, err_info))) {
3000       os_stri_free(result);
3001       result = NULL;
3002     } /* if */
3003     logFunction(printf("cp_to_os_path --> \"" FMT_S_OS "\" "
3004                        "(path_info=%d, err_info=%d)\n",
3005                        result, *path_info, *err_info););
3006     return result;
3007   } /* cp_to_os_path */
3008 
3009 #endif
3010 
3011 
3012 
3013 os_striType temp_name_in_dir (const const_os_striType path)
3014 
3015   {
3016     memSizeType path_length;
3017     memSizeType pos;
3018     uintType random_value;
3019     unsigned int digit;
3020     memSizeType temp_length;
3021     os_striType temp_name;
3022 
3023   /* temp_name_in_dir */
3024     logFunction(printf("temp_name_in_dir(\"" FMT_S_OS "\")\n", path););
3025     path_length = os_stri_strlen(path);
3026     pos = path_length;
3027     while (pos > 0 && path[pos - 1] != '/' && path[pos - 1] != '\\') {
3028       pos--;
3029     } /* while */
3030     temp_length = pos + 10;
3031     /* printf("temp_length: %lu\n", temp_length); */
3032     if (likely(os_stri_alloc(temp_name, temp_length))) {
3033       memcpy(temp_name, path, pos * sizeof(os_charType));
3034       random_value = uintRand();
3035       for (; pos < temp_length; pos++) {
3036         digit = (unsigned int) (random_value % 36);
3037         random_value /= 36;
3038         temp_name[pos] = (os_charType) "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[digit];
3039       } /* for */
3040       temp_name[pos] = '\0';
3041     } /* if */
3042     logFunction(printf("temp_name_in_dir --> \"" FMT_S_OS "\"\n", temp_name););
3043     return temp_name;
3044   } /* temp_name_in_dir */
3045 
3046 
3047 
3048 /**
3049  *  Add escapes and quotes to a command for system() and popen().
3050  *  @param inBuffer Null terminated string with the shell command.
3051  *  @param outBuffer Destination for the processed command.
3052  *  @param err_info Unchanged if the function succeeds, and
3053  *                  RANGE_ERROR if there are illegal chars in inBuffer.
3054  */
3055 static void escape_command (const const_os_striType inBuffer, os_striType outBuffer,
3056     errInfoType *err_info)
3057 
3058   {
3059     memSizeType inPos;
3060     memSizeType outPos;
3061     boolType quote_path = FALSE;
3062 
3063   /* escape_command */
3064     logFunction(printf("escape_command(\"" FMT_S_OS "\", *, %d)\n",
3065                        inBuffer, *err_info););
3066     for (inPos = 0, outPos = 0; inBuffer[inPos] != '\0'; inPos++, outPos++) {
3067       switch (inBuffer[inPos]) {
3068 #ifdef ESCAPE_SHELL_COMMANDS
3069         case '\t': case ' ':  case '!':  case '\"': case '#':
3070         case '$':  case '&':  case '\'': case '(':  case ')':
3071         case '*':  case ',':  case ':':  case ';':  case '<':
3072         case '=':  case '>':  case '?':  case '[':  case '\\':
3073         case ']':  case '^':  case '`':  case '{':  case '|':
3074         case '}':  case '~':
3075           outBuffer[outPos] = '\\';
3076           outPos++;
3077           outBuffer[outPos] = inBuffer[inPos];
3078           break;
3079         case '\n':
3080           *err_info = RANGE_ERROR;
3081           break;
3082 #else
3083         case ' ':  case '%':  case '&':  case '\'': case '(':
3084         case ')':  case ',':  case ';':  case '=':  case '^':
3085         case '~':  case (os_charType) 160:
3086           quote_path = TRUE;
3087           outBuffer[outPos] = inBuffer[inPos];
3088           break;
3089         case ':':
3090           if (likely(inPos == 1 &&
3091                      inBuffer[0] >= 'a' && inBuffer[0] <= 'z')) {
3092             /* After the drive letter a colon is allowed. */
3093             outBuffer[outPos] = inBuffer[inPos];
3094           } else {
3095             *err_info = RANGE_ERROR;
3096           } /* if */
3097           break;
3098         case '\"': case '*':  case '<':  case '>':  case '?':
3099         case '|':  case '\n': case '\r':
3100           *err_info = RANGE_ERROR;
3101           break;
3102 #endif
3103 #if PATH_DELIMITER != '/'
3104         case '/':
3105           outBuffer[outPos] = PATH_DELIMITER;
3106           break;
3107 #endif
3108         default:
3109           outBuffer[outPos] = inBuffer[inPos];
3110           break;
3111       } /* switch */
3112     } /* for */
3113     if (quote_path) {
3114       memmove(&outBuffer[1], outBuffer, sizeof(os_charType) * outPos);
3115       outBuffer[0] = '\"';
3116       outBuffer[outPos + 1] = '\"';
3117       outBuffer[outPos + 2] = '\0';
3118     } else {
3119       outBuffer[outPos] = '\0';
3120     } /* if */
3121     logFunction(printf("escape_command(\"" FMT_S_OS "\", \"" FMT_S_OS "\", %d)\n",
3122                        inBuffer, outBuffer, *err_info););
3123   } /* escape_command */
3124 
3125 
3126 
3127 /**
3128  *  Create a command string that is usable for system() and popen().
3129  *  @param command Name of the command to be executed. A path must
3130  *                 use the standard path representation.
3131  *  @param parameters Space separated list of parameters for the
3132  *                    'command', or "" if there are no parameters.
3133  *                    Parameters which contain a space must be
3134  *                    enclosed in double quotes.
3135  *  @param err_info Unchanged if the function succeeds, and
3136  *                  MEMORY_ERROR if a memory allocation failed, and
3137  *                  RANGE_ERROR if command or parameters are not okay.
3138  *  @return command string with all necessary escapes and quotes
3139  *          such that it can be used for system() and popen(), or
3140  *          NULL if an error occurred.
3141  */
3142 os_striType cp_to_command (const const_striType command,
3143     const const_striType parameters, errInfoType *err_info)
3144 
3145   {
3146     os_striType os_commandPath;
3147     os_striType os_parameters;
3148     memSizeType command_len;
3149     memSizeType param_len;
3150     memSizeType result_len;
3151     int path_info;
3152     os_striType result;
3153 
3154   /* cp_to_command */
3155     logFunction(printf("cp_to_command(\"%s\", ",
3156                        striAsUnquotedCStri(command));
3157                 printf("\"%s\", *)\n",
3158                        striAsUnquotedCStri(parameters)););
3159 #if EMULATE_ROOT_CWD
3160     if (memchr_strelem(command->mem, '/', command->size) != NULL) {
3161       os_commandPath = cp_to_os_path(command, &path_info, err_info);
3162     } else if (unlikely(memchr_strelem(command->mem, '\\',
3163                                        command->size) != NULL)) {
3164       *err_info = RANGE_ERROR;
3165       os_commandPath = NULL;
3166     } else {
3167       os_commandPath = stri_to_os_stri(command, err_info);
3168     } /* if */
3169 #else
3170     os_commandPath = cp_to_os_path(command, &path_info, err_info);
3171 #endif
3172     logMessage(printf("cp_to_command: os_commandPath: \"" FMT_S_OS "\"\n",
3173                       os_commandPath););
3174     if (unlikely(os_commandPath == NULL)) {
3175       result = NULL;
3176     } else {
3177       os_parameters = stri_to_os_stri(parameters, err_info);
3178       if (unlikely(os_parameters == NULL)) {
3179         result = NULL;
3180       } else {
3181         command_len = os_stri_strlen(os_commandPath);
3182         param_len = os_stri_strlen(os_parameters);
3183         if (unlikely(MAX_OS_STRI_SIZE - 4 < param_len ||
3184                      command_len > (MAX_OS_STRI_SIZE - 4 - param_len) / 3)) {
3185           *err_info = MEMORY_ERROR;
3186           result = NULL;
3187         } else {
3188           result_len = 3 * command_len + param_len + 4;
3189           if (unlikely(!ALLOC_OS_STRI(result, result_len))) {
3190             *err_info = MEMORY_ERROR;
3191           } else {
3192 #if defined USE_EXTENDED_LENGTH_PATH && USE_EXTENDED_LENGTH_PATH
3193             if (memcmp(os_commandPath, PATH_PREFIX, PREFIX_LEN * sizeof(os_charType)) == 0) {
3194               escape_command(&os_commandPath[PREFIX_LEN], result, err_info);
3195             } else {
3196               escape_command(os_commandPath, result, err_info);
3197             } /* if */
3198 #else
3199             escape_command(os_commandPath, result, err_info);
3200 #endif
3201             if (unlikely(*err_info != OKAY_NO_ERROR)) {
3202               FREE_OS_STRI(result);
3203               result = NULL;
3204             } else {
3205               result_len = os_stri_strlen(result);
3206 #ifdef QUOTE_WHOLE_SHELL_COMMAND
3207               if (result[0] == '\"') {
3208                 memmove(&result[1], result, sizeof(os_charType) * result_len);
3209                 result[0] = '\"';
3210                 result_len++;
3211               } /* if */
3212 #endif
3213               if (os_parameters[0] != ' ' && os_parameters[0] != '\0') {
3214                 result[result_len] = ' ';
3215                 result_len++;
3216               } /* if */
3217               memcpy(&result[result_len], os_parameters,
3218                      sizeof(os_charType) * (param_len + 1));
3219 #ifdef QUOTE_WHOLE_SHELL_COMMAND
3220               if (result[0] == '\"' && result[1] == '\"') {
3221                 result_len = os_stri_strlen(result);
3222                 result[result_len] = '\"';
3223                 result[result_len + 1] = '\0';
3224               } /* if */
3225 #endif
3226             } /* if */
3227           } /* if */
3228         } /* if */
3229         os_stri_free(os_parameters);
3230       } /* if */
3231       os_stri_free(os_commandPath);
3232     } /* if */
3233     logFunction(printf("cp_to_command -> " FMT_S_OS "\n", result););
3234     return result;
3235   } /* cp_to_command */
3236