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