1 
2 /********************************************************************/
3 /*                                                                  */
4 /*  cmd_rtl.c     Directory, file and other system functions.       */
5 /*  Copyright (C) 1989 - 2016, 2018 - 2021  Thomas Mertes           */
6 /*                                                                  */
7 /*  This file is part of the Seed7 Runtime Library.                 */
8 /*                                                                  */
9 /*  The Seed7 Runtime Library is free software; you can             */
10 /*  redistribute it and/or modify it under the terms of the GNU     */
11 /*  Lesser General Public License as published by the Free Software */
12 /*  Foundation; either version 2.1 of the License, or (at your      */
13 /*  option) any later version.                                      */
14 /*                                                                  */
15 /*  The Seed7 Runtime Library is distributed in the hope that it    */
16 /*  will be useful, but WITHOUT ANY WARRANTY; without even the      */
17 /*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
18 /*  PURPOSE.  See the GNU Lesser General Public License for more    */
19 /*  details.                                                        */
20 /*                                                                  */
21 /*  You should have received a copy of the GNU Lesser General       */
22 /*  Public License along with this program; if not, write to the    */
23 /*  Free Software Foundation, Inc., 51 Franklin Street,             */
24 /*  Fifth Floor, Boston, MA  02110-1301, USA.                       */
25 /*                                                                  */
26 /*  Module: Seed7 Runtime Library                                   */
27 /*  File: seed7/src/cmd_rtl.c                                       */
28 /*  Changes: 1994, 2006, 2009, 2018 - 2021  Thomas Mertes           */
29 /*  Content: Directory, file and other system functions.            */
30 /*                                                                  */
31 /********************************************************************/
32 
33 #define LOG_FUNCTIONS 0
34 #define VERBOSE_EXCEPTIONS 0
35 
36 #include "version.h"
37 
38 #include "stdlib.h"
39 #include "stdio.h"
40 #include "string.h"
41 #include "limits.h"
42 #include "time.h"
43 #include "sys/types.h"
44 #include "sys/stat.h"
45 #ifdef INCLUDE_SYS_UTIME
46 #include "sys/utime.h"
47 #else
48 #include "utime.h"
49 #endif
50 #ifdef OS_STRI_WCHAR
51 #include "wchar.h"
52 #ifdef OS_WIDE_DIR_INCLUDE_DIR_H
53 #include "dir.h"
54 #endif
55 #ifdef OS_CHMOD_INCLUDE_IO_H
56 #include "io.h"
57 #endif
58 #endif
59 #ifdef DEFINE_SYSTEM_FUNCTION
60 #include "emscripten.h"
61 #endif
62 #include "errno.h"
63 
64 #if UNISTD_H_PRESENT
65 #include "unistd.h"
66 #endif
67 
68 #if HAS_MMAP
69 #include "sys/mman.h"
70 #endif
71 
72 #include "common.h"
73 #include "data_rtl.h"
74 #include "os_decls.h"
75 #include "heaputl.h"
76 #include "striutl.h"
77 #include "level.h"
78 #include "str_rtl.h"
79 #include "chr_rtl.h"
80 #include "int_rtl.h"
81 #include "fil_rtl.h"
82 #include "dir_drv.h"
83 #include "dir_rtl.h"
84 #include "set_rtl.h"
85 #include "tim_rtl.h"
86 #include "arr_rtl.h"
87 #include "tim_drv.h"
88 #include "big_drv.h"
89 #include "cmd_drv.h"
90 #include "stat_drv.h"
91 #include "rtl_err.h"
92 
93 #undef EXTERN
94 #define EXTERN
95 #include "cmd_rtl.h"
96 
97 
98 #define MAX_CSTRI_BUFFER_LEN 40
99 
100 #ifndef CALL_C_COMPILER_FROM_SHELL
101 #define CALL_C_COMPILER_FROM_SHELL 0
102 #endif
103 #ifndef CPLUSPLUS_COMPILER
104 #define CPLUSPLUS_COMPILER C_COMPILER
105 #endif
106 #ifndef EXECUTABLE_FILE_EXTENSION
107 #define EXECUTABLE_FILE_EXTENSION ""
108 #endif
109 #ifndef CC_OPT_LINK_TIME_OPTIMIZATION
110 #define CC_OPT_LINK_TIME_OPTIMIZATION ""
111 #endif
112 #ifndef LINKER_OPT_LTO_MANDATORY
113 #define LINKER_OPT_LTO_MANDATORY 0
114 #endif
115 #ifndef CC_OPT_TRAP_OVERFLOW
116 #define CC_OPT_TRAP_OVERFLOW ""
117 #endif
118 #ifndef CC_OPT_VERSION_INFO
119 #define CC_OPT_VERSION_INFO ""
120 #endif
121 #ifndef CC_ENVIRONMENT_INI
122 #define CC_ENVIRONMENT_INI ""
123 #endif
124 #ifndef CC_FLAGS
125 #define CC_FLAGS ""
126 #endif
127 #ifndef LINKER_OPT_DEBUG_INFO
128 #define LINKER_OPT_DEBUG_INFO ""
129 #endif
130 #ifndef LINKER_OPT_NO_DEBUG_INFO
131 #define LINKER_OPT_NO_DEBUG_INFO ""
132 #endif
133 #ifndef LINKER_OPT_OUTPUT_FILE
134 #define LINKER_OPT_OUTPUT_FILE ""
135 #endif
136 #ifndef LINKER_OPT_SPECIAL_LIB
137 #define LINKER_OPT_SPECIAL_LIB ""
138 #endif
139 #ifndef LINKER_FLAGS
140 #define LINKER_FLAGS ""
141 #endif
142 #ifndef LINKED_PROGRAM_EXTENSION
143 #ifdef EXECUTABLE_FILE_EXTENSION
144 #define LINKED_PROGRAM_EXTENSION EXECUTABLE_FILE_EXTENSION
145 #else
146 #define LINKED_PROGRAM_EXTENSION ""
147 #endif
148 #endif
149 #ifndef SPECIAL_LIB
150 #define SPECIAL_LIB ""
151 #endif
152 #ifndef SYSTEM_LIBS
153 #define SYSTEM_LIBS ""
154 #endif
155 #ifndef SYSTEM_MATH_LIBS
156 #define SYSTEM_MATH_LIBS ""
157 #endif
158 #ifndef PIXEL_RED_MASK
159 #define PIXEL_RED_MASK "0"
160 #endif
161 #ifndef PIXEL_GREEN_MASK
162 #define PIXEL_GREEN_MASK "0"
163 #endif
164 #ifndef PIXEL_BLUE_MASK
165 #define PIXEL_BLUE_MASK "0"
166 #endif
167 #ifndef RGB_TO_PIXEL_FLAG_NAME
168 #define RGB_TO_PIXEL_FLAG_NAME ""
169 #endif
170 
171 
172 #if HAS_BUILTIN_OVERFLOW_OPERATIONS
173 #if INTTYPE_SIZE == INT_SIZE
174 #define BUILTIN_ADD_OVERFLOW "__builtin_sadd_overflow"
175 #define BUILTIN_SUB_OVERFLOW "__builtin_ssub_overflow"
176 #define BUILTIN_MULT_OVERFLOW "__builtin_smul_overflow"
177 #elif INTTYPE_SIZE == LONG_SIZE
178 #define BUILTIN_ADD_OVERFLOW "__builtin_saddl_overflow"
179 #define BUILTIN_SUB_OVERFLOW "__builtin_ssubl_overflow"
180 #define BUILTIN_MULT_OVERFLOW "__builtin_smull_overflow"
181 #elif defined(LONG_LONG_SIZE) && INTTYPE_SIZE == LONG_LONG_SIZE
182 #define BUILTIN_ADD_OVERFLOW "__builtin_saddll_overflow"
183 #define BUILTIN_SUB_OVERFLOW "__builtin_ssubll_overflow"
184 #define BUILTIN_MULT_OVERFLOW "__builtin_smulll_overflow"
185 #endif
186 #else
187 #define BUILTIN_ADD_OVERFLOW ""
188 #define BUILTIN_SUB_OVERFLOW ""
189 #define BUILTIN_MULT_OVERFLOW ""
190 #endif
191 
192 
193 #ifndef INT64TYPE
194 #define INT64TYPE_STRI ""
195 #define UINT64TYPE_STRI ""
196 #undef INT32TYPE_LITERAL_SUFFIX
197 #define INT32TYPE_LITERAL_SUFFIX ""
198 #define INT64TYPE_LITERAL_SUFFIX ""
199 #endif
200 
201 #ifndef INT128TYPE
202 #define INT128TYPE_STRI ""
203 #define UINT128TYPE_STRI ""
204 #endif
205 
206 #ifndef PATH_MAX
207 #define PATH_MAX 2048
208 #endif
209 
210 #define CLASSIC_WINDOWS_MAX_PATH 260
211 
212 #define SIZE_NORMAL_BUFFER   32768
213 #define SIZE_RESERVE_BUFFER   2048
214 
215 #define PRESERVE_NOTHING    0x00
216 #define PRESERVE_MODE       0x01
217 #define PRESERVE_OWNERSHIP  0x02
218 #define PRESERVE_TIMESTAMPS 0x04
219 #define PRESERVE_SYMLINKS   0x08
220 #define PRESERVE_ALL        0xFF
221 
222 #define USR_BITS_NORMAL (S_IRUSR == 0400 && S_IWUSR == 0200 && S_IXUSR == 0100)
223 #define GRP_BITS_NORMAL (S_IRGRP == 0040 && S_IWGRP == 0020 && S_IXGRP == 0010)
224 #define OTH_BITS_NORMAL (S_IROTH == 0004 && S_IWOTH == 0002 && S_IXOTH == 0001)
225 #define MODE_BITS_NORMAL (USR_BITS_NORMAL && GRP_BITS_NORMAL && OTH_BITS_NORMAL)
226 
227 #define INITAL_ARRAY_SIZE  256
228 #define ARRAY_SIZE_DELTA   256
229 
230 #define CONFIG_VALUE_BUFFER_SIZE 4096
231 
232 #if DECLARE_OS_ENVIRON
233 extern os_striType *os_environ;
234 #endif
235 
236 static const os_charType path_variable[] = {'P', 'A', 'T', 'H', 0};
237 
238 
239 #define driveLetterPathWrong(standardPath) \
240     (standardPath->size >= 2 && \
241      (standardPath->mem[standardPath->size - 1] == '/' || \
242       (standardPath->mem[1] == ':' && \
243       ((standardPath->mem[0] >= 'a' && standardPath->mem[0] <= 'z') || \
244        (standardPath->mem[0] >= 'A' && standardPath->mem[0] <= 'Z')))))
245 
246 #define standardPathWrong(standardPath) \
247     (standardPath->size >= 2 && \
248      standardPath->mem[standardPath->size - 1] == '/')
249 
250 
251 #ifdef DETERMINE_OS_PROPERTIES_AT_RUNTIME
252 
253 char *nullDevice;
254 unsigned char shellPathDelimiter;
255 boolType shellUsesDriveLetters;
256 #ifdef EMULATE_ENVIRONMENT
257 int (*environmentStrncmp) (const char *s1, const char *s2, size_t n);
258 #endif
259 #define NULL_DEVICE_FOR_SCRIPTS nullDevice
260 #define SHELL_PATH_DELIMITER shellPathDelimiter
261 #define if_pathDelimiterNotSlash(thenPart) if (shellPathDelimiter != '/') thenPart
262 #define pathIsWrong(standardPath) (shellUsesDriveLetters && driveLetterPathWrong(standardPath)) || \
263                                   (!shellUsesDriveLetters && standardPathWrong(standardPath))
264 #define if_mapAbsoluteShellPathToDriveLetters(cond, thenPart, elsePart) \
265     if (shellUsesDriveLetters && (cond)) thenPart else elsePart
266 
267 #else
268 
269 #define NULL_DEVICE_FOR_SCRIPTS NULL_DEVICE
270 #define SHELL_PATH_DELIMITER PATH_DELIMITER
271 
272 #if PATH_DELIMITER != '/'
273 #define if_pathDelimiterNotSlash(thenPart) thenPart
274 #else
275 #define if_pathDelimiterNotSlash(thenPart)
276 #endif
277 
278 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
279 #define pathIsWrong(standardPath) driveLetterPathWrong(standardPath)
280 #define if_mapAbsoluteShellPathToDriveLetters(cond, thenPart, elsePart) if (cond) thenPart else elsePart
281 #else
282 #define pathIsWrong(standardPath) standardPathWrong(standardPath)
283 #define if_mapAbsoluteShellPathToDriveLetters(cond, thenPart, elsePart) elsePart
284 #endif
285 
286 #endif
287 
288 
289 
290 #ifdef USE_CDECL
cmp_mem(char * strg1,char * strg2)291 static int _cdecl cmp_mem (char *strg1, char *strg2)
292 #else
293 static int cmp_mem (void const *strg1, void const *strg2)
294 #endif
295 
296   { /* cmp_mem */
297     return (int) strCompare(
298         ((const_rtlObjectType *) strg1)->value.striValue,
299         ((const_rtlObjectType *) strg2)->value.striValue);
300   } /* cmp_mem */
301 
302 
303 
304 static void remove_any_file (const const_os_striType file_name, errInfoType *);
305 static void copy_any_file (const const_os_striType from_name,
306     const const_os_striType to_name, int, errInfoType *err_info);
307 
308 
309 
remove_dir(const const_os_striType dir_name,errInfoType * err_info)310 static void remove_dir (const const_os_striType dir_name, errInfoType *err_info)
311 
312   {
313     os_DIR *directory;
314     os_dirent_struct *current_entry;
315     size_t dir_name_size;
316     size_t dir_path_capacity = 0;
317     os_striType dir_path = NULL;
318     size_t new_size;
319     os_striType resized_path;
320     boolType init_path = TRUE;
321 
322   /* remove_dir */
323     logFunction(printf("remove_dir(\"" FMT_S_OS "\")\n", dir_name););
324     if ((directory = os_opendir(dir_name)) == NULL) {
325       logError(printf("remove_dir: os_opendir(\"" FMT_S_OS "\") failed:\n"
326                       "errno=%d\nerror: %s\n",
327                       dir_name, errno, strerror(errno)););
328       *err_info = FILE_ERROR;
329     } else {
330       do {
331         current_entry = os_readdir(directory);
332 /*      printf("$" FMT_U_MEM "$\n", (memSizeType) current_entry);
333         fflush(stdout); */
334       } while (current_entry != NULL && current_entry->d_name[0] == '.' &&
335                (current_entry->d_name[1] == '\0' ||
336                 (current_entry->d_name[1] == '.' &&
337                  current_entry->d_name[2] == '\0')));
338       dir_name_size = os_stri_strlen(dir_name);
339       while (*err_info == OKAY_NO_ERROR && current_entry != NULL) {
340 /*      printf("!" FMT_S_OS "!\n", current_entry->d_name);
341         fflush(stdout); */
342         new_size = dir_name_size + 1 + os_stri_strlen(current_entry->d_name);
343         if (new_size > dir_path_capacity) {
344           resized_path = REALLOC_OS_STRI(dir_path, new_size);
345           if (resized_path != NULL) {
346             dir_path = resized_path;
347             dir_path_capacity = new_size;
348           } else if (dir_path != NULL) {
349             FREE_OS_STRI(dir_path);
350             dir_path = NULL;
351           } /* if */
352         } /* if */
353         if (dir_path != NULL) {
354           if (init_path) {
355             os_stri_strcpy(dir_path, dir_name);
356             os_stri_strcpy(&dir_path[dir_name_size], pathDelimiter);
357             init_path = FALSE;
358           } /* if */
359           os_stri_strcpy(&dir_path[dir_name_size + 1], current_entry->d_name);
360           remove_any_file(dir_path, err_info);
361         } else {
362           *err_info = MEMORY_ERROR;
363         } /* if */
364         do {
365           current_entry = os_readdir(directory);
366 /*        printf("$" FMT_U_MEM "$\n", (memSizeType) current_entry);
367           fflush(stdout); */
368         } while (current_entry != NULL && current_entry->d_name[0] == '.' &&
369                  (current_entry->d_name[1] == '\0' ||
370                   (current_entry->d_name[1] == '.' &&
371                    current_entry->d_name[2] == '\0')));
372       } /* while */
373       if (dir_path != NULL) {
374         FREE_OS_STRI(dir_path);
375       } /* if */
376       os_closedir(directory);
377       if (*err_info == OKAY_NO_ERROR) {
378         /* printf("before remove directory <" FMT_S_OS ">\n", dir_name); */
379         if (os_rmdir(dir_name) != 0) {
380           logError(printf("remove_dir: os_rmdir(\"" FMT_S_OS "\") failed:\n"
381                           "errno=%d\nerror: %s\n",
382                           dir_name, errno, strerror(errno)););
383           *err_info = FILE_ERROR;
384         } /* if */
385       } /* if */
386     } /* if */
387     logFunction(printf("remove_dir(\"" FMT_S_OS "\", %d) -->\n", dir_name, *err_info););
388   } /* remove_dir */
389 
390 
391 
remove_any_file(const const_os_striType file_name,errInfoType * err_info)392 static void remove_any_file (const const_os_striType file_name, errInfoType *err_info)
393 
394   {
395     os_stat_struct file_stat;
396 
397   /* remove_any_file */
398     logFunction(printf("remove_any_file(\"" FMT_S_OS "\")\n", file_name););
399     if (os_lstat(file_name, &file_stat) != 0) {
400       logError(printf("remove_any_file: os_lstat(" FMT_S_OS ", *) failed:\n"
401                       "errno=%d\nerror: %s\n",
402                       file_name, errno, strerror(errno)););
403       *err_info = FILE_ERROR;
404     } else {
405       if (S_ISDIR(file_stat.st_mode)) {
406         remove_dir(file_name, err_info);
407       } else {
408         if (os_remove(file_name) != 0) {
409           logError(printf("remove_any_file: os_remove(\"" FMT_S_OS "\") failed:\n"
410                           "errno=%d\nerror: %s\n",
411                           file_name, errno, strerror(errno)););
412           *err_info = FILE_ERROR;
413         } /* if */
414       } /* if */
415     } /* if */
416     logFunction(printf("remove_any_file(\"" FMT_S_OS "\", %d) -->\n",
417                        file_name, *err_info););
418   } /* remove_any_file */
419 
420 
421 
copy_file(const const_os_striType from_name,const const_os_striType to_name,errInfoType * err_info)422 static void copy_file (const const_os_striType from_name,
423     const const_os_striType to_name, errInfoType *err_info)
424 
425   {
426     FILE *from_file;
427     FILE *to_file;
428 #if HAS_MMAP
429     int file_no;
430     os_fstat_struct file_stat;
431     memSizeType file_length;
432     ustriType file_content;
433     boolType classic_copy = TRUE;
434 #endif
435     char *normal_buffer;
436     char *buffer;
437     size_t buffer_size;
438     char reserve_buffer[SIZE_RESERVE_BUFFER];
439     size_t bytes_read;
440 
441   /* copy_file */
442     logFunction(printf("copy_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\")\n",
443                        from_name, to_name););
444     if ((from_file = os_fopen(from_name, os_mode_rb)) != NULL) {
445       if ((to_file = os_fopen(to_name, os_mode_wb)) != NULL) {
446 #if HAS_MMAP
447         file_no = fileno(from_file);
448         if (file_no != -1 && os_fstat(file_no, &file_stat) == 0) {
449           if (file_stat.st_size >= 0 &&
450               (unsigned_os_off_t) file_stat.st_size < MAX_MEMSIZETYPE) {
451             file_length = (memSizeType) file_stat.st_size;
452             if ((file_content = (ustriType) mmap(NULL, file_length,
453                 PROT_READ, MAP_PRIVATE, file_no, 0)) != (ustriType) -1) {
454               if (fwrite(file_content, 1, file_length, to_file) != file_length) {
455                 logError(printf("copy_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\"): "
456                                 "fwrite(*, 1, " FMT_U_MEM ", %d) failed:\n"
457                                 "errno=%d\nerror: %s\n",
458                                 from_name, to_name, file_length, safe_fileno(to_file),
459                                 errno, strerror(errno)););
460                 *err_info = FILE_ERROR;
461               } /* if */
462               munmap(file_content, file_length);
463               classic_copy = FALSE;
464             } /* if */
465           } /* if */
466         } /* if */
467         if (classic_copy) {
468 #endif
469           if (ALLOC_BYTES(normal_buffer, SIZE_NORMAL_BUFFER)) {
470             buffer = normal_buffer;
471             buffer_size = SIZE_NORMAL_BUFFER;
472           } else {
473             buffer = reserve_buffer;
474             buffer_size = SIZE_RESERVE_BUFFER;
475           } /* if */
476           while (*err_info == OKAY_NO_ERROR && (bytes_read =
477               fread(buffer, 1, buffer_size, from_file)) != 0) {
478             if (fwrite(buffer, 1, bytes_read, to_file) != bytes_read) {
479               logError(printf("copy_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\"): "
480                               "fwrite(*, 1, " FMT_U_MEM ", %d) failed:\n"
481                               "errno=%d\nerror: %s\n",
482                               from_name, to_name, (memSizeType) bytes_read,
483                               safe_fileno(to_file), errno, strerror(errno)););
484               *err_info = FILE_ERROR;
485             } /* if */
486           } /* while */
487           if (normal_buffer != NULL) {
488             FREE_BYTES(normal_buffer, SIZE_NORMAL_BUFFER);
489           } /* if */
490 #if HAS_MMAP
491         } /* if */
492 #endif
493         if (fclose(from_file) != 0) {
494           logError(printf("copy_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\"): "
495                           "fclose(%d) failed:\n"
496                           "errno=%d\nerror: %s\n",
497                           from_name, to_name, safe_fileno(from_file),
498                           errno, strerror(errno)););
499           *err_info = FILE_ERROR;
500         } /* if */
501         if (fclose(to_file) != 0) {
502           logError(printf("copy_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\"): "
503                           "fclose(%d) failed:\n"
504                           "errno=%d\nerror: %s\n",
505                           from_name, to_name, safe_fileno(to_file),
506                           errno, strerror(errno)););
507           *err_info = FILE_ERROR;
508         } /* if */
509         if (unlikely(*err_info != OKAY_NO_ERROR)) {
510           os_remove(to_name);
511         } /* if */
512       } else {
513         logError(printf("copy_file: os_fopen(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
514                         "errno=%d\nerror: %s\n",
515                         to_name, os_mode_wb, errno, strerror(errno)););
516         fclose(from_file);
517         *err_info = FILE_ERROR;
518       } /* if */
519     } else {
520       logError(printf("copy_file: os_fopen(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
521                       "errno=%d\nerror: %s\n",
522                       from_name, os_mode_rb, errno, strerror(errno)););
523       *err_info = FILE_ERROR;
524     } /* if */
525     logFunction(printf("copy_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\", %d) -->\n",
526                        from_name, to_name, *err_info););
527   } /* copy_file */
528 
529 
530 
copy_dir(const const_os_striType from_name,const const_os_striType to_name,int flags,errInfoType * err_info)531 static void copy_dir (const const_os_striType from_name,
532     const const_os_striType to_name, int flags, errInfoType *err_info)
533 
534   {
535     os_DIR *directory;
536     os_dirent_struct *current_entry;
537     size_t from_name_size;
538     size_t to_name_size;
539     size_t d_name_size;
540     size_t from_path_capacity = 0;
541     os_striType from_path = NULL;
542     size_t to_path_capacity = 0;
543     os_striType to_path = NULL;
544     size_t new_size;
545     os_striType resized_path;
546     boolType init_path = TRUE;
547 
548   /* copy_dir */
549     logFunction(printf("copy_dir(\"" FMT_S_OS "\", \"" FMT_S_OS "\")\n",
550                        from_name, to_name););
551     if ((directory = os_opendir(from_name)) == NULL) {
552       logError(printf("copy_dir: os_opendir(\"" FMT_S_OS "\") failed:\n"
553                       "errno=%d\nerror: %s\n",
554                       from_name, errno, strerror(errno)););
555       *err_info = FILE_ERROR;
556     } else {
557       if (os_mkdir(to_name, (S_IRWXU | S_IRWXG | S_IRWXO)) != 0) {
558         logError(printf("copy_dir: os_mkdir(\"" FMT_S_OS "\", rwxrwxrwx) failed:\n"
559                         "errno=%d\nerror: %s\n",
560                         to_name, errno, strerror(errno)););
561         *err_info = FILE_ERROR;
562       } else {
563         do {
564           current_entry = os_readdir(directory);
565           /* printf("$" FMT_U_MEM "$\n", (memSizeType) current_entry);
566              fflush(stdout); */
567         } while (current_entry != NULL && current_entry->d_name[0] == '.' &&
568                  (current_entry->d_name[1] == '\0' ||
569                   (current_entry->d_name[1] == '.' &&
570                    current_entry->d_name[2] == '\0')));
571         from_name_size = os_stri_strlen(from_name);
572         to_name_size = os_stri_strlen(to_name);
573         while (*err_info == OKAY_NO_ERROR && current_entry != NULL) {
574           /* printf("!" FMT_S_OS "!\n", current_entry->d_name);
575              fflush(stdout); */
576           d_name_size = os_stri_strlen(current_entry->d_name);
577           new_size = from_name_size + 1 + d_name_size;
578           if (new_size > from_path_capacity) {
579             resized_path = REALLOC_OS_STRI(from_path, new_size);
580             if (resized_path != NULL) {
581               from_path = resized_path;
582               from_path_capacity = new_size;
583             } else if (from_path != NULL) {
584               FREE_OS_STRI(from_path);
585               from_path = NULL;
586             } /* if */
587           } /* if */
588           new_size = to_name_size + 1 + d_name_size;
589           if (new_size > to_path_capacity) {
590             resized_path = REALLOC_OS_STRI(to_path, new_size);
591             if (resized_path != NULL) {
592               to_path = resized_path;
593               to_path_capacity = new_size;
594             } else if (to_path != NULL) {
595               FREE_OS_STRI(to_path);
596               to_path = NULL;
597             } /* if */
598           } /* if */
599           if (from_path != NULL && to_path != NULL) {
600             if (init_path) {
601               os_stri_strcpy(from_path, from_name);
602               os_stri_strcpy(&from_path[from_name_size], pathDelimiter);
603               os_stri_strcpy(to_path, to_name);
604               os_stri_strcpy(&to_path[to_name_size], pathDelimiter);
605               init_path = FALSE;
606             } /* if */
607             os_stri_strcpy(&from_path[from_name_size + 1], current_entry->d_name);
608             os_stri_strcpy(&to_path[to_name_size + 1], current_entry->d_name);
609             copy_any_file(from_path, to_path, flags, err_info);
610           } else {
611             *err_info = MEMORY_ERROR;
612           } /* if */
613           do {
614             current_entry = os_readdir(directory);
615             /* printf("$" FMT_U_MEM "$\n", (memSizeType) current_entry);
616                fflush(stdout); */
617           } while (current_entry != NULL && current_entry->d_name[0] == '.' &&
618                    (current_entry->d_name[1] == '\0' ||
619                     (current_entry->d_name[1] == '.' &&
620                      current_entry->d_name[2] == '\0')));
621         } /* while */
622         if (unlikely(*err_info != OKAY_NO_ERROR)) {
623           remove_dir(to_name, err_info);
624         } /* if */
625         if (from_path != NULL) {
626           FREE_OS_STRI(from_path);
627         } /* if */
628         if (to_path != NULL) {
629           FREE_OS_STRI(to_path);
630         } /* if */
631       } /* if */
632       os_closedir(directory);
633     } /* if */
634     logFunction(printf("copy_dir(\"" FMT_S_OS "\", \"" FMT_S_OS "\", %d) -->\n",
635                        from_name, to_name, *err_info););
636   } /* copy_dir */
637 
638 
639 
copy_any_file(const const_os_striType from_name,const const_os_striType to_name,int flags,errInfoType * err_info)640 static void copy_any_file (const const_os_striType from_name,
641     const const_os_striType to_name, int flags, errInfoType *err_info)
642 
643   {
644     os_stat_struct from_stat;
645     int from_stat_result;
646 #if HAS_SYMBOLIC_LINKS
647     os_striType link_destination;
648     ssize_t readlink_result;
649 #endif
650     os_utimbuf_struct to_utime;
651 
652   /* copy_any_file */
653     logFunction(printf("copy_any_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\")\n",
654                        from_name, to_name););
655     if (flags & PRESERVE_SYMLINKS) {
656       from_stat_result = os_lstat(from_name, &from_stat);
657     } else {
658       from_stat_result = os_stat(from_name, &from_stat);
659     } /* if */
660     if (from_stat_result != 0) {
661       /* Source file does not exist */
662       logError(printf("copy_any_file: os_%sstat(\"" FMT_S_OS "\", *) failed:\n"
663                       "errno=%d\nerror: %s\n",
664                       flags & PRESERVE_SYMLINKS ? "l" : "",
665                       from_name, errno, strerror(errno)););
666       *err_info = FILE_ERROR;
667     } else {
668       if (S_ISLNK(from_stat.st_mode)) {
669 #if HAS_SYMBOLIC_LINKS
670         /* printf("link size=%lu\n", from_stat.st_size); */
671         if (unlikely(from_stat.st_size < 0 ||
672                      (unsigned_os_off_t) from_stat.st_size > MAX_OS_STRI_LEN)) {
673           *err_info = RANGE_ERROR;
674         } else {
675           if (unlikely(!os_stri_alloc(link_destination,
676                                       (memSizeType) from_stat.st_size))) {
677             *err_info = MEMORY_ERROR;
678           } else {
679             readlink_result = readlink(from_name, link_destination,
680                                        (size_t) from_stat.st_size);
681             if (unlikely(readlink_result != -1)) {
682               link_destination[readlink_result] = '\0';
683               /* printf("readlink_result=%lu\n", readlink_result);
684                  printf("link=" FMT_S_OS "\n", link_destination); */
685               if (symlink(link_destination, to_name) != 0) {
686                 *err_info = FILE_ERROR;
687               } /* if */
688             } else {
689               *err_info = FILE_ERROR;
690             } /* if */
691             os_stri_free(link_destination);
692           } /* if */
693         } /* if */
694 #else
695         *err_info = FILE_ERROR;
696 #endif
697       } else if (S_ISREG(from_stat.st_mode)) {
698         copy_file(from_name, to_name, err_info);
699       } else if (S_ISDIR(from_stat.st_mode)) {
700         copy_dir(from_name, to_name, flags, err_info);
701       } else if (S_ISFIFO(from_stat.st_mode)) {
702 #if HAS_FIFO_FILES
703         if (mkfifo(to_name, (S_IRWXU | S_IRWXG | S_IRWXO)) != 0) {
704           *err_info = FILE_ERROR;
705         } /* if */
706 #else
707         *err_info = FILE_ERROR;
708 #endif
709       } else {
710         *err_info = FILE_ERROR;
711       } /* if */
712       if (*err_info == OKAY_NO_ERROR && !S_ISLNK(from_stat.st_mode)) {
713         if (flags & PRESERVE_TIMESTAMPS) {
714           to_utime.actime = from_stat.st_atime;
715           to_utime.modtime = from_stat.st_mtime;
716           /* printf("copy_any_file: st_atime=%ld\n", from_stat.st_atime); */
717           /* printf("copy_any_file: st_mtime=%ld\n", from_stat.st_mtime); */
718           os_utime(to_name, &to_utime);
719         } /* if */
720         if (flags & PRESERVE_MODE) {
721           os_chmod(to_name, from_stat.st_mode);
722         } /* if */
723         if (flags & PRESERVE_OWNERSHIP) {
724           os_chown(to_name, from_stat.st_uid, from_stat.st_gid);
725         } /* if */
726       } /* if */
727     } /* if */
728     logFunction(printf("copy_any_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\", %d) -->\n",
729                        from_name, to_name, *err_info););
730   } /* copy_any_file */
731 
732 
733 
move_with_copy(const const_os_striType from_name,const const_os_striType to_name,errInfoType * err_info)734 static void move_with_copy (const const_os_striType from_name,
735     const const_os_striType to_name, errInfoType *err_info)
736 
737   {
738     os_striType temp_name;
739 
740   /* move_with_copy */
741     logFunction(printf("move_with_copy(\"" FMT_S_OS "\", \"" FMT_S_OS "\")\n",
742                        from_name, to_name););
743     temp_name = temp_name_in_dir(from_name);
744     if (unlikely(temp_name == NULL)) {
745       *err_info = MEMORY_ERROR;
746     } else {
747       if (os_rename(from_name, temp_name) != 0) {
748         logError(printf("move_with_copy: "
749                         "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
750                         "errno=%d\nerror: %s\n",
751                         from_name, temp_name, errno, strerror(errno)););
752         *err_info = FILE_ERROR;
753       } else {
754         copy_any_file(temp_name, to_name, PRESERVE_ALL, err_info);
755         if (*err_info == OKAY_NO_ERROR) {
756           remove_any_file(temp_name, err_info);
757         } else {
758           /* Rename back to the original name. */
759           if (os_rename(temp_name, from_name) != 0) {
760             logError(printf("move_with_copy: "
761                             "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
762                             "errno=%d\nerror: %s\n",
763                             temp_name, from_name, errno, strerror(errno)););
764           } /* if */
765         } /* if */
766       } /* if */
767       os_stri_free(temp_name);
768     } /* if */
769     logFunction(printf("move_with_copy(\"" FMT_S_OS "\", \"" FMT_S_OS "\", %d) -->\n",
770                        from_name, to_name, *err_info););
771   } /* move_with_copy */
772 
773 
774 
775 #ifdef USE_EACCES_INSTEAD_OF_EXDEV
devices_differ(const const_os_striType from_name,const const_os_striType to_name)776 static boolType devices_differ (const const_os_striType from_name,
777     const const_os_striType to_name)
778 
779   {
780     os_stat_struct from_stat;
781     os_stat_struct dir_stat;
782     memSizeType to_name_length;
783     memSizeType pos;
784     memSizeType dir_name_length;
785     os_striType dir_name;
786     boolType differs = TRUE;
787 
788   /* devices_differ */
789     if (os_stat(from_name, &from_stat) == 0) {
790       to_name_length = os_stri_strlen(to_name);
791       pos = to_name_length;
792       while (pos > 0 && to_name[pos - 1] != '/' && to_name[pos - 1] != '\\') {
793         pos--;
794       } /* while */
795       if (pos > 0) {
796         dir_name_length = pos;
797         if (likely(os_stri_alloc(dir_name, dir_name_length))) {
798           memcpy(dir_name, to_name, dir_name_length * sizeof(os_charType));
799           dir_name[dir_name_length] = '\0';
800           /* printf("dir_name: " FMT_S_OS "\n", dir_name); */
801           if (os_stat(dir_name, &dir_stat) == 0) {
802             /* printf("from device: %ld, to device: %ld\n",
803                from_stat.st_dev, dir_stat.st_dev); */
804             differs = from_stat.st_dev != dir_stat.st_dev;
805           } /* if */
806           os_stri_free(dir_name);
807         } /* if */
808       } /* if */
809     } /* if */
810     logFunction(printf("devices_differ(" FMT_S_OS ", " FMT_S_OS ") --> %d\n",
811                        from_name, to_name, differs););
812     return differs;
813   } /* devices_differ */
814 #endif
815 
816 
817 
move_any_file(const const_os_striType from_name,const const_os_striType to_name,errInfoType * err_info)818 static void move_any_file (const const_os_striType from_name,
819     const const_os_striType to_name, errInfoType *err_info)
820 
821   {
822     os_stat_struct to_stat;
823 
824   /* move_any_file */
825     logFunction(printf("move_any_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\")\n",
826                        from_name, to_name););
827     if (os_stat(to_name, &to_stat) == 0) {
828       logError(printf("move_any_file: "
829                       "Destination " FMT_S_OS " exists already.\n",
830                       to_name););
831       *err_info = FILE_ERROR;
832     } else {
833       if (os_rename(from_name, to_name) != 0) {
834         switch (errno) {
835 #ifdef EXDEV
836           case EXDEV:
837             /* printf("move_any_file: "
838                 "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") triggers EXDEV\n",
839                 from_name, to_name); */
840             move_with_copy(from_name, to_name, err_info);
841             break;
842 #endif
843 #ifdef USE_EACCES_INSTEAD_OF_EXDEV
844           case EACCES:
845             /* printf("move_any_file: "
846                 "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") triggers EACCES\n",
847                 from_name, to_name); */
848             if (devices_differ(from_name, to_name)) {
849               move_with_copy(from_name, to_name, err_info);
850             } else {
851               logError(printf("move_any_file: "
852                               "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
853                               "errno=%d\nerror: %s\n",
854                               from_name, to_name, EACCES, strerror(EACCES)););
855             } /* if */
856             break;
857 #endif
858           default:
859             logError(printf("move_any_file: "
860                             "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
861                             "errno=%d\nerror: %s\n",
862                             from_name, to_name, errno, strerror(errno)););
863             *err_info = FILE_ERROR;
864             break;
865         } /* switch */
866       } /* if */
867     } /* if */
868     logFunction(printf("move_any_file(\"" FMT_S_OS "\", \"" FMT_S_OS "\", %d) -->\n",
869                        from_name, to_name, *err_info););
870   } /* move_any_file */
871 
872 
873 
addStriToRtlArray(const striType stri,rtlArrayType work_array,intType used_max_position)874 static rtlArrayType addStriToRtlArray (const striType stri,
875     rtlArrayType work_array, intType used_max_position)
876 
877   {
878     rtlArrayType resized_work_array;
879 
880   /* addStriToRtlArray */
881     logFunction(printf("addStriToRtlArray(\"%s\", *, " FMT_D ")\n",
882                        striAsUnquotedCStri(stri), used_max_position););
883     if (used_max_position >= work_array->max_position) {
884       if (unlikely(work_array->max_position > (intType) (MAX_RTL_ARR_INDEX - ARRAY_SIZE_DELTA) ||
885           (resized_work_array = REALLOC_RTL_ARRAY(work_array,
886               (uintType) work_array->max_position,
887               (uintType) work_array->max_position + ARRAY_SIZE_DELTA)) == NULL)) {
888         FREE_STRI(stri, stri->size);
889         freeRtlStriArray(work_array, used_max_position);
890         work_array = NULL;
891       } else {
892         work_array = resized_work_array;
893         COUNT3_RTL_ARRAY((uintType) work_array->max_position,
894             (uintType) work_array->max_position + ARRAY_SIZE_DELTA);
895         work_array->max_position += ARRAY_SIZE_DELTA;
896         work_array->arr[used_max_position].value.striValue = stri;
897       } /* if */
898     } else {
899       work_array->arr[used_max_position].value.striValue = stri;
900     } /* if */
901     return work_array;
902   } /* addStriToRtlArray */
903 
904 
905 
completeRtlStriArray(rtlArrayType work_array,intType used_max_position)906 static rtlArrayType completeRtlStriArray (rtlArrayType work_array,
907     intType used_max_position)
908 
909   {
910     rtlArrayType resized_work_array;
911 
912   /* completeRtlStriArray */
913     if (likely(work_array != NULL)) {
914       resized_work_array = REALLOC_RTL_ARRAY(work_array,
915           (uintType) work_array->max_position, (uintType) used_max_position);
916       if (unlikely(resized_work_array == NULL)) {
917         freeRtlStriArray(work_array, used_max_position);
918         work_array = NULL;
919       } else {
920         work_array = resized_work_array;
921         COUNT3_RTL_ARRAY((uintType) work_array->max_position,
922                          (uintType) used_max_position);
923         work_array->max_position = used_max_position;
924       } /* if */
925     } /* if */
926     return work_array;
927   } /* completeRtlStriArray */
928 
929 
930 
read_dir(const const_striType dir_name,errInfoType * err_info)931 static rtlArrayType read_dir (const const_striType dir_name, errInfoType *err_info)
932 
933   {
934     intType used_max_position;
935     dirType directory;
936     striType nameStri;
937     rtlArrayType dir_array;
938 
939   /* read_dir */
940     logFunction(printf("read_dir(\"%s\", *)\n",
941                        striAsUnquotedCStri(dir_name)););
942     if (unlikely((directory = dirOpen(dir_name)) == NULL)) {
943       logError(printf("read_dir: dirOpen(\"%s\") failed.\n",
944                       striAsUnquotedCStri(dir_name)););
945       dir_array = NULL;
946       *err_info = FILE_ERROR;
947     } else {
948       if (likely(ALLOC_RTL_ARRAY(dir_array, INITAL_ARRAY_SIZE))) {
949         dir_array->min_position = 1;
950         dir_array->max_position = INITAL_ARRAY_SIZE;
951         used_max_position = 0;
952         nameStri = dirRead(directory);
953         if (nameStri != NULL) {
954           do {
955             dir_array = addStriToRtlArray(nameStri, dir_array,
956                 used_max_position);
957             used_max_position++;
958             nameStri = dirRead(directory);
959           } while (nameStri != NULL && dir_array != NULL);
960         } /* if */
961         if (unlikely(nameStri != NULL)) {
962           FREE_STRI(nameStri, nameStri->size);
963         } /* if */
964         dir_array = completeRtlStriArray(dir_array, used_max_position);
965         if (unlikely(dir_array == NULL)) {
966           *err_info = MEMORY_ERROR;
967         } /* if */
968       } else {
969         *err_info = MEMORY_ERROR;
970       } /* if */
971       dirClose(directory);
972     } /* if */
973     return dir_array;
974   } /* read_dir */
975 
976 
977 
978 #ifdef os_setenv
setEnvironmentVariable(const const_striType name,const const_striType value,errInfoType * err_info)979 static void setEnvironmentVariable (const const_striType name, const const_striType value,
980     errInfoType *err_info)
981 
982   {
983     os_striType env_name;
984     os_striType env_value;
985     int setenv_result;
986     int saved_errno;
987 
988   /* setEnvironmentVariable */
989     logFunction(printf("setEnvironmentVariable(\"%s\", ",
990                        striAsUnquotedCStri(name));
991                 printf("\"%s\", *)\n",
992                        striAsUnquotedCStri(value)););
993     env_name = stri_to_os_stri(name, err_info);
994     if (likely(env_name != NULL)) {
995       env_value = stri_to_os_stri(value, err_info);
996       if (likely(env_value != NULL)) {
997         setenv_result = os_setenv(env_name, env_value, 1);
998         saved_errno = errno;
999         os_stri_free(env_value);
1000         if (unlikely(setenv_result != 0)) {
1001           logError(printf("setEnvironmentVariable: "
1002                           "os_setenv(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
1003                           "errno=%d\nerror: %s\n",
1004                           env_name, env_value, saved_errno, strerror(saved_errno)););
1005           if (saved_errno == ENOMEM) {
1006             *err_info = MEMORY_ERROR;
1007           } else {
1008             *err_info = RANGE_ERROR;
1009           } /* if */
1010         } /* if */
1011       } /* if */
1012       /* printf("getenv7(\"%s\"): \"%s\"\n", env_name, os_getenv(env_name)); */
1013       os_stri_free(env_name);
1014     } /* if */
1015     logFunction(printf("setEnvironmentVariable -->\n"););
1016   } /* setEnvironmentVariable */
1017 
1018 #else
1019 
1020 
1021 
setEnvironmentVariable(const const_striType name,const const_striType value,errInfoType * err_info)1022 static void setEnvironmentVariable (const const_striType name, const const_striType value,
1023     errInfoType *err_info)
1024 
1025   {
1026     memSizeType stri_size;
1027     striType stri;
1028     os_striType env_stri;
1029     int putenv_result;
1030 
1031   /* setEnvironmentVariable */
1032     logFunction(printf("setEnvironmentVariable(\"%s\", ",
1033                        striAsUnquotedCStri(name));
1034                 printf("\"%s\", *)\n",
1035                        striAsUnquotedCStri(value)););
1036     if (strChPos(name, (charType) '=') != 0) {
1037       logError(printf("setEnvironmentVariable(\"%s\", ",
1038                       striAsUnquotedCStri(name));
1039                printf("\"%s\", *): "
1040                       "Name contains '=' (putenv() works with \"name=value\").\n",
1041                       striAsUnquotedCStri(value)););
1042       *err_info = RANGE_ERROR;
1043     } else if (unlikely(name->size > MAX_STRI_LEN - value->size - 1)) {
1044       /* Number of bytes does not fit into memSizeType. */
1045       *err_info = MEMORY_ERROR;
1046     } else {
1047       stri_size = name->size + value->size + 1;
1048       if (unlikely(!ALLOC_STRI_SIZE_OK(stri, stri_size))) {
1049         *err_info = MEMORY_ERROR;
1050       } else {
1051         stri->size = stri_size;
1052         memcpy(stri->mem, name->mem,
1053             name->size * sizeof(strElemType));
1054         stri->mem[name->size] = (strElemType) '=';
1055         memcpy(&stri->mem[name->size + 1], value->mem,
1056             value->size * sizeof(strElemType));
1057         env_stri = stri_to_os_stri(stri, err_info);
1058         FREE_STRI(stri, stri->size);
1059         if (likely(env_stri != NULL)) {
1060           putenv_result = os_putenv(env_stri);
1061           if (unlikely(putenv_result != 0)) {
1062             logError(printf("setEnvironmentVariable: os_putenv(\"" FMT_S_OS "\") failed:\n"
1063                             "errno=%d\nerror: %s\n",
1064                             env_stri, errno, strerror(errno)););
1065             *err_info = RANGE_ERROR;
1066           } /* if */
1067 #if DELETE_PUTENV_ARGUMENT
1068           os_stri_free(env_stri);
1069 #endif
1070         } /* if */
1071       } /* if */
1072     } /* if */
1073     logFunction(printf("setEnvironmentVariable -->\n"););
1074   } /* setEnvironmentVariable */
1075 
1076 #endif
1077 
1078 
1079 
1080 #if SEARCH_PATH_DELIMITER != 0
1081 #define getSearchPathDelimiter(path) SEARCH_PATH_DELIMITER
1082 #else
1083 
1084 
1085 
getSearchPathDelimiter(os_striType path)1086 static os_charType getSearchPathDelimiter (os_striType path)
1087 
1088   {
1089     static os_charType searchPathDelimiter = 0;
1090     boolType colonFound = FALSE;
1091 
1092   /* getSearchPathDelimiter */
1093     if (searchPathDelimiter == 0) {
1094       if (SEARCH_PATH_DELIMITER != 0) {
1095         searchPathDelimiter = SEARCH_PATH_DELIMITER;
1096       } else if (path != NULL) {
1097         /* Try to guess the search path delimiter. */
1098         if (((path[0] >= 'a' && path[0] <= 'z') ||
1099              (path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':') {
1100           searchPathDelimiter = ';';
1101         } else {
1102           while (*path != '\0' && searchPathDelimiter == 0) {
1103             if (*path == ';' &&
1104                 ((path[1] >= 'a' && path[1] <= 'z') ||
1105                  (path[1] >= 'A' && path[1] <= 'Z')) && path[2] == ':') {
1106               searchPathDelimiter = ';';
1107             } else if (*path == ':') {
1108               colonFound = TRUE;
1109             } /* if */
1110             path++;
1111           } /* while */
1112           if (searchPathDelimiter == 0 && colonFound) {
1113             searchPathDelimiter = ':';
1114           } /* if */
1115         } /* if */
1116       } /* if */
1117     } /* if */
1118     return searchPathDelimiter;
1119   } /* getSearchPathDelimiter */
1120 
1121 #endif
1122 
1123 
1124 
getSearchPath(errInfoType * err_info)1125 static rtlArrayType getSearchPath (errInfoType *err_info)
1126 
1127   {
1128     os_striType search_path_value;
1129     os_charType searchPathDelimiter;
1130     memSizeType path_length;
1131     os_striType path_copy;
1132     os_striType path_start;
1133     os_striType path_end;
1134     striType pathStri;
1135     intType used_max_position;
1136     rtlArrayType path_array;
1137 
1138   /* getSearchPath */
1139     logFunction(printf("getSearchPath(*)\n"););
1140     search_path_value = os_getenv(path_variable);
1141     searchPathDelimiter = getSearchPathDelimiter(search_path_value);
1142     if (unlikely(searchPathDelimiter == 0)) {
1143       logError(printf("getSearchPath(*): "
1144                       "Unable to determine the search path delimiter."););
1145       path_array = NULL;
1146       *err_info = FILE_ERROR;
1147     } else if (unlikely(!ALLOC_RTL_ARRAY(path_array, INITAL_ARRAY_SIZE))) {
1148       *err_info = MEMORY_ERROR;
1149     } else {
1150       path_array->min_position = 1;
1151       path_array->max_position = INITAL_ARRAY_SIZE;
1152       used_max_position = 0;
1153       if (search_path_value != NULL) {
1154         /* printf("path: " FMT_S_OS "\n", search_path_value); */
1155         path_length = os_stri_strlen(search_path_value);
1156         if (unlikely(!os_stri_alloc(path_copy, path_length))) {
1157           *err_info = MEMORY_ERROR;
1158         } else {
1159           os_stri_strcpy(path_copy, search_path_value);
1160           path_start = path_copy;
1161           do {
1162             path_end = os_stri_strchr(path_start, searchPathDelimiter);
1163             if (path_end != NULL) {
1164               *path_end = '\0';
1165             } /* if */
1166             pathStri = cp_from_os_path(path_start, err_info);
1167             if (likely(pathStri != NULL)) {
1168               path_array = addStriToRtlArray(pathStri, path_array,
1169                   used_max_position);
1170               used_max_position++;
1171             } /* if */
1172             if (path_end == NULL) {
1173               path_start = NULL;
1174             } else {
1175               path_start = path_end + 1;
1176             } /* if */
1177           } while (path_start != NULL && path_array != NULL);
1178           os_stri_free(path_copy);
1179         } /* if */
1180       } /* if */
1181       path_array = completeRtlStriArray(path_array, used_max_position);
1182       if (unlikely(path_array == NULL)) {
1183         *err_info = MEMORY_ERROR;
1184       } /* if */
1185     } /* if */
1186     if (search_path_value != NULL) {
1187       os_getenv_string_free(search_path_value);
1188     } /* if */
1189     logFunction(printf("getSearchPath --> " FMT_U_MEM
1190                        " (size=" FMT_U_MEM ", err_info=%d)\n",
1191                        (memSizeType) path_array,
1192                        path_array != NULL ? arraySize(path_array) : 0,
1193                        *err_info););
1194     return path_array;
1195   } /* getSearchPath */
1196 
1197 
1198 
setSearchPath(rtlArrayType searchPath,errInfoType * err_info)1199 static void setSearchPath (rtlArrayType searchPath, errInfoType *err_info)
1200 
1201   {
1202     os_charType searchPathDelimiter;
1203     memSizeType numElements;
1204     memSizeType idx;
1205     memSizeType length = 0;
1206     memSizeType pos;
1207     striType pathElement;
1208     striType pathStri;
1209     striType pathVariableName;
1210 
1211   /* setSearchPath */
1212     logFunction(printf("setSearchPath(" FMT_U_MEM " (size = " FMT_U_MEM "), *)\n",
1213                        (memSizeType) searchPath,
1214                        searchPath != NULL ? arraySize(searchPath) : 0););
1215     searchPathDelimiter = getSearchPathDelimiter(NULL);
1216     if (searchPathDelimiter == 0) {
1217       searchPathDelimiter = getSearchPathDelimiter(os_getenv(path_variable));
1218     } /* if */
1219     if (unlikely(searchPathDelimiter == 0)) {
1220       logError(printf("setSearchPath(*): "
1221                       "Unable to determine the search path delimiter."););
1222       *err_info = FILE_ERROR;
1223     } else {
1224       numElements = arraySize(searchPath);
1225       if (numElements != 0) {
1226         for (idx = 0; idx < numElements; idx++) {
1227           length += searchPath->arr[idx].value.striValue->size;
1228         } /* for */
1229         length += numElements - 1;
1230       } /* if */
1231       if (!ALLOC_STRI_SIZE_OK(pathStri, length)) {
1232         *err_info = MEMORY_ERROR;
1233       } else {
1234         pathStri->size = length;
1235         if (numElements != 0) {
1236           pathElement = searchPath->arr[0].value.striValue;
1237           memcpy(pathStri->mem, pathElement->mem, pathElement->size * sizeof(strElemType));
1238           pos = pathElement->size;
1239           for (idx = 1; idx < numElements; idx++) {
1240             pathStri->mem[pos] = (charType) searchPathDelimiter;
1241             pos++;
1242             pathElement = searchPath->arr[idx].value.striValue;
1243             memcpy(&pathStri->mem[pos], pathElement->mem,
1244                    pathElement->size * sizeof(strElemType));
1245             pos += pathElement->size;
1246           } /* for */
1247         } /* if */
1248         pathVariableName = CSTRI_LITERAL_TO_STRI("PATH");
1249         if (pathVariableName == NULL) {
1250           *err_info = MEMORY_ERROR;
1251         } else {
1252           setEnvironmentVariable(pathVariableName, pathStri, err_info);
1253           FREE_STRI(pathVariableName, pathVariableName->size);
1254         } /* if */
1255         FREE_STRI(pathStri, pathStri->size);
1256       } /* if */
1257     } /* if */
1258     logFunction(printf("setSearchPath --> (err_info=%d)\n",
1259                        *err_info););
1260   } /* setSearchPath */
1261 
1262 
1263 
getFileTypeSL(const const_striType filePath,errInfoType * err_info)1264 static intType getFileTypeSL (const const_striType filePath, errInfoType *err_info)
1265 
1266   {
1267     os_striType os_path;
1268     os_stat_struct stat_buf;
1269     int stat_result;
1270     int path_info = PATH_IS_NORMAL;
1271     int saved_errno;
1272     intType type_of_file;
1273 
1274   /* getFileTypeSL */
1275     logFunction(printf("getFileTypeSL(\"%s\")\n",
1276                        striAsUnquotedCStri(filePath)););
1277     os_path = cp_to_os_path(filePath, &path_info, err_info);
1278     if (unlikely(os_path == NULL)) {
1279 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
1280       if (path_info == PATH_IS_EMULATED_ROOT) {
1281         type_of_file = FILE_DIR;
1282       } else if (path_info == PATH_NOT_MAPPED) {
1283         type_of_file = FILE_ABSENT;
1284       } else
1285 #endif
1286       {
1287         logError(printf("getFileTypeSL: cp_to_os_path(\"%s\", *, *) failed:\n"
1288                         "path_info=%d, err_info=%d\n",
1289                         striAsUnquotedCStri(filePath), path_info, *err_info););
1290         type_of_file = FILE_ABSENT;
1291       }
1292     } else {
1293       stat_result = os_lstat(os_path, &stat_buf);
1294       saved_errno = errno;
1295       /* printf("lstat(\"" FMT_S_OS "\") returns: %d, errno=%d\n",
1296           os_path, stat_result, saved_errno); */
1297       if (stat_result == 0) {
1298         if (S_ISREG(stat_buf.st_mode)) {
1299           type_of_file = FILE_REGULAR;
1300         } else if (S_ISDIR(stat_buf.st_mode)) {
1301           type_of_file = FILE_DIR;
1302         } else if (S_ISCHR(stat_buf.st_mode)) {
1303           type_of_file = FILE_CHAR;
1304         } else if (S_ISBLK(stat_buf.st_mode)) {
1305           type_of_file = FILE_BLOCK;
1306         } else if (S_ISFIFO(stat_buf.st_mode)) {
1307           type_of_file = FILE_FIFO;
1308         } else if (S_ISLNK(stat_buf.st_mode)) {
1309           type_of_file = FILE_SYMLINK;
1310         } else if (S_ISSOCK(stat_buf.st_mode)) {
1311           type_of_file = FILE_SOCKET;
1312         } else {
1313           type_of_file = FILE_UNKNOWN;
1314         } /* if */
1315       } else {
1316         type_of_file = FILE_ABSENT;
1317         if (unlikely(filePath->size != 0 && saved_errno != ENOENT &&
1318                      saved_errno != ENOTDIR && saved_errno != ENAMETOOLONG &&
1319                      saved_errno != EACCES)) {
1320           logError(printf("getFileTypeSL: os_lstat(\"" FMT_S_OS "\") failed:\n"
1321                           "errno=%d\nerror: %s\n",
1322                           os_path, saved_errno, strerror(saved_errno)););
1323           /* printf("filePath->size=%lu\n", filePath->size); */
1324           /* printf("strlen(os_path)=%d\n", os_stri_strlen(os_path)); */
1325           *err_info = FILE_ERROR;
1326         } /* if */
1327       } /* if */
1328       os_stri_free(os_path);
1329     } /* if */
1330     logFunction(printf("getFileTypeSL(\"%s\") --> " FMT_D " (err_info=%d)\n",
1331                        striAsUnquotedCStri(filePath),
1332                        type_of_file, *err_info););
1333     return type_of_file;
1334   } /* getFileTypeSL */
1335 
1336 
1337 
1338 #if HAS_READLINK
1339 /**
1340  *  Reads the destination of a symbolic link.
1341  *  @param err_info Unchanged if the function succeeds, and
1342  *                  MEMORY_ERROR if a memory allocation failed, and
1343  *                  RANGE_ERROR if the conversion to the system path failed, and
1344  *                  FILE_ERROR if the file does not exist or is not a symbolic link.
1345  *  @return The destination referred by the symbolic link, or
1346  *          NULL if an error occurred.
1347  */
doReadLink(const const_striType filePath,errInfoType * err_info)1348 striType doReadLink (const const_striType filePath, errInfoType *err_info)
1349 
1350   {
1351     os_striType os_filePath;
1352     os_stat_struct link_stat;
1353     memSizeType link_size;
1354     os_striType link_destination;
1355     os_charType buffer[PATH_MAX];
1356     ssize_t readlink_result;
1357     int path_info;
1358     striType destination = NULL;
1359 
1360   /* doReadLink */
1361     logFunction(printf("doReadLink(\"%s\", %d)\n",
1362                        striAsUnquotedCStri(filePath), *err_info););
1363     os_filePath = cp_to_os_path(filePath, &path_info, err_info);
1364     if (unlikely(os_filePath == NULL)) {
1365       logError(printf("cmdReadLink: cp_to_os_path(\"%s\", *, *) failed:\n"
1366                       "path_info=%d, err_info=%d\n",
1367                       striAsUnquotedCStri(filePath), path_info, *err_info););
1368     } else {
1369       if (unlikely(os_lstat(os_filePath, &link_stat) != 0)) {
1370         logError(printf("cmdReadLink: os_lstat(" FMT_S_OS ", *) failed:\n"
1371                         "errno=%d\nerror: %s\n",
1372                         os_filePath, errno, strerror(errno)););
1373         *err_info = FILE_ERROR;
1374       } else if (unlikely(!S_ISLNK(link_stat.st_mode))) {
1375         logError(printf("cmdReadLink: "
1376                         "The file " FMT_S_OS " is not a symbolic link.\n",
1377                         os_filePath););
1378         *err_info = FILE_ERROR;
1379       } else if (unlikely(link_stat.st_size < 0 ||
1380                           (unsigned_os_off_t) link_stat.st_size > MAX_OS_STRI_LEN)) {
1381         *err_info = FILE_ERROR;
1382       } else {
1383         link_size = (memSizeType) link_stat.st_size;
1384         /* printf("link size=" FMT_U_MEM "\n", link_size); */
1385         if (link_size < sizeof(buffer)) {
1386           link_size = (memSizeType) sizeof(buffer) - NULL_TERMINATION_LEN;
1387           link_destination = buffer;
1388         } else if (unlikely(!os_stri_alloc(link_destination, link_size))) {
1389           *err_info = MEMORY_ERROR;
1390         } /* if */
1391         if (likely(link_destination != NULL)) {
1392           readlink_result = readlink(os_filePath, link_destination,
1393                                      (size_t) (link_size + NULL_TERMINATION_LEN));
1394           if (unlikely(readlink_result == -1)) {
1395             logError(printf("cmdReadLink: "
1396                             "readlink(\"" FMT_S_OS "\", *, " FMT_U_MEM ") failed:\n"
1397                             "errno=%d\nerror: %s\n",
1398                             os_filePath, link_size + NULL_TERMINATION_LEN,
1399                             errno, strerror(errno)););
1400             *err_info = FILE_ERROR;
1401           } else if (unlikely(readlink_result > link_size)) {
1402             logError(printf("cmdReadLink: "
1403                             "readlink(\"" FMT_S_OS "\", *, " FMT_U_MEM ") failed:\n"
1404                             "Link destination possibly truncated.\n",
1405                             os_filePath, link_size + NULL_TERMINATION_LEN););
1406             *err_info = FILE_ERROR;
1407           } else {
1408             link_destination[readlink_result] = '\0';
1409             destination = cp_from_os_path(link_destination, err_info);
1410             if (unlikely(destination == NULL)) {
1411               logError(printf("cmdReadLink: "
1412                               "cp_from_os_path(\"" FMT_S_OS "\", *) failed:\n"
1413                               "err_info=%d\n",
1414                               link_destination, *err_info););
1415             } /* if */
1416           } /* if */
1417           if (link_destination != buffer) {
1418             os_stri_free(link_destination);
1419           } /* if */
1420         } /* if */
1421       } /* if */
1422       os_stri_free(os_filePath);
1423     } /* if */
1424     logFunction(printf("doReadLink(\"%s\", %d) --> ",
1425                        striAsUnquotedCStri(filePath), *err_info);
1426                 printf("\"%s\"\n", striAsUnquotedCStri(destination)););
1427     return destination;
1428   } /* doReadLink */
1429 #endif
1430 
1431 
1432 
1433 #if HAS_SYMBOLIC_LINKS
followLink(striType startPath,errInfoType * err_info)1434 striType followLink (striType startPath, errInfoType *err_info)
1435 
1436   {
1437     striType helpPath;
1438     int number_of_links_followed = 5;
1439     striType path;
1440 
1441   /* followLink */
1442     logFunction(printf("followLink(\"%s\")\n", striAsUnquotedCStri(startPath)););
1443     if (getFileTypeSL(startPath, err_info) == FILE_SYMLINK) {
1444       path = doReadLink(startPath, err_info);
1445       while (path != NULL &&
1446              getFileTypeSL(path, err_info) == FILE_SYMLINK &&
1447              number_of_links_followed != 0) {
1448         helpPath = path;
1449         path = doReadLink(helpPath, err_info);
1450         FREE_STRI(helpPath, helpPath->size);
1451         number_of_links_followed--;
1452       } /* while */
1453       if (path == NULL || number_of_links_followed != 0) {
1454         FREE_STRI(startPath, startPath->size);
1455       } else {
1456         FREE_STRI(path, path->size);
1457         path = startPath;
1458       } /* if */
1459     } else {
1460       path = startPath;
1461     } /* if */
1462     logFunction(printf("followLink --> \"%s\" (err_info=%d)\n",
1463                        striAsUnquotedCStri(path), *err_info););
1464     return path;
1465   } /* followLink */
1466 #endif
1467 
1468 
1469 
1470 /**
1471  *  Return the absolute path of the current working directory.
1472  *  If the size of the provided 'buffer' is not sufficient a buffer
1473  *  with sufficient size is allocated. The allocated buffer must be
1474  *  freed afterwards with FREE_OS_STRI().
1475  *  @param buffer Buffer to be used if its size is sufficient.
1476  *  @param buffer_size Size of 'buffer'.
1477  *  @param err_info Unchanged if the function succeeds, and
1478  *                  MEMORY_ERROR if a memory allocation failed, and
1479  *                  FILE_ERROR if the operating system function failed.
1480  *  @return the 'buffer' or an allocated buffer with a null terminated
1481  *          operating system string.
1482  */
getOsCwd(const os_striType buffer,memSizeType buffer_size,errInfoType * err_info)1483 static os_striType getOsCwd (const os_striType buffer, memSizeType buffer_size,
1484     errInfoType *err_info)
1485 
1486   {
1487     os_striType large_buffer = NULL;
1488     os_striType os_cwd;
1489 
1490   /* getOsCwd */
1491     logFunction(printf("getOsCwd(*, " FMT_U_MEM ", *)", buffer_size);
1492                 fflush(stdout););
1493     if (unlikely((os_cwd = os_getcwd(buffer, buffer_size)) == NULL)) {
1494       if (errno == ERANGE || errno == ENAMETOOLONG) {
1495         do {
1496           buffer_size *= 2;
1497           FREE_OS_STRI(large_buffer);
1498 #ifdef OS_GETCWD_MAX_BUFFER_SIZE
1499           if (unlikely(buffer_size > OS_GETCWD_MAX_BUFFER_SIZE)) {
1500             large_buffer = NULL;
1501             *err_info = MEMORY_ERROR;
1502           } else
1503 #endif
1504           if (unlikely(!ALLOC_OS_STRI(large_buffer, buffer_size))) {
1505             *err_info = MEMORY_ERROR;
1506           } else {
1507             /* printf("getOsCwd: os_getcwd(*, " FMT_U_MEM ")\n", buffer_size); */
1508             if (unlikely((os_cwd = os_getcwd(large_buffer, buffer_size)) == NULL)) {
1509               if (errno != ERANGE && errno != ENAMETOOLONG) {
1510                 logError(printf("getOsCwd: os_getcwd(*, " FMT_U_MEM ") failed:\n"
1511                                 "errno=%d\nerror: %s\n",
1512                                 buffer_size, errno, strerror(errno)););
1513                 FREE_OS_STRI(large_buffer);
1514                 large_buffer = NULL;
1515                 *err_info = FILE_ERROR;
1516               } /* if */
1517             } /* if */
1518           } /* if */
1519         } while (os_cwd == NULL && large_buffer != NULL);
1520       } else {
1521         logError(printf("getOsCwd: os_getcwd(*, " FMT_U_MEM ") failed:\n"
1522                         "errno=%d\nerror: %s\n",
1523                         buffer_size, errno, strerror(errno)););
1524         *err_info = FILE_ERROR;
1525       } /* if */
1526     } /* if */
1527 #ifdef OS_GETCWD_RETURNS_SLASH
1528     {
1529       os_charType *ch;
1530 
1531       for (ch = os_cwd; *ch != 0; ch++) {
1532         if (*ch == '/') {
1533           *ch = PATH_DELIMITER;
1534         } /* if */
1535       } /* for */
1536     }
1537 #endif
1538     logFunctionResult(printf("\"" FMT_S_OS "\"\n", os_cwd););
1539     return os_cwd;
1540   } /* getOsCwd */
1541 
1542 
1543 
1544 #if defined USE_EXTENDED_LENGTH_PATH && USE_EXTENDED_LENGTH_PATH
adjustCwdForShell(errInfoType * err_info)1545 void adjustCwdForShell (errInfoType *err_info)
1546 
1547   {
1548     struct striStruct stri1_buffer;
1549     striType dotStri;
1550     os_striType os_cwd;
1551     int path_info = PATH_IS_NORMAL;
1552     int chdir_result;
1553 
1554   /* adjustCwdForShell */
1555     logFunction(printf("adjustCwdForShell(%d)\n", *err_info););
1556     dotStri = chrStrMacro('.', stri1_buffer);
1557     os_cwd = cp_to_os_path(dotStri, &path_info, err_info);
1558     if (unlikely(os_cwd == NULL)) {
1559       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
1560         logError(printf("adjustCwdForShell: Current directory is emulated root.\n"););
1561       } else {
1562         logError(printf("adjustCwdForShell: Cannot get current_emulated_cwd.\n"););
1563       } /* if */
1564     } else {
1565       logMessage(printf("adjustCwdForShell: os_chdir(\"" FMT_S_OS "\")\n",
1566                         &os_cwd[PREFIX_LEN]););
1567       chdir_result = os_chdir(&os_cwd[PREFIX_LEN]);
1568       if (unlikely(chdir_result != 0)) {
1569         logError(printf("adjustCwdForShell: os_chdir(\"" FMT_S_OS "\") failed:\n"
1570                         "errno=%d\nerror: %s\n",
1571                         &os_cwd[PREFIX_LEN], errno, strerror(errno)););
1572         *err_info = FILE_ERROR;
1573       } /* if */
1574       os_stri_free(os_cwd);
1575     } /* if */
1576     logFunction(printf("adjustCwdForShell(%d) -->\n", *err_info););
1577   } /* adjustCwdForShell */
1578 #endif
1579 
1580 
1581 
1582 #if EMULATE_ROOT_CWD
initEmulatedCwd(errInfoType * err_info)1583 void initEmulatedCwd (errInfoType *err_info)
1584 
1585   {
1586     os_charType buffer[PATH_MAX];
1587     os_striType os_cwd;
1588 
1589   /* initEmulatedCwd */
1590     logFunction(printf("initEmulatedCwd(*)\n"););
1591     if ((os_cwd = getOsCwd(buffer, PATH_MAX, err_info)) != NULL) {
1592       setEmulatedCwd(os_cwd, err_info);
1593       if (os_cwd != buffer) {
1594         FREE_OS_STRI(os_cwd);
1595       } /* if */
1596     } /* if */
1597     logFunction(printf("initEmulatedCwd(%d) -->\n", *err_info););
1598   } /* initEmulatedCwd */
1599 #endif
1600 
1601 
1602 
1603 #if defined USE_EXTENDED_LENGTH_PATH && USE_EXTENDED_LENGTH_PATH
1604 /**
1605  *  Determine the current working directory of the calling process.
1606  *  @param err_info Unchanged if the function succeeds, and
1607  *                  MEMORY_ERROR if a memory allocation failed, and
1608  *                  FILE_ERROR if the system function returns an error.
1609  *  @return The absolute path of the current working directory, or
1610  *          NULL if an error occurred.
1611  */
doGetCwd(errInfoType * err_info)1612 striType doGetCwd (errInfoType *err_info)
1613 
1614   {
1615     struct striStruct stri1_buffer;
1616     striType dotStri;
1617     os_striType os_cwd;
1618     int path_info = PATH_IS_NORMAL;
1619     striType cwd;
1620 
1621   /* doGetCwd */
1622     logFunction(printf("doGetCwd\n"););
1623     dotStri = chrStrMacro('.', stri1_buffer);
1624     os_cwd = cp_to_os_path(dotStri, &path_info, err_info);
1625     if (unlikely(os_cwd == NULL)) {
1626 #if EMULATE_ROOT_CWD
1627       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
1628         cwd = cp_from_os_path(current_emulated_cwd, err_info);
1629         if (unlikely(cwd == NULL)) {
1630           logError(printf("doGetCwd: "
1631                           "cp_from_os_path(\"" FMT_S_OS "\", *) failed:\n"
1632                           "err_info=%d\n",
1633                           current_emulated_cwd, *err_info););
1634         } /* if */
1635       } else
1636 #endif
1637       {
1638         logError(printf("doGetCwd: Cannot get current_emulated_cwd.\n"););
1639         cwd = NULL;
1640       }
1641     } else {
1642       cwd = cp_from_os_path(os_cwd, err_info);
1643       if (unlikely(cwd == NULL)) {
1644         logError(printf("doGetCwd: "
1645                         "cp_from_os_path(\"" FMT_S_OS "\", *) failed:\n"
1646                         "err_info=%d\n",
1647                         os_cwd, *err_info););
1648       } /* if */
1649       os_stri_free(os_cwd);
1650     } /* if */
1651     logFunction(printf("doGetCwd --> \"%s\" (err_info=%d)\n",
1652                        striAsUnquotedCStri(cwd), *err_info););
1653     return cwd;
1654   } /* doGetCwd */
1655 
1656 #else
1657 
1658 
1659 
1660 /**
1661  *  Determine the current working directory of the calling process.
1662  *  @param err_info Unchanged if the function succeeds, and
1663  *                  MEMORY_ERROR if a memory allocation failed, and
1664  *                  FILE_ERROR if the system function returns an error.
1665  *  @return The absolute path of the current working directory, or
1666  *          NULL if an error occurred.
1667  */
doGetCwd(errInfoType * err_info)1668 striType doGetCwd (errInfoType *err_info)
1669 
1670   {
1671     os_charType buffer[PATH_MAX];
1672     os_striType os_cwd;
1673     striType cwd;
1674 
1675   /* doGetCwd */
1676     logFunction(printf("doGetCwd\n"););
1677 #if EMULATE_ROOT_CWD
1678     if (IS_EMULATED_ROOT(current_emulated_cwd)) {
1679       cwd = cp_from_os_path(current_emulated_cwd, err_info);
1680       if (unlikely(cwd == NULL)) {
1681         logError(printf("doGetCwd: "
1682                         "cp_from_os_path(\"" FMT_S_OS "\", *) failed:\n"
1683                         "err_info=%d\n",
1684                         current_emulated_cwd, *err_info););
1685       } /* if */
1686     } else
1687 #endif
1688     {
1689       if (unlikely((os_cwd = getOsCwd(buffer, PATH_MAX, err_info)) == NULL)) {
1690         cwd = NULL;
1691       } else {
1692         cwd = cp_from_os_path(os_cwd, err_info);
1693         if (unlikely(cwd == NULL)) {
1694           logError(printf("doGetCwd: "
1695                           "cp_from_os_path(\"" FMT_S_OS "\", *) failed:\n"
1696                           "err_info=%d\n",
1697                           os_cwd, *err_info););
1698         } /* if */
1699         if (os_cwd != buffer) {
1700           FREE_OS_STRI(os_cwd);
1701         } /* if */
1702       } /* if */
1703     }
1704     logFunction(printf("doGetCwd --> \"%s\" (err_info=%d)\n",
1705                        striAsUnquotedCStri(cwd), *err_info););
1706     return cwd;
1707   } /* doGetCwd */
1708 
1709 #endif
1710 
1711 
1712 
1713 /**
1714  *  Get the absolute file path in the standard path representation.
1715  *  @return the absolute file path in the standard path
1716  *          representation, or NULL if the memory allocation failed.
1717  */
getAbsolutePath(const const_striType aPath)1718 striType getAbsolutePath (const const_striType aPath)
1719 
1720   {
1721     striType cwd;
1722     errInfoType err_info = OKAY_NO_ERROR;
1723     striType absolutePath;
1724 
1725   /* getAbsolutePath */
1726     logFunction(printf("getAbsolutePath(\"%s\")\n",
1727                        striAsUnquotedCStri(aPath)););
1728     if (aPath->size >= 1 &&
1729         aPath->mem[0] == (charType) '/') {
1730       absolutePath = straightenAbsolutePath(aPath);
1731     } else {
1732       cwd = doGetCwd(&err_info);
1733       if (unlikely(cwd == NULL)) {
1734         absolutePath = NULL;
1735       } else {
1736         absolutePath = concatPath(cwd, aPath);
1737         FREE_STRI(cwd, cwd->size);
1738       } /* if */
1739     } /* if */
1740     logFunction(printf("getAbsolutePath --> \"%s\"\n",
1741                        striAsUnquotedCStri(absolutePath)););
1742     return absolutePath;
1743   } /* getAbsolutePath */
1744 
1745 
1746 
1747 #ifdef DEFINE_SYSTEM_FUNCTION
systemForNodeJs(const char * command)1748 static int systemForNodeJs (const char *command)
1749 
1750   {
1751     int result;
1752 
1753   /* systemForNodeJs */
1754     logFunction(printf("systemForNodeJs(\"%s\")\n", command););
1755     result = EM_ASM_INT({
1756       let cmd = Module.UTF8ToString($0);
1757       // console.log('I received: ' + cmd);
1758       if (typeof require === 'function') {
1759         var child_process;
1760         try {
1761           child_process = require('child_process');
1762         } catch (e) {
1763           child_process = null;
1764         }
1765         if (child_process !== null) {
1766           let bslash = String.fromCharCode(92);
1767           let currDir = process.cwd().replace(new RegExp(bslash + bslash, 'g'), '/');
1768           let newDir = FS.cwd();
1769           // console.log('emcc cwd: ' + newDir);
1770           // console.log('node cwd: ' + currDir);
1771           if (currDir.charAt(1) === ':' && currDir.charAt(2) === '/') {
1772             if (newDir !== '/') {
1773               if (newDir.charAt(0) === '/' && newDir.charAt(1).match(/[a-z]/i) && newDir.charAt(2) === '/') {
1774                 newDir = newDir.charAt(1) + ':' + newDir.substring(2);
1775               }
1776             }
1777           }
1778           try {
1779             process.chdir(newDir);
1780           } catch (e) {
1781             // console.log('chdir: ' + e);
1782           }
1783           try {
1784             child_process.execSync(cmd);
1785             return 0;
1786           } catch (e) {
1787             return -1;
1788           }
1789         }
1790       }
1791       return -1;
1792     }, command);
1793     return result;
1794   } /* systemForNodeJs */
1795 
1796 #ifdef os_system
1797 #undef os_system
1798 #endif
1799 #define os_system(cmd) systemForNodeJs(cmd)
1800 #endif
1801 
1802 
1803 
1804 /**
1805  *  Determine the size of a file.
1806  *  The file size is measured in bytes.
1807  *  For directories, fifos and sockets a size of 0 is returned.
1808  *  @return the size of the file.
1809  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
1810  *             to the system path type.
1811  *  @exception RANGE_ERROR 'filePath' does not use the standard path
1812  *             representation or it cannot be converted to the system
1813  *             path type.
1814  *  @exception FILE_ERROR It was not possible to determine the file size.
1815  */
cmdBigFileSize(const const_striType filePath)1816 bigIntType cmdBigFileSize (const const_striType filePath)
1817 
1818   {
1819     os_striType os_path;
1820     os_stat_struct stat_buf;
1821     int stat_result;
1822     cFileType aFile;
1823     int path_info = PATH_IS_NORMAL;
1824     errInfoType err_info = OKAY_NO_ERROR;
1825     bigIntType size_of_file;
1826 
1827   /* cmdBigFileSize */
1828     logFunction(printf("cmdBigFileSize(\"%s\")", striAsUnquotedCStri(filePath));
1829                 fflush(stdout););
1830     os_path = cp_to_os_path(filePath, &path_info, &err_info);
1831     if (unlikely(os_path == NULL)) {
1832 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
1833       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
1834         size_of_file = bigIConv(0);
1835       } else
1836 #endif
1837       {
1838         logError(printf("cmdBigFileSize: cp_to_os_path(\"%s\", *, *) failed:\n"
1839                         "path_info=%d, err_info=%d\n",
1840                         striAsUnquotedCStri(filePath), path_info, err_info););
1841         raise_error(err_info);
1842         size_of_file = NULL;
1843       }
1844     } else {
1845       stat_result = os_stat(os_path, &stat_buf);
1846       if (stat_result == 0 && S_ISREG(stat_buf.st_mode)) {
1847 #if OS_OFF_T_SIZE == 32
1848         size_of_file = bigFromUInt32((uint32Type) stat_buf.st_size);
1849 #elif OS_OFF_T_SIZE == 64
1850         size_of_file = bigFromUInt64((uint64Type) stat_buf.st_size);
1851 #else
1852 #error "sizeof(os_off_t) is neither 4 nor 8."
1853 #endif
1854       } else if (stat_result == 0 && (S_ISDIR(stat_buf.st_mode) ||
1855                                       S_ISFIFO(stat_buf.st_mode) ||
1856                                       S_ISSOCK(stat_buf.st_mode))) {
1857         size_of_file = bigIConv(0);
1858       } else {
1859         aFile = os_fopen(os_path, os_mode_rb);
1860         if (aFile == NULL) {
1861           logError(printf("cmdBigFileSize: "
1862                           "os_fopen(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
1863                           "errno=%d\nerror: %s\n",
1864                           os_path, os_mode_rb, errno, strerror(errno)););
1865           /* if (stat_result == 0) {
1866             printf("stat_buf.st_blksize=%lu\n", stat_buf.st_blksize);
1867             printf("stat_buf.st_blocks=%llu\n", stat_buf.st_blocks);
1868             printf("stat_buf.st_size=%llu\n", stat_buf.st_size);
1869           } */
1870           err_info = FILE_ERROR;
1871           size_of_file = NULL;
1872         } else {
1873           size_of_file = getBigFileLengthUsingSeek(aFile);
1874           fclose(aFile);
1875         } /* if */
1876       } /* if */
1877       os_stri_free(os_path);
1878       if (unlikely(err_info != OKAY_NO_ERROR)) {
1879         raise_error(err_info);
1880       } /* if */
1881     } /* if */
1882     return size_of_file;
1883   } /* cmdBigFileSize */
1884 
1885 
1886 
1887 /**
1888  *  Changes the current working directory of the calling process.
1889  *  @exception MEMORY_ERROR Not enough memory to convert 'dirPath' to
1890  *             the system path type.
1891  *  @exception RANGE_ERROR 'dirPath' does not use the standard path
1892  *             representation or it cannot be converted to the system
1893  *             path type.
1894  *  @exception FILE_ERROR A system function returns an error.
1895  */
cmdChdir(const const_striType dirPath)1896 void cmdChdir (const const_striType dirPath)
1897 
1898   {
1899     os_striType os_path;
1900     int path_info = PATH_IS_NORMAL;
1901     errInfoType err_info = OKAY_NO_ERROR;
1902     int chdir_result;
1903 
1904   /* cmdChdir */
1905     logFunction(printf("cmdChdir(\"%s\")\n", striAsUnquotedCStri(dirPath)););
1906     os_path = cp_to_os_path(dirPath, &path_info, &err_info);
1907     if (unlikely(os_path == NULL)) {
1908 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
1909       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
1910         setEmulatedCwdToRoot();
1911       } else {
1912         logError(printf("cmdChdir: cp_to_os_path(\"%s\", *, *) failed:\n"
1913                         "path_info=%d, err_info=%d\n",
1914                         striAsUnquotedCStri(dirPath), path_info, err_info););
1915         raise_error(err_info);
1916       } /* if */
1917     } else {
1918 #if defined USE_EXTENDED_LENGTH_PATH && USE_EXTENDED_LENGTH_PATH
1919       /* The extended length path is only used, if it */
1920       /* is absolutely necessary. Many subprocesses   */
1921       /* cannot handle a current working directory    */
1922       /* with an extended length path.                */
1923       if (os_stri_strlen(&os_path[PREFIX_LEN]) < CLASSIC_WINDOWS_MAX_PATH) {
1924         logMessage(printf("cmdChdir: os_chdir(\"" FMT_S_OS "\")\n",
1925                           &os_path[PREFIX_LEN]););
1926         chdir_result = os_chdir(&os_path[PREFIX_LEN]);
1927       } else {
1928         logMessage(printf("cmdChdir: os_chdir(\"" FMT_S_OS "\")\n",
1929                           os_path););
1930         chdir_result = os_chdir(os_path);
1931       } /* if */
1932       if (unlikely(chdir_result != 0)) {
1933         logMessage(printf("cmdChdir: os_chdir(\"" FMT_S_OS "\") failed:\n"
1934                           "errno=%d\nerror: %s\n",
1935                           os_path, errno, strerror(errno)););
1936         setEmulatedCwd(os_path, &err_info);
1937 #else
1938       logMessage(printf("cmdChdir: os_chdir(\"" FMT_S_OS "\")\n",
1939                         os_path););
1940       chdir_result = os_chdir(os_path);
1941       if (unlikely(chdir_result != 0)) {
1942         logError(printf("cmdChdir: os_chdir(\"" FMT_S_OS "\") failed:\n"
1943                         "errno=%d\nerror: %s\n",
1944                         os_path, errno, strerror(errno)););
1945         err_info = FILE_ERROR;
1946 #endif
1947       } else {
1948         setEmulatedCwd(os_path, &err_info);
1949       } /* if */
1950 #else
1951       logError(printf("cmdChdir: cp_to_os_path(\"%s\", *, *) failed:\n"
1952                       "path_info=%d, err_info=%d\n",
1953                       striAsUnquotedCStri(dirPath), path_info, err_info););
1954       raise_error(err_info);
1955     } else {
1956       logMessage(printf("cmdChdir: os_chdir(\"" FMT_S_OS "\")\n",
1957                         os_path););
1958       chdir_result = os_chdir(os_path);
1959       if (unlikely(chdir_result != 0)) {
1960         logError(printf("cmdChdir: os_chdir(\"" FMT_S_OS "\") failed:\n"
1961                         "errno=%d\nerror: %s\n",
1962                         os_path, errno, strerror(errno)););
1963         err_info = FILE_ERROR;
1964       } /* if */
1965 #endif
1966       os_stri_free(os_path);
1967       if (unlikely(err_info != OKAY_NO_ERROR)) {
1968         raise_error(err_info);
1969       } /* if */
1970     } /* if */
1971     logFunction(printf("cmdChdir(\"%s\") -->\n",
1972                        striAsUnquotedCStri(dirPath)););
1973   } /* cmdChdir */
1974 
1975 
1976 
1977 /**
1978  *  Clone a file or directory tree.
1979  *  Permissions/mode, ownership and timestamps of the original are
1980  *  preserved. Symlinks are not followed. Instead the symlink is
1981  *  copied. Note that 'cloneFile' does not preserve hard links (they
1982  *  are resolved to distinct files).
1983  *  @exception MEMORY_ERROR Not enough memory to convert
1984  *             'sourcePath' or 'destPath' to the system path type.
1985  *  @exception RANGE_ERROR 'sourcePath' or 'destPath' does not use
1986  *             the standard path representation or one of them cannot be
1987  *             converted to the system path type.
1988  *  @exception FILE_ERROR Source file does not exist, destination file
1989  *             already exists or a system function returns an error.
1990  */
1991 void cmdCloneFile (const const_striType sourcePath, const const_striType destPath)
1992 
1993   {
1994     os_striType os_sourcePath;
1995     os_striType os_destPath;
1996     os_stat_struct to_stat;
1997     int path_info;
1998     errInfoType err_info = OKAY_NO_ERROR;
1999 
2000   /* cmdCloneFile */
2001     logFunction(printf("cmdCloneFile(\"%s\", ", striAsUnquotedCStri(sourcePath));
2002                 printf("\"%s\")\n", striAsUnquotedCStri(destPath)););
2003     os_sourcePath = cp_to_os_path(sourcePath, &path_info, &err_info);
2004     if (unlikely(os_sourcePath == NULL)) {
2005       logError(printf("cmdCloneFile: cp_to_os_path(\"%s\", *, *) failed:\n"
2006                       "path_info=%d, err_info=%d\n",
2007                       striAsUnquotedCStri(sourcePath), path_info, err_info););
2008     } else {
2009       os_destPath = cp_to_os_path(destPath, &path_info, &err_info);
2010       if (unlikely(os_destPath == NULL)) {
2011         logError(printf("cmdCloneFile: cp_to_os_path(\"%s\", *, *) failed:\n"
2012                         "path_info=%d, err_info=%d\n",
2013                         striAsUnquotedCStri(destPath), path_info, err_info););
2014       } else {
2015         if (os_stat(os_destPath, &to_stat) == 0) {
2016           logError(printf("cmdCloneFile: "
2017                           "Destination " FMT_S_OS " exists already.\n",
2018                           os_destPath););
2019           err_info = FILE_ERROR;
2020         } else {
2021           copy_any_file(os_sourcePath, os_destPath, PRESERVE_ALL, &err_info);
2022         } /* if */
2023         os_stri_free(os_destPath);
2024       } /* if */
2025       os_stri_free(os_sourcePath);
2026     } /* if */
2027     if (unlikely(err_info != OKAY_NO_ERROR)) {
2028       raise_error(err_info);
2029     } /* if */
2030   } /* cmdCloneFile */
2031 
2032 
2033 
2034 /**
2035  *  Get a built-in C compiler/runtime configuration value.
2036  *  The makefile (used to compile Seed7) and the program chkccomp.c
2037  *  write the configuration values to version.h. The configuration
2038  *  values are hard-coded in the Seed7 runtime library.
2039  *  @param name Name of the configuration value to be retrieved.
2040  *  @return the requested configuration value, and
2041  *          "" if a value with the name does not exist.
2042  *  @exception MEMORY_ERROR Not enough memory to convert the
2043  *             configuration value to a string.
2044  */
2045 striType cmdConfigValue (const const_striType name)
2046 
2047   {
2048     char opt_name[MAX_CSTRI_BUFFER_LEN + NULL_TERMINATION_LEN];
2049     const_cstriType opt;
2050     char buffer[CONFIG_VALUE_BUFFER_SIZE];
2051     striType configValue = NULL;
2052 
2053   /* cmdConfigValue */
2054     if (unlikely(name->size > MAX_CSTRI_BUFFER_LEN)) {
2055       opt = "";
2056     } else if (unlikely(conv_to_cstri(opt_name, name) == NULL)) {
2057       opt = "";
2058     } else if (strcmp(opt_name, "OBJECT_FILE_EXTENSION") == 0) {
2059       opt = OBJECT_FILE_EXTENSION;
2060     } else if (strcmp(opt_name, "LIBRARY_FILE_EXTENSION") == 0) {
2061       opt = LIBRARY_FILE_EXTENSION;
2062     } else if (strcmp(opt_name, "EXECUTABLE_FILE_EXTENSION") == 0) {
2063       opt = EXECUTABLE_FILE_EXTENSION;
2064     } else if (strcmp(opt_name, "LINKED_PROGRAM_EXTENSION") == 0) {
2065       opt = LINKED_PROGRAM_EXTENSION;
2066     } else if (strcmp(opt_name, "C_COMPILER") == 0) {
2067       opt = C_COMPILER;
2068     } else if (strcmp(opt_name, "CPLUSPLUS_COMPILER") == 0) {
2069       opt = CPLUSPLUS_COMPILER;
2070     } else if (strcmp(opt_name, "CALL_C_COMPILER_FROM_SHELL") == 0) {
2071       opt = CALL_C_COMPILER_FROM_SHELL ? "TRUE" : "FALSE";
2072     } else if (strcmp(opt_name, "C_COMPILER_VERSION") == 0) {
2073       opt = C_COMPILER_VERSION;
2074     } else if (strcmp(opt_name, "CC_OPT_DEBUG_INFO") == 0) {
2075       opt = CC_OPT_DEBUG_INFO;
2076     } else if (strcmp(opt_name, "CC_OPT_LINK_TIME_OPTIMIZATION") == 0) {
2077       opt = CC_OPT_LINK_TIME_OPTIMIZATION;
2078     } else if (strcmp(opt_name, "LINKER_OPT_LTO_MANDATORY") == 0) {
2079       opt = LINKER_OPT_LTO_MANDATORY ? "TRUE" : "FALSE";
2080     } else if (strcmp(opt_name, "CC_OPT_NO_WARNINGS") == 0) {
2081       opt = CC_OPT_NO_WARNINGS;
2082     } else if (strcmp(opt_name, "CC_OPT_OPTIMIZE_1") == 0) {
2083       opt = CC_OPT_OPTIMIZE_1;
2084     } else if (strcmp(opt_name, "CC_OPT_OPTIMIZE_2") == 0) {
2085       opt = CC_OPT_OPTIMIZE_2;
2086     } else if (strcmp(opt_name, "CC_OPT_OPTIMIZE_3") == 0) {
2087       opt = CC_OPT_OPTIMIZE_3;
2088     } else if (strcmp(opt_name, "CC_OPT_TRAP_OVERFLOW") == 0) {
2089       opt = CC_OPT_TRAP_OVERFLOW;
2090     } else if (strcmp(opt_name, "CC_OPT_VERSION_INFO") == 0) {
2091       opt = CC_OPT_VERSION_INFO;
2092     } else if (strcmp(opt_name, "CC_ENVIRONMENT_INI") == 0) {
2093       opt = CC_ENVIRONMENT_INI;
2094     } else if (strcmp(opt_name, "CC_FLAGS") == 0) {
2095       opt = CC_FLAGS;
2096     } else if (strcmp(opt_name, "CC_ERROR_FILEDES") == 0) {
2097       opt = STRINGIFY(CC_ERROR_FILEDES);
2098     } else if (strcmp(opt_name, "CC_VERSION_INFO_FILEDES") == 0) {
2099       opt = STRINGIFY(CC_VERSION_INFO_FILEDES);
2100     } else if (strcmp(opt_name, "LINKER_OPT_DEBUG_INFO") == 0) {
2101       opt = LINKER_OPT_DEBUG_INFO;
2102     } else if (strcmp(opt_name, "LINKER_OPT_NO_DEBUG_INFO") == 0) {
2103       opt = LINKER_OPT_NO_DEBUG_INFO;
2104     } else if (strcmp(opt_name, "LINKER_OPT_OUTPUT_FILE") == 0) {
2105       opt = LINKER_OPT_OUTPUT_FILE;
2106     } else if (strcmp(opt_name, "LINKER_OPT_SPECIAL_LIB") == 0) {
2107       opt = LINKER_OPT_SPECIAL_LIB;
2108     } else if (strcmp(opt_name, "LINKER_FLAGS") == 0) {
2109       opt = LINKER_FLAGS;
2110     } else if (strcmp(opt_name, "SYSTEM_LIBS") == 0) {
2111       opt = SYSTEM_LIBS;
2112     } else if (strcmp(opt_name, "SYSTEM_BIGINT_LIBS") == 0) {
2113       opt = SYSTEM_BIGINT_LIBS;
2114     } else if (strcmp(opt_name, "SYSTEM_DATABASE_LIBS") == 0) {
2115       opt = SYSTEM_DATABASE_LIBS;
2116     } else if (strcmp(opt_name, "SYSTEM_DRAW_LIBS") == 0) {
2117       opt = SYSTEM_DRAW_LIBS;
2118     } else if (strcmp(opt_name, "SYSTEM_MATH_LIBS") == 0) {
2119       opt = SYSTEM_MATH_LIBS;
2120     } else if (strcmp(opt_name, "SEED7_LIB") == 0) {
2121       opt = SEED7_LIB;
2122     } else if (strcmp(opt_name, "DRAW_LIB") == 0) {
2123       opt = DRAW_LIB;
2124     } else if (strcmp(opt_name, "CONSOLE_LIB") == 0) {
2125       opt = CONSOLE_LIB;
2126     } else if (strcmp(opt_name, "DATABASE_LIB") == 0) {
2127       opt = DATABASE_LIB;
2128     } else if (strcmp(opt_name, "COMP_DATA_LIB") == 0) {
2129       opt = COMP_DATA_LIB;
2130     } else if (strcmp(opt_name, "COMPILER_LIB") == 0) {
2131       opt = COMPILER_LIB;
2132     } else if (strcmp(opt_name, "SPECIAL_LIB") == 0) {
2133       opt = SPECIAL_LIB;
2134     } else if (strcmp(opt_name, "S7_LIB_DIR") == 0) {
2135       opt = S7_LIB_DIR;
2136     } else if (strcmp(opt_name, "VERSION_REVISION_LEVEL") == 0) {
2137       opt = STRINGIFY(LEVEL);
2138     } else if (strcmp(opt_name, "REDIRECT_FILEDES_1") == 0) {
2139       opt = REDIRECT_FILEDES_1;
2140     } else if (strcmp(opt_name, "REDIRECT_FILEDES_2") == 0) {
2141       opt = REDIRECT_FILEDES_2;
2142     } else if (strcmp(opt_name, "NULL_DEVICE") == 0) {
2143       opt = NULL_DEVICE_FOR_SCRIPTS;
2144     } else if (strcmp(opt_name, "BOOLTYPE") == 0) {
2145       opt = BOOLTYPE_STRI;
2146     } else if (strcmp(opt_name, "INT32TYPE") == 0) {
2147       opt = INT32TYPE_STRI;
2148     } else if (strcmp(opt_name, "UINT32TYPE") == 0) {
2149       opt = UINT32TYPE_STRI;
2150     } else if (strcmp(opt_name, "INT64TYPE") == 0) {
2151       opt = INT64TYPE_STRI;
2152     } else if (strcmp(opt_name, "UINT64TYPE") == 0) {
2153       opt = UINT64TYPE_STRI;
2154     } else if (strcmp(opt_name, "INT128TYPE") == 0) {
2155       opt = INT128TYPE_STRI;
2156     } else if (strcmp(opt_name, "UINT128TYPE") == 0) {
2157       opt = UINT128TYPE_STRI;
2158     } else if (strcmp(opt_name, "INT32TYPE_LITERAL_SUFFIX") == 0) {
2159       opt = INT32TYPE_LITERAL_SUFFIX;
2160     } else if (strcmp(opt_name, "INT64TYPE_LITERAL_SUFFIX") == 0) {
2161       opt = INT64TYPE_LITERAL_SUFFIX;
2162     } else if (strcmp(opt_name, "INTTYPE_SIZE") == 0) {
2163       sprintf(buffer, "%d", INTTYPE_SIZE);
2164       opt = buffer;
2165     } else if (strcmp(opt_name, "FLOATTYPE_SIZE") == 0) {
2166       sprintf(buffer, "%d", FLOATTYPE_SIZE);
2167       opt = buffer;
2168     } else if (strcmp(opt_name, "POINTER_SIZE") == 0) {
2169       sprintf(buffer, "%d", POINTER_SIZE);
2170       opt = buffer;
2171     } else if (strcmp(opt_name, "INT_SIZE") == 0) {
2172       opt = STRINGIFY(INT_SIZE);
2173     } else if (strcmp(opt_name, "LONG_SIZE") == 0) {
2174       opt = STRINGIFY(LONG_SIZE);
2175     } else if (strcmp(opt_name, "FLOATTYPE_MANTISSA_BITS") == 0) {
2176       sprintf(buffer, "%d", FLOATTYPE_MANTISSA_BITS);
2177       opt = buffer;
2178     } else if (strcmp(opt_name, "FLOATTYPE_EXPONENT_OFFSET") == 0) {
2179       sprintf(buffer, "%d", FLOATTYPE_EXPONENT_OFFSET);
2180       opt = buffer;
2181     } else if (strcmp(opt_name, "INT_RANGE_IN_FLOATTYPE_MAX") == 0) {
2182       sprintf(buffer, FMT_D, INT_RANGE_IN_FLOATTYPE_MAX);
2183       opt = buffer;
2184     } else if (strcmp(opt_name, "MINIMUM_TRUNC_ARGUMENT") == 0) {
2185 #if FLOATTYPE_DOUBLE && INTTYPE_SIZE == 64
2186       opt = STRINGIFY(MINIMUM_TRUNC_ARGUMENT);
2187 #else
2188       opt = "";
2189 #endif
2190     } else if (strcmp(opt_name, "MAXIMUM_TRUNC_ARGUMENT") == 0) {
2191 #if FLOATTYPE_DOUBLE && INTTYPE_SIZE == 64
2192       opt = STRINGIFY(MAXIMUM_TRUNC_ARGUMENT);
2193 #else
2194       opt = "";
2195 #endif
2196     } else if (strcmp(opt_name, "PIXEL_RED_MASK") == 0) {
2197       opt = PIXEL_RED_MASK;
2198     } else if (strcmp(opt_name, "PIXEL_GREEN_MASK") == 0) {
2199       opt = PIXEL_GREEN_MASK;
2200     } else if (strcmp(opt_name, "PIXEL_BLUE_MASK") == 0) {
2201       opt = PIXEL_BLUE_MASK;
2202     } else if (strcmp(opt_name, "RGB_TO_PIXEL_FLAG_NAME") == 0) {
2203       opt = RGB_TO_PIXEL_FLAG_NAME;
2204     } else if (strcmp(opt_name, "RAND_MULTIPLIER") == 0) {
2205       opt = STRINGIFY(RAND_MULTIPLIER);
2206     } else if (strcmp(opt_name, "RAND_INCREMENT") == 0) {
2207       opt = STRINGIFY(RAND_INCREMENT);
2208     } else if (strcmp(opt_name, "MACRO_DEFS") == 0) {
2209       /* Use string literal concatenation: */
2210       opt = MACRO_DEFS  OS_ISNAN_DEFINITION;
2211     } else if (strcmp(opt_name, "OVERFLOW_SIGNAL") == 0) {
2212       opt = OVERFLOW_SIGNAL_STR;
2213     } else if (strcmp(opt_name, "BUILTIN_ADD_OVERFLOW") == 0) {
2214       opt = BUILTIN_ADD_OVERFLOW;
2215     } else if (strcmp(opt_name, "BUILTIN_SUB_OVERFLOW") == 0) {
2216       opt = BUILTIN_SUB_OVERFLOW;
2217     } else if (strcmp(opt_name, "BUILTIN_MULT_OVERFLOW") == 0) {
2218       opt = BUILTIN_MULT_OVERFLOW;
2219     } else if (strcmp(opt_name, "FLOATTYPE_DOUBLE") == 0) {
2220       opt = FLOATTYPE_DOUBLE ? "TRUE" : "FALSE";
2221     } else if (strcmp(opt_name, "HAS_SIGSETJMP") == 0) {
2222       opt = HAS_SIGSETJMP ? "TRUE" : "FALSE";
2223     } else if (strcmp(opt_name, "CHECK_INT_DIV_BY_ZERO") == 0) {
2224       opt = CHECK_INT_DIV_BY_ZERO ? "TRUE" : "FALSE";
2225     } else if (strcmp(opt_name, "CHECK_INT_DIV_ZERO_BY_ZERO") == 0) {
2226       opt = CHECK_INT_DIV_ZERO_BY_ZERO ? "TRUE" : "FALSE";
2227     } else if (strcmp(opt_name, "CHECK_INT_REM_BY_ZERO") == 0) {
2228       opt = CHECK_INT_REM_BY_ZERO ? "TRUE" : "FALSE";
2229     } else if (strcmp(opt_name, "CHECK_INT_REM_ZERO_BY_ZERO") == 0) {
2230       opt = CHECK_INT_REM_ZERO_BY_ZERO ? "TRUE" : "FALSE";
2231     } else if (strcmp(opt_name, "HAS_EXP2") == 0) {
2232       opt = HAS_EXP2 ? "TRUE" : "FALSE";
2233     } else if (strcmp(opt_name, "HAS_EXP10") == 0) {
2234       opt = HAS_EXP10 ? "TRUE" : "FALSE";
2235     } else if (strcmp(opt_name, "HAS_EXPM1") == 0) {
2236       opt = HAS_EXPM1 ? "TRUE" : "FALSE";
2237     } else if (strcmp(opt_name, "HAS_LOG1P") == 0) {
2238       opt = HAS_LOG1P ? "TRUE" : "FALSE";
2239     } else if (strcmp(opt_name, "HAS_CBRT") == 0) {
2240       opt = HAS_CBRT ? "TRUE" : "FALSE";
2241     } else if (strcmp(opt_name, "CHECK_FLOAT_DIV_BY_ZERO") == 0) {
2242       opt = CHECK_FLOAT_DIV_BY_ZERO ? "TRUE" : "FALSE";
2243     } else if (strcmp(opt_name, "FLOAT_COMPARISON_OKAY") == 0) {
2244       opt = FLOAT_COMPARISON_OKAY ? "TRUE" : "FALSE";
2245     } else if (strcmp(opt_name, "WITH_STRI_CAPACITY") == 0) {
2246       opt = WITH_STRI_CAPACITY ? "TRUE" : "FALSE";
2247     } else if (strcmp(opt_name, "ALLOW_STRITYPE_SLICES") == 0) {
2248       opt = ALLOW_STRITYPE_SLICES ? "TRUE" : "FALSE";
2249     } else if (strcmp(opt_name, "ALLOW_BSTRITYPE_SLICES") == 0) {
2250       opt = ALLOW_BSTRITYPE_SLICES ? "TRUE" : "FALSE";
2251     } else if (strcmp(opt_name, "RSHIFT_DOES_SIGN_EXTEND") == 0) {
2252       opt = RSHIFT_DOES_SIGN_EXTEND ? "TRUE" : "FALSE";
2253     } else if (strcmp(opt_name, "TWOS_COMPLEMENT_INTTYPE") == 0) {
2254       opt = TWOS_COMPLEMENT_INTTYPE ? "TRUE" : "FALSE";
2255     } else if (strcmp(opt_name, "LITTLE_ENDIAN_INTTYPE") == 0) {
2256       opt = LITTLE_ENDIAN_INTTYPE ? "TRUE" : "FALSE";
2257     } else if (strcmp(opt_name, "POW_FUNCTION_OKAY") == 0) {
2258       opt = POW_FUNCTION_OKAY ? "TRUE" : "FALSE";
2259     } else if (strcmp(opt_name, "SQRT_FUNCTION_OKAY") == 0) {
2260       opt = SQRT_FUNCTION_OKAY ? "TRUE" : "FALSE";
2261     } else if (strcmp(opt_name, "EXP_FUNCTION_OKAY") == 0) {
2262       opt = EXP_FUNCTION_OKAY ? "TRUE" : "FALSE";
2263     } else if (strcmp(opt_name, "LOG_FUNCTION_OKAY") == 0) {
2264       opt = LOG_FUNCTION_OKAY ? "TRUE" : "FALSE";
2265     } else if (strcmp(opt_name, "LOG10_FUNCTION_OKAY") == 0) {
2266       opt = LOG10_FUNCTION_OKAY ? "TRUE" : "FALSE";
2267     } else if (strcmp(opt_name, "LOG2_FUNCTION_OKAY") == 0) {
2268       opt = LOG2_FUNCTION_OKAY ? "TRUE" : "FALSE";
2269     } else if (strcmp(opt_name, "FMOD_FUNCTION_OKAY") == 0) {
2270       opt = FMOD_FUNCTION_OKAY ? "TRUE" : "FALSE";
2271     } else if (strcmp(opt_name, "LDEXP_FUNCTION_OKAY") == 0) {
2272       opt = LDEXP_FUNCTION_OKAY ? "TRUE" : "FALSE";
2273     } else if (strcmp(opt_name, "FREXP_FUNCTION_OKAY") == 0) {
2274       opt = FREXP_FUNCTION_OKAY ? "TRUE" : "FALSE";
2275     } else if (strcmp(opt_name, "FLOAT_ZERO_DIV_ERROR") == 0) {
2276       opt = FLOAT_ZERO_DIV_ERROR ? "TRUE" : "FALSE";
2277     } else if (strcmp(opt_name, "LIMITED_CSTRI_LITERAL_LEN") == 0) {
2278       opt = LIMITED_CSTRI_LITERAL_LEN ? "TRUE" : "FALSE";
2279     } else if (strcmp(opt_name, "SWITCH_WORKS_FOR_INT64TYPE") == 0) {
2280       opt = SWITCH_WORKS_FOR_INT64TYPE ? "TRUE" : "FALSE";
2281     } else if (strcmp(opt_name, "STMT_BLOCK_IN_PARENTHESES_OK") == 0) {
2282       opt = STMT_BLOCK_IN_PARENTHESES_OK ? "TRUE" : "FALSE";
2283     } else if (strcmp(opt_name, "CC_SOURCE_UTF8") == 0) {
2284 #ifdef CC_SOURCE_UTF8
2285       opt = "TRUE";
2286 #else
2287       opt = "FALSE";
2288 #endif
2289     } else if (strcmp(opt_name, "USE_WMAIN") == 0) {
2290 #ifdef USE_WMAIN
2291       opt = "TRUE";
2292 #else
2293       opt = "FALSE";
2294 #endif
2295     } else if (strcmp(opt_name, "USE_WINMAIN") == 0) {
2296 #ifdef USE_WINMAIN
2297       opt = "TRUE";
2298 #else
2299       opt = "FALSE";
2300 #endif
2301     } else {
2302       opt = "";
2303     } /* if */
2304     if (configValue == NULL) {
2305       configValue = cstri8_or_cstri_to_stri(opt);
2306     } /* if */
2307     if (unlikely(configValue == NULL)) {
2308       raise_error(MEMORY_ERROR);
2309     } /* if */
2310     return configValue;
2311   } /* cmdConfigValue */
2312 
2313 
2314 
2315 /**
2316  *  Copy a file or directory tree.
2317  *  Permissions/mode, ownership and timestamps of the destination file
2318  *  are determined independent of the corresponding source properties.
2319  *  The destination file gets the permissions/mode defined by umask.
2320  *  The user executing the program is the owner of the destination file.
2321  *  The timestamps of the destination file are set to the current time.
2322  *  Symbolic links in 'sourcePath' are always followed.
2323  *  Therefore 'copyFile' will never create a symbolic link.
2324  *  Note that 'copyFile' does not preserve hard links (they are
2325  *  resolved to distinct files).
2326  *  @exception MEMORY_ERROR Not enough memory to convert 'sourcePath'
2327  *             or 'destPath' to the system path type.
2328  *  @exception RANGE_ERROR 'sourcePath' or 'destPath' does not use
2329  *             the standard path representation or one of them cannot be
2330  *             converted to the system path type.
2331  *  @exception FILE_ERROR Source file does not exist, destination file
2332  *             already exists or a system function returns an error.
2333  */
2334 void cmdCopyFile (const const_striType sourcePath, const const_striType destPath)
2335 
2336   {
2337     os_striType os_sourcePath;
2338     os_striType os_destPath;
2339     os_stat_struct to_stat;
2340     int path_info;
2341     errInfoType err_info = OKAY_NO_ERROR;
2342 
2343   /* cmdCopyFile */
2344     logFunction(printf("cmdCopyFile(\"%s\", ", striAsUnquotedCStri(sourcePath));
2345                 printf("\"%s\")\n", striAsUnquotedCStri(destPath)););
2346     os_sourcePath = cp_to_os_path(sourcePath, &path_info, &err_info);
2347     if (unlikely(os_sourcePath == NULL)) {
2348       logError(printf("cmdCopyFile: cp_to_os_path(\"%s\", *, *) failed:\n"
2349                       "path_info=%d, err_info=%d\n",
2350                       striAsUnquotedCStri(sourcePath), path_info, err_info););
2351     } else {
2352       os_destPath = cp_to_os_path(destPath, &path_info, &err_info);
2353       if (unlikely(os_destPath == NULL)) {
2354         logError(printf("cmdCopyFile: cp_to_os_path(\"%s\", *, *) failed:\n"
2355                         "path_info=%d, err_info=%d\n",
2356                         striAsUnquotedCStri(destPath), path_info, err_info););
2357       } else {
2358         if (os_stat(os_destPath, &to_stat) == 0) {
2359           logError(printf("cmdCopyFile: "
2360                           "Destination " FMT_S_OS " exists already.\n",
2361                           os_destPath););
2362           err_info = FILE_ERROR;
2363         } else {
2364           copy_any_file(os_sourcePath, os_destPath, PRESERVE_NOTHING, &err_info);
2365         } /* if */
2366         os_stri_free(os_destPath);
2367       } /* if */
2368       os_stri_free(os_sourcePath);
2369     } /* if */
2370     if (unlikely(err_info != OKAY_NO_ERROR)) {
2371       raise_error(err_info);
2372     } /* if */
2373   } /* cmdCopyFile */
2374 
2375 
2376 
2377 /**
2378  *  Returns the list of environment variable names as array of strings.
2379  *  @return the list of environment variable names.
2380  *  @exception MEMORY_ERROR Not enough memory to create the result.
2381  */
2382 rtlArrayType cmdEnvironment (void)
2383 
2384   {
2385 #if USE_GET_ENVIRONMENT
2386     os_striType *os_environ;
2387 #elif INITIALIZE_OS_ENVIRON
2388     static const os_charType empty_os_stri[] = {0};
2389 #endif
2390     intType used_max_position;
2391     os_striType *nameStartPos;
2392     os_striType nameEndPos;
2393     striType variableName;
2394     errInfoType err_info = OKAY_NO_ERROR;
2395     rtlArrayType environment_array;
2396 
2397   /* cmdEnvironment */
2398     logFunction(printf("cmdEnvironment()\n"););
2399 #if USE_GET_ENVIRONMENT
2400     os_environ = getEnvironment();
2401 #elif INITIALIZE_OS_ENVIRON
2402     if (os_environ == NULL) {
2403       (void) os_getenv(empty_os_stri);
2404     } /* if */
2405 #endif
2406     if (unlikely(!ALLOC_RTL_ARRAY(environment_array, INITAL_ARRAY_SIZE))) {
2407       raise_error(MEMORY_ERROR);
2408     } else {
2409       environment_array->min_position = 1;
2410       environment_array->max_position = INITAL_ARRAY_SIZE;
2411       used_max_position = 0;
2412       if (os_environ != NULL) {
2413         for (nameStartPos = os_environ; *nameStartPos != NULL && environment_array != NULL;
2414              ++nameStartPos) {
2415           /* printf("nameStartPos: \"" FMT_S_OS "\"\n", *nameStartPos); */
2416           if ((*nameStartPos)[0] != '=' && (*nameStartPos)[0] != '\0') {
2417             nameEndPos = os_stri_strchr(*nameStartPos, '=');
2418             if (unlikely(nameEndPos == NULL)) {
2419               nameEndPos = *nameStartPos + os_stri_strlen(*nameStartPos);
2420             } /* if */
2421             variableName = conv_from_os_stri(*nameStartPos,
2422                                              (memSizeType) (nameEndPos - *nameStartPos));
2423             if (unlikely(variableName == NULL)) {
2424               err_info = MEMORY_ERROR;
2425             } else {
2426               environment_array = addStriToRtlArray(variableName, environment_array,
2427                   used_max_position);
2428               used_max_position++;
2429             } /* if */
2430           } /* if */
2431         } /* for */
2432       } /* if */
2433       environment_array = completeRtlStriArray(environment_array, used_max_position);
2434       if (unlikely(environment_array == NULL)) {
2435         err_info = MEMORY_ERROR;
2436       } /* if */
2437       if (unlikely(err_info != OKAY_NO_ERROR)) {
2438         raise_error(err_info);
2439         environment_array = NULL;
2440       } /* if */
2441     } /* if */
2442 #if USE_GET_ENVIRONMENT
2443     freeEnvironment(os_environ);
2444 #endif
2445     logFunction(printf("cmdEnvironment --> " FMT_U_MEM
2446                        " (size=" FMT_U_MEM ")\n",
2447                        (memSizeType) environment_array,
2448                        environment_array != NULL ?
2449                        arraySize(environment_array) : 0););
2450     return environment_array;
2451   } /* cmdEnvironment */
2452 
2453 
2454 
2455 /**
2456  *  Determine the file mode (permissions) of a file.
2457  *  @return the file mode.
2458  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
2459  *             to the system path type.
2460  *  @exception RANGE_ERROR 'filePath' does not use the standard path
2461  *             representation or it cannot be converted to the system
2462  *             path type.
2463  *  @exception FILE_ERROR A system function returns an error.
2464  */
2465 setType cmdFileMode (const const_striType filePath)
2466 
2467   {
2468     os_striType os_path;
2469     os_stat_struct stat_buf;
2470     int stat_result;
2471     int path_info = PATH_IS_NORMAL;
2472     errInfoType err_info = OKAY_NO_ERROR;
2473     setType file_mode;
2474 
2475   /* cmdFileMode */
2476     logFunction(printf("cmdFileMode(\"%s\")\n", striAsUnquotedCStri(filePath)););
2477     os_path = cp_to_os_path(filePath, &path_info, &err_info);
2478     if (unlikely(os_path == NULL)) {
2479 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2480       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
2481         file_mode = setIConv(0444);
2482       } else
2483 #endif
2484       {
2485         logError(printf("cmdFileMode: cp_to_os_path(\"%s\", *, *) failed:\n"
2486                         "path_info=%d, err_info=%d\n",
2487                         striAsUnquotedCStri(filePath), path_info, err_info););
2488         raise_error(err_info);
2489         file_mode = NULL;
2490       }
2491     } else {
2492       stat_result = os_stat(os_path, &stat_buf);
2493       if (unlikely(stat_result != 0)) {
2494         logError(printf("cmdFileMode: os_stat(\"" FMT_S_OS "\") failed:\n"
2495                         "errno=%d\nerror: %s\n",
2496                         os_path, errno, strerror(errno)););
2497         os_stri_free(os_path);
2498         raise_error(FILE_ERROR);
2499         file_mode = NULL;
2500       } else {
2501         os_stri_free(os_path);
2502         /* printf("cmdFileMode: st_mode=0%o\n", stat_buf.st_mode); */
2503 #if MODE_BITS_NORMAL
2504         file_mode = setIConv(0777 & stat_buf.st_mode);
2505 #else
2506         /* Force the bits to the standard sequence */
2507         file_mode = setIConv(
2508             (stat_buf.st_mode & S_IRUSR ? 0400 : 0) |
2509             (stat_buf.st_mode & S_IWUSR ? 0200 : 0) |
2510             (stat_buf.st_mode & S_IXUSR ? 0100 : 0) |
2511             (stat_buf.st_mode & S_IRGRP ? 0040 : 0) |
2512             (stat_buf.st_mode & S_IWGRP ? 0020 : 0) |
2513             (stat_buf.st_mode & S_IXGRP ? 0010 : 0) |
2514             (stat_buf.st_mode & S_IROTH ? 0004 : 0) |
2515             (stat_buf.st_mode & S_IWOTH ? 0002 : 0) |
2516             (stat_buf.st_mode & S_IXOTH ? 0001 : 0));
2517 #endif
2518       } /* if */
2519     } /* if */
2520     return file_mode;
2521   } /* cmdFileMode */
2522 
2523 
2524 
2525 /**
2526  *  Determine the size of a file.
2527  *  The file size is measured in bytes.
2528  *  For directories, fifos and sockets a size of 0 is returned.
2529  *  @return the size of the file.
2530  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
2531  *             to the system path type.
2532  *  @exception RANGE_ERROR 'filePath' does not use the standard path
2533  *             representation or it cannot be converted to the system
2534  *             path type.
2535  *  @exception RANGE_ERROR The file size is not representable as integer.
2536  *  @exception FILE_ERROR It was not possible to determine the file size.
2537  */
2538 intType cmdFileSize (const const_striType filePath)
2539 
2540   {
2541     os_striType os_path;
2542     os_stat_struct stat_buf;
2543     int stat_result;
2544     cFileType aFile;
2545     int path_info = PATH_IS_NORMAL;
2546     errInfoType err_info = OKAY_NO_ERROR;
2547     intType size_of_file;
2548 
2549   /* cmdFileSize */
2550     logFunction(printf("cmdFileSize(\"%s\")", striAsUnquotedCStri(filePath));
2551                 fflush(stdout););
2552     os_path = cp_to_os_path(filePath, &path_info, &err_info);
2553     if (unlikely(os_path == NULL)) {
2554 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2555       if (unlikely(path_info != PATH_IS_EMULATED_ROOT))
2556 #endif
2557       {
2558         logError(printf("cmdFileSize: cp_to_os_path(\"%s\", *, *) failed:\n"
2559                         "path_info=%d, err_info=%d\n",
2560                         striAsUnquotedCStri(filePath), path_info, err_info););
2561         raise_error(err_info);
2562       }
2563       size_of_file = 0;
2564     } else {
2565       stat_result = os_stat(os_path, &stat_buf);
2566       if (stat_result == 0 && S_ISREG(stat_buf.st_mode)) {
2567         if (stat_buf.st_size > INTTYPE_MAX || stat_buf.st_size < 0) {
2568           logError(printf("cmdFileSize(\"%s\"): "
2569                           "File size not representable as integer.\n",
2570                           striAsUnquotedCStri(filePath)););
2571           err_info = RANGE_ERROR;
2572           size_of_file = 0;
2573         } else {
2574           size_of_file = (intType) stat_buf.st_size;
2575         } /* if */
2576       } else if (stat_result == 0 && (S_ISDIR(stat_buf.st_mode) ||
2577                                       S_ISFIFO(stat_buf.st_mode) ||
2578                                       S_ISSOCK(stat_buf.st_mode))) {
2579         size_of_file = 0;
2580       } else {
2581         /* printf("stat_result=%d\nerrno=%d\n", stat_result, errno); */
2582         aFile = os_fopen(os_path, os_mode_rb);
2583         if (aFile == NULL) {
2584           logError(printf("cmdFileSize: "
2585                           "os_fopen(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
2586                           "errno=%d\nerror: %s\n",
2587                           os_path, os_mode_rb, errno, strerror(errno)););
2588           /* if (stat_result == 0) {
2589             printf("stat_buf.st_blksize=%lu\n", stat_buf.st_blksize);
2590             printf("stat_buf.st_blocks=" FMT_U64 "\n", (uint64Type) stat_buf.st_blocks);
2591             printf("stat_buf.st_size=" FMT_U64 "\n", (uint64Type) stat_buf.st_size);
2592           } */
2593           err_info = FILE_ERROR;
2594           size_of_file = 0;
2595         } else {
2596           size_of_file = getFileLengthUsingSeek(aFile);
2597           fclose(aFile);
2598         } /* if */
2599       } /* if */
2600       os_stri_free(os_path);
2601       if (unlikely(err_info != OKAY_NO_ERROR)) {
2602         raise_error(err_info);
2603       } /* if */
2604     } /* if */
2605     logFunctionResult(printf("" FMT_D "\n", size_of_file););
2606     return size_of_file;
2607   } /* cmdFileSize */
2608 
2609 
2610 
2611 /**
2612  *  Determine the type of a file.
2613  *  The function does follow symbolic links. If the chain of
2614  *  symbolic links is too long the function returns 'FILE_SYMLINK'.
2615  *  If a symbolic link refers to a place where the permission
2616  *  is denied the function returns 'FILE_SYMLINK'.
2617  *  A return value of 'FILE_ABSENT' does not imply that a file
2618  *  with this name can be created, since missing directories and
2619  *  illegal file names cause also 'FILE_ABSENT'.
2620  *  @return the type of the file.
2621  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
2622  *             to the system path type.
2623  *  @exception RANGE_ERROR 'filePath' does not use the standard path
2624  *             representation.
2625  *  @exception FILE_ERROR The system function returns an error other
2626  *             than ENOENT, ENOTDIR, ENAMETOOLONG or EACCES.
2627  */
2628 intType cmdFileType (const const_striType filePath)
2629 
2630   {
2631     os_striType os_path;
2632     os_stat_struct stat_buf;
2633     int stat_result;
2634     int path_info = PATH_IS_NORMAL;
2635     errInfoType err_info = OKAY_NO_ERROR;
2636     int saved_errno;
2637     intType type_of_file;
2638 
2639   /* cmdFileType */
2640     logFunction(printf("cmdFileType(\"%s\")", striAsUnquotedCStri(filePath));
2641                 fflush(stdout););
2642     os_path = cp_to_os_path(filePath, &path_info, &err_info);
2643     if (unlikely(os_path == NULL)) {
2644 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2645       if (path_info == PATH_IS_EMULATED_ROOT) {
2646         type_of_file = FILE_DIR;
2647       } else if (path_info == PATH_NOT_MAPPED) {
2648         type_of_file = FILE_ABSENT;
2649       } else
2650 #endif
2651       {
2652         logError(printf("cmdFileType: cp_to_os_path(\"%s\", *, *) failed:\n"
2653                         "path_info=%d, err_info=%d\n",
2654                         striAsUnquotedCStri(filePath), path_info, err_info););
2655         raise_error(err_info);
2656         type_of_file = FILE_ABSENT;
2657       }
2658     } else {
2659       stat_result = os_stat(os_path, &stat_buf);
2660       saved_errno = errno;
2661       /* printf("stat(\"" FMT_S_OS "\") returns: %d, errno=%d\n",
2662          os_path, stat_result, saved_errno); */
2663       if (stat_result == 0) {
2664         if (S_ISREG(stat_buf.st_mode)) {
2665           type_of_file = FILE_REGULAR;
2666         } else if (S_ISDIR(stat_buf.st_mode)) {
2667           type_of_file = FILE_DIR;
2668         } else if (S_ISCHR(stat_buf.st_mode)) {
2669           type_of_file = FILE_CHAR;
2670         } else if (S_ISBLK(stat_buf.st_mode)) {
2671           type_of_file = FILE_BLOCK;
2672         } else if (S_ISFIFO(stat_buf.st_mode)) {
2673           type_of_file = FILE_FIFO;
2674         } else if (S_ISLNK(stat_buf.st_mode)) {
2675           type_of_file = FILE_SYMLINK;
2676           logError(printf("cmdFileType: os_stat(\"" FMT_S_OS "\", *) "
2677                           "returns a mode of S_IFLNK.\n",
2678                           os_path););
2679           err_info = FILE_ERROR;
2680         } else if (S_ISSOCK(stat_buf.st_mode)) {
2681           type_of_file = FILE_SOCKET;
2682         } else {
2683           type_of_file = FILE_UNKNOWN;
2684         } /* if */
2685 #ifdef ELOOP
2686       } else if (unlikely(saved_errno == ELOOP)) {
2687         type_of_file = FILE_SYMLINK;
2688 #endif
2689       } else if (unlikely(saved_errno == EACCES) &&
2690                           os_lstat(os_path, &stat_buf) == 0 &&
2691                           S_ISLNK(stat_buf.st_mode)) {
2692         /* Symbolic link that refers to a place where */
2693         /* the permission is denied. */
2694         type_of_file = FILE_SYMLINK;
2695       } else {
2696         type_of_file = FILE_ABSENT;
2697         if (unlikely(filePath->size != 0 && saved_errno != ENOENT &&
2698                      saved_errno != ENOTDIR && saved_errno != ENAMETOOLONG &&
2699                      saved_errno != EACCES)) {
2700           logError(printf("cmdFileType: os_stat(\"" FMT_S_OS "\") failed:\n"
2701                           "errno=%d\nerror: %s\n",
2702                           os_path, saved_errno, strerror(saved_errno)););
2703           /* printf("filePath->size=%lu\n", filePath->size); */
2704           /* printf("strlen(os_path)=%d\n", os_stri_strlen(os_path)); */
2705           err_info = FILE_ERROR;
2706         } /* if */
2707       } /* if */
2708       os_stri_free(os_path);
2709       if (unlikely(err_info != OKAY_NO_ERROR)) {
2710         raise_error(err_info);
2711       } /* if */
2712     } /* if */
2713     logFunctionResult(printf("" FMT_D "\n", type_of_file););
2714     return type_of_file;
2715   } /* cmdFileType */
2716 
2717 
2718 
2719 /**
2720  *  Determine the type of a file.
2721  *  The function does not follow symbolic links. Therefore it may
2722  *  return 'FILE_SYMLINK'. A return value of 'FILE_ABSENT' does
2723  *  not imply that a file with this name can be created, since missing
2724  *  directories and illegal file names cause also 'FILE_ABSENT'.
2725  *  @return the type of the file.
2726  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
2727  *             to the system path type.
2728  *  @exception RANGE_ERROR 'filePath' does not use the standard path
2729  *             representation.
2730  *  @exception FILE_ERROR The system function returns an error other
2731  *             than ENOENT, ENOTDIR, ENAMETOOLONG or EACCES.
2732  */
2733 intType cmdFileTypeSL (const const_striType filePath)
2734 
2735   {
2736     errInfoType err_info = OKAY_NO_ERROR;
2737     intType type_of_file;
2738 
2739   /* cmdFileTypeSL */
2740     logFunction(printf("cmdFileTypeSL(\"%s\")", striAsUnquotedCStri(filePath));
2741                 fflush(stdout););
2742     type_of_file = getFileTypeSL(filePath, &err_info);
2743     if (unlikely(err_info != OKAY_NO_ERROR)) {
2744       raise_error(err_info);
2745     } /* if */
2746     logFunctionResult(printf("" FMT_D "\n", type_of_file););
2747     return type_of_file;
2748   } /* cmdFileTypeSL */
2749 
2750 
2751 
2752 /**
2753  *  Determine the current working directory of the calling process.
2754  *  @return The absolute path of the current working directory.
2755  *  @exception MEMORY_ERROR Not enough memory to represent the
2756  *             result string.
2757  *  @exception FILE_ERROR The system function returns an error.
2758  */
2759 striType cmdGetcwd (void)
2760 
2761   {
2762     errInfoType err_info = OKAY_NO_ERROR;
2763     striType cwd;
2764 
2765   /* cmdGetcwd */
2766     logFunction(printf("cmdGetcwd\n"););
2767     cwd = doGetCwd(&err_info);
2768     if (unlikely(cwd == NULL)) {
2769       logError(printf("cmdGetcwd: doGetCwd() failed:\n"
2770                       "err_info=%d\n", err_info););
2771       raise_error(err_info);
2772     } /* if */
2773     logFunction(printf("cmdGetcwd --> \"%s\"\n", striAsUnquotedCStri(cwd)););
2774     return cwd;
2775   } /* cmdGetcwd */
2776 
2777 
2778 
2779 /**
2780  *  Determine the value of an environment variable.
2781  *  The function getenv searches the environment for an environment variable
2782  *  with the given 'name'. If such an environment variable exists the
2783  *  corresponding string value is returned.
2784  *  @return the value of an environment variable, and
2785  *          "" if the requested environment variable does not exist.
2786  *  @exception MEMORY_ERROR Not enough memory to convert 'name' to the
2787  *             system string type or not enough memory to represent the
2788  *             result string.
2789  *  @exception RANGE_ERROR 'name' cannot be converted to the system string
2790  *             type or a system function returns an error.
2791  */
2792 striType cmdGetenv (const const_striType name)
2793 
2794   {
2795     os_striType env_name;
2796     os_striType env_value;
2797     errInfoType err_info = OKAY_NO_ERROR;
2798     striType value;
2799 
2800   /* cmdGetenv */
2801     logFunction(printf("cmdGetenv(\"%s\")", striAsUnquotedCStri(name));
2802                 fflush(stdout););
2803     env_name = stri_to_os_stri(name, &err_info);
2804     if (unlikely(env_name == NULL)) {
2805       logError(printf("cmdGetenv: stri_to_os_stri(\"%s\", *, *) failed:\n"
2806                       "err_info=%d\n",
2807                       striAsUnquotedCStri(name), err_info););
2808       raise_error(err_info);
2809       value = NULL;
2810     } else {
2811       env_value = os_getenv(env_name);
2812       os_stri_free(env_name);
2813       if (env_value == NULL) {
2814         if (unlikely(!ALLOC_STRI_SIZE_OK(value, 0))) {
2815           err_info = MEMORY_ERROR;
2816         } else {
2817           value->size = 0;
2818         } /* if */
2819       } else {
2820         value = os_stri_to_stri(env_value, &err_info);
2821         os_getenv_string_free(env_value);
2822       } /* if */
2823       if (unlikely(value == NULL)) {
2824         raise_error(err_info);
2825       } /* if */
2826     } /* if */
2827     logFunctionResult(printf("\"%s\"\n", striAsUnquotedCStri(value)););
2828     return value;
2829   } /* cmdGetenv */
2830 
2831 
2832 
2833 /**
2834  *  Determine the access time of a file.
2835  *  @return the access time of the file.
2836  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
2837  *             to the system path type.
2838  *  @exception RANGE_ERROR 'filePath' does not use the standard path
2839  *             representation or it cannot be converted to the system
2840  *             path type.
2841  *  @exception FILE_ERROR A system function returns an error.
2842  */
2843 void cmdGetATime (const const_striType filePath,
2844     intType *year, intType *month, intType *day, intType *hour,
2845     intType *min, intType *sec, intType *micro_sec, intType *time_zone,
2846     boolType *is_dst)
2847 
2848   {
2849     os_striType os_path;
2850     os_stat_struct stat_buf;
2851     int stat_result;
2852     int path_info = PATH_IS_NORMAL;
2853     errInfoType err_info = OKAY_NO_ERROR;
2854 
2855   /* cmdGetATime */
2856     logFunction(printf("cmdGetATime(\"%s\")\n", striAsUnquotedCStri(filePath)););
2857     os_path = cp_to_os_path(filePath, &path_info, &err_info);
2858     if (unlikely(os_path == NULL)) {
2859 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2860       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
2861         timFromTimestamp(0,
2862             year, month, day, hour,
2863             min, sec, micro_sec, time_zone, is_dst);
2864       } else
2865 #endif
2866       {
2867         logError(printf("cmdGetATime: cp_to_os_path(\"%s\", *, *) failed:\n"
2868                         "path_info=%d, err_info=%d\n",
2869                         striAsUnquotedCStri(filePath), path_info, err_info););
2870         raise_error(err_info);
2871       }
2872     } else {
2873       stat_result = os_stat(os_path, &stat_buf);
2874       if (unlikely(stat_result != 0)) {
2875         logError(printf("cmdGetATime: os_stat(\"" FMT_S_OS "\") failed:\n"
2876                         "errno=%d\nerror: %s\n",
2877                         os_path, errno, strerror(errno)););
2878         err_info = FILE_ERROR;
2879       } else {
2880         /* printf("cmdGetATime: st_atime=" FMT_T "\n", stat_buf.st_atime); */
2881         timFromTimestamp(stat_buf.st_atime,
2882             year, month, day, hour,
2883             min, sec, micro_sec, time_zone, is_dst);
2884       } /* if */
2885       os_stri_free(os_path);
2886       if (unlikely(err_info != OKAY_NO_ERROR)) {
2887         raise_error(err_info);
2888       } /* if */
2889     } /* if */
2890     logFunction(printf("cmdGetATime(" F_D(04) "-" F_D(02) "-" F_D(02) " "
2891                        F_D(02) ":" F_D(02) ":" F_D(02) "." F_D(06) " " FMT_D " %d) -->\n",
2892                        *year, *month, *day, *hour, *min, *sec,
2893                        *micro_sec, *time_zone, *is_dst););
2894   } /* cmdGetATime */
2895 
2896 
2897 
2898 /**
2899  *  Determine the change time of a file.
2900  *  @return the change time of the file.
2901  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
2902  *             to the system path type.
2903  *  @exception RANGE_ERROR 'filePath' does not use the standard path
2904  *             representation or it cannot be converted to the system
2905  *             path type.
2906  *  @exception FILE_ERROR A system function returns an error.
2907  */
2908 void cmdGetCTime (const const_striType filePath,
2909     intType *year, intType *month, intType *day, intType *hour,
2910     intType *min, intType *sec, intType *micro_sec, intType *time_zone,
2911     boolType *is_dst)
2912 
2913   {
2914     os_striType os_path;
2915     os_stat_struct stat_buf;
2916     int stat_result;
2917     int path_info = PATH_IS_NORMAL;
2918     errInfoType err_info = OKAY_NO_ERROR;
2919 
2920   /* cmdGetCTime */
2921     logFunction(printf("cmdGetCTime(\"%s\")\n", striAsUnquotedCStri(filePath)););
2922     os_path = cp_to_os_path(filePath, &path_info, &err_info);
2923     if (unlikely(os_path == NULL)) {
2924 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2925       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
2926         timFromTimestamp(0,
2927             year, month, day, hour,
2928             min, sec, micro_sec, time_zone, is_dst);
2929       } else
2930 #endif
2931       {
2932         logError(printf("cmdGetCTime: cp_to_os_path(\"%s\", *, *) failed:\n"
2933                         "path_info=%d, err_info=%d\n",
2934                         striAsUnquotedCStri(filePath), path_info, err_info););
2935         raise_error(err_info);
2936       }
2937     } else {
2938       stat_result = os_stat(os_path, &stat_buf);
2939       if (unlikely(stat_result != 0)) {
2940         logError(printf("cmdGetCTime: os_stat(\"" FMT_S_OS "\") failed:\n"
2941                         "errno=%d\nerror: %s\n",
2942                         os_path, errno, strerror(errno)););
2943         err_info = FILE_ERROR;
2944       } else {
2945         /* printf("cmdGetCTime: st_ctime=" FMT_T "\n", stat_buf.st_ctime); */
2946         timFromTimestamp(stat_buf.st_ctime,
2947             year, month, day, hour,
2948             min, sec, micro_sec, time_zone, is_dst);
2949       } /* if */
2950       os_stri_free(os_path);
2951       if (unlikely(err_info != OKAY_NO_ERROR)) {
2952         raise_error(err_info);
2953       } /* if */
2954     } /* if */
2955     logFunction(printf("cmdGetCTime(" F_D(04) "-" F_D(02) "-" F_D(02) " "
2956                        F_D(02) ":" F_D(02) ":" F_D(02) "." F_D(06) " " FMT_D " %d) -->\n",
2957                        *year, *month, *day, *hour, *min, *sec,
2958                        *micro_sec, *time_zone, *is_dst););
2959   } /* cmdGetCTime */
2960 
2961 
2962 
2963 /**
2964  *  Determine the modification time of a file.
2965  *  @return the modification time of the file.
2966  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
2967  *             to the system path type.
2968  *  @exception RANGE_ERROR 'filePath' does not use the standard path
2969  *             representation or it cannot be converted to the system
2970  *             path type.
2971  *  @exception FILE_ERROR A system function returns an error.
2972  */
2973 void cmdGetMTime (const const_striType filePath,
2974     intType *year, intType *month, intType *day, intType *hour,
2975     intType *min, intType *sec, intType *micro_sec, intType *time_zone,
2976     boolType *is_dst)
2977 
2978   {
2979     os_striType os_path;
2980     os_stat_struct stat_buf;
2981     int stat_result;
2982     int path_info = PATH_IS_NORMAL;
2983     errInfoType err_info = OKAY_NO_ERROR;
2984 
2985   /* cmdGetMTime */
2986     logFunction(printf("cmdGetMTime(\"%s\")\n", striAsUnquotedCStri(filePath)););
2987     os_path = cp_to_os_path(filePath, &path_info, &err_info);
2988     if (unlikely(os_path == NULL)) {
2989 #if MAP_ABSOLUTE_PATH_TO_DRIVE_LETTERS
2990       if (likely(path_info == PATH_IS_EMULATED_ROOT)) {
2991         timFromTimestamp(0,
2992             year, month, day, hour,
2993             min, sec, micro_sec, time_zone, is_dst);
2994       } else
2995 #endif
2996       {
2997         logError(printf("cmdGetMTime: cp_to_os_path(\"%s\", *, *) failed:\n"
2998                         "path_info=%d, err_info=%d\n",
2999                         striAsUnquotedCStri(filePath), path_info, err_info););
3000         raise_error(err_info);
3001       }
3002     } else {
3003       stat_result = os_stat(os_path, &stat_buf);
3004       if (unlikely(stat_result != 0)) {
3005         logError(printf("cmdGetMTime: os_stat(\"" FMT_S_OS "\") failed:\n"
3006                         "errno=%d\nerror: %s\n",
3007                         os_path, errno, strerror(errno)););
3008         err_info = FILE_ERROR;
3009       } else {
3010         /* printf("cmdGetMTime: st_mtime=" FMT_T "\n", stat_buf.st_mtime); */
3011         timFromTimestamp(stat_buf.st_mtime,
3012             year, month, day, hour,
3013             min, sec, micro_sec, time_zone, is_dst);
3014       } /* if */
3015       os_stri_free(os_path);
3016       if (unlikely(err_info != OKAY_NO_ERROR)) {
3017         raise_error(err_info);
3018       } /* if */
3019     } /* if */
3020     logFunction(printf("cmdGetMTime(" F_D(04) "-" F_D(02) "-" F_D(02) " "
3021                        F_D(02) ":" F_D(02) ":" F_D(02) "." F_D(06) " " FMT_D " %d) -->\n",
3022                        *year, *month, *day, *hour, *min, *sec,
3023                        *micro_sec, *time_zone, *is_dst););
3024   } /* cmdGetMTime */
3025 
3026 
3027 
3028 /**
3029  *  Returns the search path of the system as array of strings.
3030  *  @return the search path of the system.
3031  *  @exception MEMORY_ERROR Not enough memory to create the result.
3032  */
3033 rtlArrayType cmdGetSearchPath (void)
3034 
3035   {
3036     errInfoType err_info = OKAY_NO_ERROR;
3037     rtlArrayType searchPath;
3038 
3039   /* cmdGetSearchPath */
3040     logFunction(printf("cmdGetSearchPath()\n"););
3041     searchPath = getSearchPath(&err_info);
3042     if (unlikely(searchPath == NULL)) {
3043       logError(printf("cmdGetSearchPath: getSearchPath(*) failed:\n"
3044                       "err_info=%d\n",
3045                       err_info););
3046       raise_error(err_info);
3047     } /* if */
3048     return searchPath;
3049   } /* cmdGetSearchPath */
3050 
3051 
3052 
3053 /**
3054  *  Determine the home directory of the user.
3055  *  This function should be preferred over the use of an environment
3056  *  variable such as $HOME. $HOME is not supported under all operating
3057  *  systems and it is not guaranteed, that it uses the standard path
3058  *  representation.
3059  *  @return The absolute path of the home directory.
3060  *  @exception MEMORY_ERROR Not enough memory to represent the
3061  *             result string.
3062  *  @exception FILE_ERROR Not able to determine the home directory.
3063  */
3064 striType cmdHomeDir (void)
3065 
3066   {
3067 #ifdef DETERMINE_OS_PROPERTIES_AT_RUNTIME
3068     static const os_charType home_dir_env_var_unx[] = {'H', 'O', 'M', 'E', 0};
3069     static const os_charType home_dir_env_var_win[] = {'U', 'S', 'E', 'R',
3070                                                        'P', 'R', 'O', 'F', 'I', 'L', 'E', 0};
3071     const os_charType *home_dir_env_var;
3072 #else
3073     static const os_charType home_dir_env_var[] = HOME_DIR_ENV_VAR;
3074 #endif
3075     os_striType os_home_dir;
3076 #ifdef DEFAULT_HOME_DIR
3077     static const os_charType default_home_dir[] = DEFAULT_HOME_DIR;
3078 #endif
3079     errInfoType err_info = OKAY_NO_ERROR;
3080     striType home_dir;
3081 
3082   /* cmdHomeDir */
3083     logFunction(printf("cmdHomeDir\n"););
3084 #ifdef DETERMINE_OS_PROPERTIES_AT_RUNTIME
3085     if (shellUsesDriveLetters) {
3086       home_dir_env_var = home_dir_env_var_win;
3087     } else {
3088       home_dir_env_var = home_dir_env_var_unx;
3089     } /* if */
3090 #endif
3091     os_home_dir = os_getenv(home_dir_env_var);
3092     /* printf("os_getenv(\"" FMT_S_OS "\") returns: " FMT_S_OS "\n",
3093         home_dir_env_var, os_home_dir); */
3094     if (unlikely(os_home_dir == NULL)) {
3095 #ifdef DEFAULT_HOME_DIR
3096       home_dir = cp_from_os_path(default_home_dir, &err_info);
3097 #else
3098       err_info = FILE_ERROR;
3099       home_dir = NULL;
3100 #endif
3101     } else {
3102       home_dir = cp_from_os_path(os_home_dir, &err_info);
3103       os_getenv_string_free(os_home_dir);
3104     } /* if */
3105     if (unlikely(home_dir == NULL)) {
3106       raise_error(err_info);
3107     } /* if */
3108     logFunction(printf("cmdHomeDir --> \"%s\"\n", striAsUnquotedCStri(home_dir)););
3109     return home_dir;
3110   } /* cmdHomeDir */
3111 
3112 
3113 
3114 /**
3115  *  Determine the filenames in a directory.
3116  *  The files "." and ".." are left out from the result.
3117  *  Note that the function returns only the filenames.
3118  *  Additional information must be obtained with other calls.
3119  *  @return a string-array containing the filenames in the directory.
3120  *  @exception MEMORY_ERROR Not enough memory to convert 'dirPath'
3121  *             to the system path type or not enough memory to
3122  *             represent the result 'string array'.
3123  *  @exception RANGE_ERROR 'dirPath' does not use the standard path
3124  *             representation or it cannot be converted to the system
3125  *             path type.
3126  *  @exception FILE_ERROR A system function returns an error.
3127  */
3128 rtlArrayType cmdLs (const const_striType dirPath)
3129 
3130   {
3131     errInfoType err_info = OKAY_NO_ERROR;
3132     rtlArrayType result;
3133 
3134   /* cmdLs */
3135     logFunction(printf("cmdLs(\"%s\")\n", striAsUnquotedCStri(dirPath)););
3136     result = read_dir(dirPath, &err_info);
3137     if (unlikely(result == NULL)) {
3138       logError(printf("cmdLs: read_dir(\"%s\", *) failed:\n"
3139                       "err_info=%d\n",
3140                       striAsUnquotedCStri(dirPath), err_info););
3141       raise_error(err_info);
3142     } else {
3143       qsort((void *) result->arr,
3144           (size_t) (result->max_position - result->min_position + 1),
3145           sizeof(rtlObjectType), &cmp_mem);
3146     } /* if */
3147     logFunction(if (result == NULL) {
3148                   printf("cmdLs --> NULL\n");
3149                 } else {
3150                   printf("cmdLs --> array[size = " FMT_U_MEM "]\n",
3151                          arraySize(result));
3152                 });
3153     return result;
3154   } /* cmdLs */
3155 
3156 
3157 
3158 /**
3159  *  Creates a new directory.
3160  *  @exception MEMORY_ERROR Not enough memory to convert 'dirPath' to
3161  *             the system path type.
3162  *  @exception RANGE_ERROR 'dirPath' does not use the standard path
3163  *             representation or it cannot be converted to the system
3164  *             path type.
3165  *  @exception FILE_ERROR A system function returns an error.
3166  */
3167 void cmdMkdir (const const_striType dirPath)
3168 
3169   {
3170     os_striType os_path;
3171     int mkdir_result;
3172     int path_info;
3173     errInfoType err_info = OKAY_NO_ERROR;
3174 
3175   /* cmdMkdir */
3176     logFunction(printf("cmdMkdir(\"%s\")\n", striAsUnquotedCStri(dirPath)););
3177     os_path = cp_to_os_path(dirPath, &path_info, &err_info);
3178     if (unlikely(os_path == NULL)) {
3179       logError(printf("cmdMkdir: cp_to_os_path(\"%s\", *, *) failed:\n"
3180                       "path_info=%d, err_info=%d\n",
3181                       striAsUnquotedCStri(dirPath), path_info, err_info););
3182       raise_error(err_info);
3183     } else {
3184       /* printf("mkdir(\"" FMT_S_OS "\")\n", os_path); */
3185       mkdir_result = os_mkdir(os_path, 0777);
3186       if (unlikely(mkdir_result != 0)) {
3187         logError(printf("cmdMkdir: os_mkdir(\"" FMT_S_OS "\", 0777) failed:\n"
3188                         "errno=%d\nerror: %s\n",
3189                         os_path, errno, strerror(errno)););
3190         os_stri_free(os_path);
3191         raise_error(FILE_ERROR);
3192       } else {
3193         os_stri_free(os_path);
3194       } /* if */
3195     } /* if */
3196   } /* cmdMkdir */
3197 
3198 
3199 
3200 /**
3201  *  Move and rename a file or directory tree.
3202  *  The function uses the C 'rename()' function. If 'rename()' fails
3203  *  the file (or directory tree) is cloned with 'cloneFile' (which
3204  *  preserves permissions/mode, ownership and timestamps) to the new
3205  *  place and with the new name. If 'cloneFile' succeeds the original
3206  *  file is deleted. If 'cloneFile' fails (no space on device or
3207  *  other reason) all remains of the failed clone are removed. Note
3208  *  that 'cloneFile' works for symbolic links but does not preserve
3209  *  hard links (they are resolved to distinct files).
3210  *  @exception MEMORY_ERROR Not enough memory to convert 'sourcePath'
3211  *             or 'destPath' to the system path type.
3212  *  @exception RANGE_ERROR 'sourcePath' or 'destPath' does not use
3213  *             the standard path representation or one of them cannot be
3214  *             converted to the system path type.
3215  *  @exception FILE_ERROR Source file does not exist, destination file
3216  *             already exists or a system function returns an error.
3217  */
3218 void cmdMove (const const_striType sourcePath, const const_striType destPath)
3219 
3220   {
3221     os_striType os_sourcePath;
3222     os_striType os_destPath;
3223     int path_info;
3224     errInfoType err_info = OKAY_NO_ERROR;
3225 
3226   /* cmdMove */
3227     logFunction(printf("cmdMove(\"%s\", ", striAsUnquotedCStri(sourcePath));
3228                 printf("\"%s\")\n", striAsUnquotedCStri(destPath)););
3229     os_sourcePath = cp_to_os_path(sourcePath, &path_info, &err_info);
3230     if (unlikely(os_sourcePath == NULL)) {
3231       logError(printf("cmdMove: cp_to_os_path(\"%s\", *, *) failed:\n"
3232                       "path_info=%d, err_info=%d\n",
3233                       striAsUnquotedCStri(sourcePath), path_info, err_info););
3234     } else {
3235       os_destPath = cp_to_os_path(destPath, &path_info, &err_info);
3236       if (unlikely(os_destPath == NULL)) {
3237         logError(printf("cmdMove: cp_to_os_path(\"%s\", *, *) failed:\n"
3238                         "path_info=%d, err_info=%d\n",
3239                         striAsUnquotedCStri(destPath), path_info, err_info););
3240       } else {
3241         move_any_file(os_sourcePath, os_destPath, &err_info);
3242         os_stri_free(os_destPath);
3243       } /* if */
3244       os_stri_free(os_sourcePath);
3245     } /* if */
3246     if (unlikely(err_info != OKAY_NO_ERROR)) {
3247       raise_error(err_info);
3248     } /* if */
3249   } /* cmdMove */
3250 
3251 
3252 
3253 /**
3254  *  Reads the destination of a symbolic link.
3255  *  @return The destination referred by the symbolic link.
3256  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
3257  *             to the system path type or not enough memory to
3258  *             represent the result string.
3259  *  @exception RANGE_ERROR 'filePath' does not use the standard path
3260  *             representation or it cannot be converted to the system
3261  *             path type.
3262  *  @exception FILE_ERROR The file described with the path does not
3263  *             exist or is not a symbolic link.
3264  */
3265 striType cmdReadLink (const const_striType filePath)
3266 
3267   {
3268     errInfoType err_info = OKAY_NO_ERROR;
3269     striType destination;
3270 
3271   /* cmdReadLink */
3272     logFunction(printf("cmdReadLink(\"%s\")\n",
3273                        striAsUnquotedCStri(filePath)););
3274 #if HAS_READLINK
3275     destination = doReadLink(filePath, &err_info);
3276     if (unlikely(destination == NULL)) {
3277       raise_error(err_info);
3278     } /* if */
3279 #else
3280     raise_error(FILE_ERROR);
3281     destination = NULL;
3282 #endif
3283     logFunction(printf("cmdReadLink --> \"%s\"\n",
3284                        striAsUnquotedCStri(destination)););
3285     return destination;
3286   } /* cmdReadLink */
3287 
3288 
3289 
3290 /**
3291  *  Remove a file of any type unless it is a directory that is not empty.
3292  *  An attempt to remove a directory that is not empty triggers FILE_ERROR.
3293  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath' to
3294  *             the system path type.
3295  *  @exception RANGE_ERROR 'filePath' does not use the standard path
3296  *             representation or it cannot be converted to the system
3297  *             path type.
3298  *  @exception FILE_ERROR The file does not exist or it is a directory
3299  *             that is not empty or a system function returns an error.
3300  */
3301 void cmdRemoveFile (const const_striType filePath)
3302 
3303   {
3304     os_striType os_path;
3305     int path_info;
3306 #if REMOVE_FAILS_FOR_EMPTY_DIRS
3307     os_stat_struct file_stat;
3308 #endif
3309 #ifdef RENAME_BEFORE_REMOVE
3310     os_striType temp_name;
3311 #endif
3312     errInfoType err_info = OKAY_NO_ERROR;
3313 
3314   /* cmdRemoveFile */
3315     logFunction(printf("cmdRemoveFile(\"%s\")\n", striAsUnquotedCStri(filePath)););
3316     os_path = cp_to_os_path(filePath, &path_info, &err_info);
3317     if (unlikely(os_path == NULL)) {
3318       logError(printf("cmdRemoveFile: cp_to_os_path(\"%s\", *, *) failed:\n"
3319                       "path_info=%d, err_info=%d\n",
3320                       striAsUnquotedCStri(filePath), path_info, err_info););
3321     } else {
3322 #if REMOVE_FAILS_FOR_EMPTY_DIRS
3323       if (os_lstat(os_path, &file_stat) != 0) {
3324         logError(printf("cmdRemoveFile: os_lstat(\"" FMT_S_OS "\") failed:\n"
3325                         "errno=%d\nerror: %s\n",
3326                         os_path, errno, strerror(errno)););
3327         err_info = FILE_ERROR;
3328       } else {
3329 #ifdef RENAME_BEFORE_REMOVE
3330         temp_name = temp_name_in_dir(os_path);
3331         if (unlikely(temp_name == NULL)) {
3332           err_info = MEMORY_ERROR;
3333         } else {
3334           if (os_rename(os_path, temp_name) != 0) {
3335             logError(printf("cmdRemoveFile: "
3336                             "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
3337                             "errno=%d\nerror: %s\n",
3338                             os_path, temp_name, errno, strerror(errno)););
3339             err_info = FILE_ERROR;
3340           } else {
3341             if (S_ISDIR(file_stat.st_mode)) {
3342               if (os_rmdir(temp_name) != 0) {
3343                 logError(printf("cmdRemoveFile: os_rmdir(\"" FMT_S_OS "\") failed:\n"
3344                                 "errno=%d\nerror: %s\n",
3345                                 temp_name, errno, strerror(errno)););
3346                 err_info = FILE_ERROR;
3347               } /* if */
3348             } else {
3349               if (os_remove(temp_name) != 0) {
3350                 logError(printf("cmdRemoveFile: os_remove(\"" FMT_S_OS "\") failed:\n"
3351                                 "errno=%d\nerror: %s\n",
3352                                 temp_name, errno, strerror(errno)););
3353                 err_info = FILE_ERROR;
3354               } /* if */
3355             } /* if */
3356             if (unlikely(err_info != OKAY_NO_ERROR)) {
3357               /* Rename back to the original name. */
3358               if (os_rename(temp_name, os_path) != 0) {
3359                 logError(printf("cmdRemoveFile: "
3360                                 "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
3361                                 "errno=%d\nerror: %s\n",
3362                                 temp_name, os_path, errno, strerror(errno)););
3363               } /* if */
3364             } /* if */
3365           } /* if */
3366           os_stri_free(temp_name);
3367         } /* if */
3368 #else
3369         if (S_ISDIR(file_stat.st_mode)) {
3370           if (os_rmdir(os_path) != 0) {
3371             logError(printf("cmdRemoveFile: os_rmdir(\"" FMT_S_OS "\") failed:\n"
3372                             "errno=%d\nerror: %s\n",
3373                             os_path, errno, strerror(errno)););
3374             err_info = FILE_ERROR;
3375           } /* if */
3376         } else {
3377           if (os_remove(os_path) != 0) {
3378             logError(printf("cmdRemoveFile: os_remove(\"" FMT_S_OS "\") failed:\n"
3379                             "errno=%d\nerror: %s\n",
3380                             os_path, errno, strerror(errno)););
3381             err_info = FILE_ERROR;
3382           } /* if */
3383         } /* if */
3384 #endif
3385       } /* if */
3386 #else
3387 #ifdef RENAME_BEFORE_REMOVE
3388       temp_name = temp_name_in_dir(os_path);
3389       if (unlikely(temp_name == NULL)) {
3390         err_info = MEMORY_ERROR;
3391       } else {
3392         if (os_rename(os_path, temp_name) != 0) {
3393           logError(printf("cmdRemoveFile: "
3394                           "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
3395                           "errno=%d\nerror: %s\n",
3396                           os_path, temp_name, errno, strerror(errno)););
3397           err_info = FILE_ERROR;
3398         } else {
3399           if (os_remove(temp_name) != 0) {
3400             logError(printf("cmdRemoveFile: os_remove(\"" FMT_S_OS "\") failed:\n"
3401                             "errno=%d\nerror: %s\n",
3402                             temp_name, errno, strerror(errno)););
3403             if (os_rename(temp_name, os_path) != 0) {
3404               /* Rename back to the original name. */
3405               logError(printf("cmdRemoveFile: "
3406                               "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
3407                               "errno=%d\nerror: %s\n",
3408                               temp_name, os_path, errno, strerror(errno)););
3409             } /* if */
3410             err_info = FILE_ERROR;
3411           } /* if */
3412         } /* if */
3413         os_stri_free(temp_name);
3414       } /* if */
3415 #else
3416       if (os_remove(os_path) != 0) {
3417         logError(printf("cmdRemoveFile: os_remove(\"" FMT_S_OS "\") failed:\n"
3418                         "errno=%d\nerror: %s\n",
3419                         os_path, errno, strerror(errno)););
3420         err_info = FILE_ERROR;
3421       } /* if */
3422 #endif
3423 #endif
3424 #ifdef CHECK_IF_FILE_IS_REMOVED
3425       if (err_info == OKAY_NO_ERROR &&
3426           os_lstat(os_path, &file_stat) == 0) {
3427         logError(printf("cmdRemoveFile: File \"" FMT_S_OS "\" still present.\n",
3428                         os_path););
3429         /* err_info = FILE_ERROR; */
3430       } /* if */
3431 #endif
3432       os_stri_free(os_path);
3433     } /* if */
3434     if (unlikely(err_info != OKAY_NO_ERROR)) {
3435       raise_error(err_info);
3436     } /* if */
3437   } /* cmdRemoveFile */
3438 
3439 
3440 
3441 /**
3442  *  Remove a file of any type inclusive a directory tree.
3443  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath' to
3444  *             the system path type.
3445  *  @exception RANGE_ERROR 'filePath' does not use the standard path
3446  *             representation or it cannot be converted to the system
3447  *             path type.
3448  *  @exception FILE_ERROR The file does not exist or a system function
3449  *             returns an error.
3450  */
3451 void cmdRemoveTree (const const_striType filePath)
3452 
3453   {
3454     os_striType os_path;
3455     int path_info;
3456     os_stat_struct file_stat;
3457 #ifdef RENAME_BEFORE_REMOVE
3458     os_striType temp_name;
3459 #endif
3460     errInfoType err_info = OKAY_NO_ERROR;
3461 
3462   /* cmdRemoveTree */
3463     logFunction(printf("cmdRemoveTree(\"%s\")\n", striAsUnquotedCStri(filePath)););
3464     os_path = cp_to_os_path(filePath, &path_info, &err_info);
3465     if (unlikely(os_path == NULL)) {
3466       logError(printf("cmdRemoveTree: cp_to_os_path(\"%s\", *, *) failed:\n"
3467                       "path_info=%d, err_info=%d\n",
3468                       striAsUnquotedCStri(filePath), path_info, err_info););
3469     } else {
3470       if (os_lstat(os_path, &file_stat) != 0) {
3471         logError(printf("cmdRemoveTree: os_lstat(\"" FMT_S_OS "\") failed:\n"
3472                         "errno=%d\nerror: %s\n",
3473                         os_path, errno, strerror(errno)););
3474         err_info = FILE_ERROR;
3475       } else {
3476 #ifdef RENAME_BEFORE_REMOVE
3477         temp_name = temp_name_in_dir(os_path);
3478         if (unlikely(temp_name == NULL)) {
3479           err_info = MEMORY_ERROR;
3480         } else {
3481           if (os_rename(os_path, temp_name) != 0) {
3482             logError(printf("cmdRemoveTree: "
3483                             "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
3484                             "errno=%d\nerror: %s\n",
3485                             os_path, temp_name, errno, strerror(errno)););
3486             err_info = FILE_ERROR;
3487           } else {
3488             if (S_ISDIR(file_stat.st_mode)) {
3489               remove_dir(temp_name, &err_info);
3490             } else {
3491               if (os_remove(temp_name) != 0) {
3492                 logError(printf("cmdRemoveTree: os_remove(\"" FMT_S_OS "\") failed:\n"
3493                                 "errno=%d\nerror: %s\n",
3494                                 os_path, errno, strerror(errno)););
3495                 err_info = FILE_ERROR;
3496               } /* if */
3497             } /* if */
3498             if (unlikely(err_info != OKAY_NO_ERROR)) {
3499               if (os_rename(temp_name, os_path) != 0) {
3500                 /* Rename back to the original name. */
3501                 logError(printf("cmdRemoveTree: "
3502                                 "os_rename(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
3503                                 "errno=%d\nerror: %s\n",
3504                                 temp_name, os_path, errno, strerror(errno)););
3505               } /* if */
3506             } /* if */
3507           } /* if */
3508           os_stri_free(temp_name);
3509         } /* if */
3510 #else
3511         if (S_ISDIR(file_stat.st_mode)) {
3512           remove_dir(os_path, &err_info);
3513         } else {
3514           if (os_remove(os_path) != 0) {
3515             logError(printf("cmdRemoveTree: os_remove(\"" FMT_S_OS "\") failed:\n"
3516                           "errno=%d\nerror: %s\n",
3517                           os_path, errno, strerror(errno)););
3518             err_info = FILE_ERROR;
3519           } /* if */
3520         } /* if */
3521 #endif
3522       } /* if */
3523 #ifdef CHECK_IF_FILE_IS_REMOVED
3524       if (err_info == OKAY_NO_ERROR &&
3525           os_lstat(os_path, &file_stat) == 0) {
3526         logError(printf("cmdRemoveTree: File \"" FMT_S_OS "\" still present.\n",
3527                         os_path););
3528         /* err_info = FILE_ERROR; */
3529       } /* if */
3530 #endif
3531       os_stri_free(os_path);
3532     } /* if */
3533     if (unlikely(err_info != OKAY_NO_ERROR)) {
3534       raise_error(err_info);
3535     } /* if */
3536   } /* cmdRemoveTree */
3537 
3538 
3539 
3540 /**
3541  *  Add or change an environment variable.
3542  *  The function searches the environment for an environment variable
3543  *  with the given 'name'. If such an environment variable exists the
3544  *  corresponding value is changed to 'value'. If no environment variable
3545  *  with the given 'name' exists a new environment variable 'name' with
3546  *  the value 'value' is created.
3547  *  @exception MEMORY_ERROR Not enough memory to convert 'name' or 'value'
3548  *             to the system string type.
3549  *  @exception RANGE_ERROR 'name' or 'value' cannot be converted to the
3550  *             system string type or a system function returns an error.
3551  */
3552 void cmdSetenv (const const_striType name, const const_striType value)
3553 
3554   {
3555     errInfoType err_info = OKAY_NO_ERROR;
3556 
3557   /* cmdSetenv */
3558     setEnvironmentVariable(name, value, &err_info);
3559     if (unlikely(err_info != OKAY_NO_ERROR)) {
3560       raise_error(err_info);
3561     } /* if */
3562   } /* cmdSetenv */
3563 
3564 
3565 
3566 /**
3567  *  Set the access time of a file.
3568  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
3569  *             to the system path type.
3570  *  @exception RANGE_ERROR 'filePath' does not use the standard path
3571  *             representation or it cannot be converted to the system
3572  *             path type.
3573  *  @exception RANGE_ERROR 'aTime' is invalid or cannot be
3574  *             converted to the system file time.
3575  *  @exception FILE_ERROR A system function returns an error.
3576  */
3577 void cmdSetATime (const const_striType filePath,
3578     intType year, intType month, intType day, intType hour,
3579     intType min, intType sec, intType micro_sec, intType time_zone)
3580 
3581   {
3582     const_os_striType os_path;
3583     os_stat_struct stat_buf;
3584     os_utimbuf_struct utime_buf;
3585     int path_info;
3586     errInfoType err_info = OKAY_NO_ERROR;
3587 
3588   /* cmdSetATime */
3589     logFunction(printf("cmdSetATime(\"%s\", " F_D(04) "-" F_D(02) "-" F_D(02) " "
3590                        F_D(02) ":" F_D(02) ":" F_D(02) "." F_D(06) " " FMT_D ")\n",
3591                        striAsUnquotedCStri(filePath), year, month, day,
3592                        hour, min, sec, micro_sec, time_zone););
3593     os_path = cp_to_os_path(filePath, &path_info, &err_info);
3594     if (unlikely(os_path == NULL)) {
3595       logError(printf("cmdSetATime: cp_to_os_path(\"%s\", *, *) failed:\n"
3596                       "path_info=%d, err_info=%d\n",
3597                       striAsUnquotedCStri(filePath), path_info, err_info););
3598     } else {
3599       if (os_stat(os_path, &stat_buf) == 0) {
3600         utime_buf.actime = timToOsTimestamp(year, month, day, hour,
3601             min, sec, time_zone);
3602         /* printf("cmdSetATime: actime=" FMT_T "\n", utime_buf.actime); */
3603         utime_buf.modtime = stat_buf.st_mtime;
3604         if (unlikely(utime_buf.actime == (time_t) TIME_T_ERROR)) {
3605           logError(printf("cmdSetATime: timToOsTimestamp("
3606                           F_D(04) "-" F_D(02) "-" F_D(02) " " F_D(02) ":"
3607                           F_D(02) ":" F_D(02) "." F_D(06) " " FMT_D ") failed.\n",
3608                           year, month, day, hour, min, sec,
3609                           micro_sec, time_zone););
3610           err_info = RANGE_ERROR;
3611         } else if (unlikely(os_utime(os_path, &utime_buf) != 0)) {
3612           logError(printf("cmdSetATime: os_utime(\"" FMT_S_OS "\") failed:\n"
3613                           "errno=%d\nerror: %s\n",
3614                           os_path, errno, strerror(errno)););
3615           err_info = FILE_ERROR;
3616         } /* if */
3617       } else {
3618         err_info = FILE_ERROR;
3619       } /* if */
3620       os_stri_free(os_path);
3621     } /* if */
3622     if (unlikely(err_info != OKAY_NO_ERROR)) {
3623       raise_error(err_info);
3624     } /* if */
3625     logFunction(printf("cmdSetATime -->\n"););
3626   } /* cmdSetATime */
3627 
3628 
3629 
3630 /**
3631  *  Change the file mode (permissions) of a file.
3632  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
3633  *             to the system path type.
3634  *  @exception RANGE_ERROR 'filePath' does not use the standard path
3635  *             representation or it cannot be converted to the system
3636  *             path type.
3637  *  @exception FILE_ERROR A system function returns an error.
3638  */
3639 void cmdSetFileMode (const const_striType filePath, const const_setType mode)
3640 
3641   {
3642     os_striType os_path;
3643     intType intType_mode;
3644     int int_mode;
3645     int chmod_result;
3646     int path_info;
3647     errInfoType err_info = OKAY_NO_ERROR;
3648 
3649   /* cmdSetFileMode */
3650     logFunction(printf("cmdSetFileMode(\"%s\", 0x" F_X(3) ")\n",
3651                        striAsUnquotedCStri(filePath), setSConv(mode)););
3652     os_path = cp_to_os_path(filePath, &path_info, &err_info);
3653     if (unlikely(os_path == NULL)) {
3654       logError(printf("cmdSetFileMode: cp_to_os_path(\"%s\", *, *) failed:\n"
3655                       "path_info=%d, err_info=%d\n",
3656                       striAsUnquotedCStri(filePath), path_info, err_info););
3657     } else {
3658       intType_mode = setSConv(mode);
3659       if (intType_mode >= 0 && intType_mode <= 0777) {
3660         /* Just the read, write and execute permissions are accepted */
3661         int_mode = (int) intType_mode;
3662         /* printf("cmdSetFileMode: mode=0%o\n", int_mode); */
3663 #if MODE_BITS_NORMAL
3664         chmod_result = os_chmod(os_path, int_mode);
3665 #else
3666         /* Force the bits to the standard sequence */
3667         chmod_result = os_chmod(os_path,
3668             (int_mode & 0400 ? S_IRUSR : 0) |
3669             (int_mode & 0200 ? S_IWUSR : 0) |
3670             (int_mode & 0100 ? S_IXUSR : 0) |
3671             (int_mode & 0040 ? S_IRGRP : 0) |
3672             (int_mode & 0020 ? S_IWGRP : 0) |
3673             (int_mode & 0010 ? S_IXGRP : 0) |
3674             (int_mode & 0004 ? S_IROTH : 0) |
3675             (int_mode & 0002 ? S_IWOTH : 0) |
3676             (int_mode & 0001 ? S_IXOTH : 0));
3677 #endif
3678         if (chmod_result != 0) {
3679           logError(printf("cmdSetFileMode: os_chmod(\"" FMT_S_OS "\") failed:\n"
3680                           "errno=%d\nerror: %s\n",
3681                           os_path, errno, strerror(errno)););
3682           err_info = FILE_ERROR;
3683         } /* if */
3684       } else {
3685         logError(printf("cmdSetFileMode(\"%s\", 0x" F_X(3) ") failed:\n"
3686                         "Mode outside allowed range.\n",
3687                         striAsUnquotedCStri(filePath), setSConv(mode)););
3688         err_info = RANGE_ERROR;
3689       } /* if */
3690       os_stri_free(os_path);
3691     } /* if */
3692     if (unlikely(err_info != OKAY_NO_ERROR)) {
3693       raise_error(err_info);
3694     } /* if */
3695   } /* cmdSetFileMode */
3696 
3697 
3698 
3699 /**
3700  *  Set the modification time of a file.
3701  *  @exception MEMORY_ERROR Not enough memory to convert 'filePath'
3702  *             to the system path type.
3703  *  @exception RANGE_ERROR 'filePath' does not use the standard path
3704  *             representation or it cannot be converted to the system
3705  *             path type.
3706  *  @exception RANGE_ERROR 'aTime' is invalid or cannot be
3707  *             converted to the system file time.
3708  *  @exception FILE_ERROR A system function returns an error.
3709  */
3710 void cmdSetMTime (const const_striType filePath,
3711     intType year, intType month, intType day, intType hour,
3712     intType min, intType sec, intType micro_sec, intType time_zone)
3713 
3714   {
3715     const_os_striType os_path;
3716     os_stat_struct stat_buf;
3717     os_utimbuf_struct utime_buf;
3718     int path_info;
3719     errInfoType err_info = OKAY_NO_ERROR;
3720 
3721   /* cmdSetMTime */
3722     logFunction(printf("cmdSetMTime(\"%s\", " F_D(04) "-" F_D(02) "-" F_D(02) " "
3723                        F_D(02) ":" F_D(02) ":" F_D(02) "." F_D(06) " " FMT_D ")\n",
3724                        striAsUnquotedCStri(filePath), year, month,
3725                        day, hour, min, sec, micro_sec, time_zone););
3726     os_path = cp_to_os_path(filePath, &path_info, &err_info);
3727     if (unlikely(os_path == NULL)) {
3728       logError(printf("cmdSetMTime: cp_to_os_path(\"%s\", *, *) failed:\n"
3729                       "path_info=%d, err_info=%d\n",
3730                       striAsUnquotedCStri(filePath), path_info, err_info););
3731     } else {
3732       if (os_stat(os_path, &stat_buf) == 0) {
3733         utime_buf.actime = stat_buf.st_atime;
3734         utime_buf.modtime = timToOsTimestamp(year, month, day, hour,
3735             min, sec, time_zone);
3736         /* printf("cmdSetMTime: modtime=" FMT_T "\n", utime_buf.modtime); */
3737         if (unlikely(utime_buf.modtime == (time_t) TIME_T_ERROR)) {
3738           logError(printf("cmdSetMTime: timToOsTimestamp("
3739                           F_D(04) "-" F_D(02) "-" F_D(02) " " F_D(02) ":"
3740                           F_D(02) ":" F_D(02) "." F_D(06) " " FMT_D ") failed.\n",
3741                           year, month, day, hour, min, sec,
3742                           micro_sec, time_zone););
3743           err_info = RANGE_ERROR;
3744         } else if (unlikely(os_utime(os_path, &utime_buf) != 0)) {
3745           logError(printf("cmdSetMTime: os_utime(\"" FMT_S_OS "\") failed:\n"
3746                           "errno=%d\nerror: %s\n",
3747                           os_path, errno, strerror(errno)););
3748           err_info = FILE_ERROR;
3749         } /* if */
3750       } else {
3751         err_info = FILE_ERROR;
3752       } /* if */
3753       os_stri_free(os_path);
3754     } /* if */
3755     if (unlikely(err_info != OKAY_NO_ERROR)) {
3756       raise_error(err_info);
3757     } /* if */
3758     logFunction(printf("cmdSetMTime -->\n"););
3759   } /* cmdSetMTime */
3760 
3761 
3762 
3763 /**
3764  *  Sets the search path from an array of strings.
3765  *  The search path is used by the current process and its sub processes.
3766  *  The path of parent processes is not affected by this function.
3767  *  @exception MEMORY_ERROR Not enough memory to convert the path
3768  *             to the system string type.
3769  *  @exception RANGE_ERROR The path cannot be converted to the
3770  *             system string type or a system function returns an error.
3771  */
3772 void cmdSetSearchPath (rtlArrayType searchPath)
3773 
3774   {
3775     errInfoType err_info = OKAY_NO_ERROR;
3776 
3777   /* cmdSetSearchPath */
3778     setSearchPath(searchPath, &err_info);
3779     if (unlikely(err_info != OKAY_NO_ERROR)) {
3780       raise_error(err_info);
3781     } /* if */
3782   } /* cmdSetSearchPath */
3783 
3784 
3785 
3786 /**
3787  *  Use the shell to execute a 'command' with 'parameters'.
3788  *  Parameters which contain a space must be enclosed in double
3789  *  quotes (E.g.: shell("aCommand", "\"par 1\" par2"); ). The
3790  *  commands supported and the format of the 'parameters' are not
3791  *  covered by the description of the 'shell' function. Due to the
3792  *  usage of the operating system shell and external programs, it is
3793  *  hard to write portable programs, which use the 'shell' function.
3794  *  @param command Name of the command to be executed. A path must
3795  *         use the standard path representation.
3796  *  @param parameters Space separated list of parameters for the
3797  *         'command', or "" if there are no parameters.
3798  *  @return the return code of the executed command or of the shell.
3799  */
3800 intType cmdShell (const const_striType command, const const_striType parameters)
3801 
3802   {
3803     os_striType os_command;
3804     errInfoType err_info = OKAY_NO_ERROR;
3805     intType result;
3806 
3807   /* cmdShell */
3808     logFunction(printf("cmdShell(\"%s\", ", striAsUnquotedCStri(command));
3809                 printf("\"%s\")\n", striAsUnquotedCStri(parameters)););
3810 #if defined USE_EXTENDED_LENGTH_PATH && USE_EXTENDED_LENGTH_PATH
3811     adjustCwdForShell(&err_info);
3812 #endif
3813     os_command = cp_to_command(command, parameters, &err_info);
3814     if (unlikely(os_command == NULL)) {
3815       logError(printf("cmdShell: cp_to_command(\"%s\", ",
3816                       striAsUnquotedCStri(command));
3817                printf("\"%s\", *) failed:\n"
3818                       "err_info=%d\n",
3819                       striAsUnquotedCStri(parameters), err_info););
3820       raise_error(err_info);
3821       result = 0;
3822     } else {
3823       logMessage(printf("cmdShell: os_command: \"" FMT_S_OS "\"\n", os_command););
3824       result = (intType) os_system(os_command);
3825       /* if (result != 0) {
3826         printf("errno=%d\nerror: %s\n", errno, strerror(errno));
3827         printf("result=" FMT_D "\n", result);
3828       } */
3829       FREE_OS_STRI(os_command);
3830     } /* if */
3831     logFunction(printf("cmdShell --> " FMT_D "\n", result););
3832     return result;
3833   } /* cmdShell */
3834 
3835 
3836 
3837 #ifdef ESCAPE_SHELL_COMMANDS
3838 /**
3839  *  Convert a string, such that it can be used as shell parameter.
3840  *  The function adds escape characters or quotations to a string.
3841  *  The result is useable as parameter for the functions 'cmdShell'
3842  *  and 'filPopen'. Shell parameters must be escaped individually.
3843  *  Afterwards escaped parameters are joined to a space separated
3844  *  list of parameters.
3845  *  @return a string which can be used as shell parameter.
3846  *  @exception MEMORY_ERROR Not enough memory to convert 'stri'.
3847  */
3848 striType cmdShellEscape (const const_striType stri)
3849 
3850   {
3851     /* A shell parameter might start and end with quote ("): */
3852     const memSizeType numOfQuotes = 0;
3853     /* Maximum escape sequence length in shell parameter: */
3854     const memSizeType escSequenceMax = STRLEN("\\=");
3855     memSizeType inPos;
3856     memSizeType outPos;
3857     errInfoType err_info = OKAY_NO_ERROR;
3858     striType resized_result;
3859     striType result;
3860 
3861   /* cmdShellEscape */
3862     logFunction(printf("cmdShellEscape(\"%s\")", striAsUnquotedCStri(stri));
3863                 fflush(stdout););
3864     if (unlikely(stri->size > (MAX_STRI_LEN - numOfQuotes) / escSequenceMax ||
3865                  !ALLOC_STRI_SIZE_OK(result, escSequenceMax * stri->size + numOfQuotes))) {
3866       raise_error(MEMORY_ERROR);
3867       result = NULL;
3868     } else {
3869       for (inPos = 0, outPos = 0; inPos < stri->size; inPos++, outPos++) {
3870         switch (stri->mem[inPos]) {
3871           case '\t': case ' ':  case '!':  case '\"': case '#':
3872           case '$':  case '&':  case '\'': case '(':  case ')':
3873           case '*':  case ',':  case ':':  case ';':  case '<':
3874           case '=':  case '>':  case '?':  case '[':  case '\\':
3875           case ']':  case '^':  case '`':  case '{':  case '|':
3876           case '}':  case '~':
3877             result->mem[outPos] = '\\';
3878             outPos++;
3879             result->mem[outPos] = stri->mem[inPos];
3880             break;
3881           case '\0': case '\n':
3882             logError(printf("cmdShellEscape: "
3883                             "Illegal character in string ('\\" FMT_U32 ";').\n",
3884                             stri->mem[inPos]););
3885             err_info = RANGE_ERROR;
3886             break;
3887           default:
3888             result->mem[outPos] = stri->mem[inPos];
3889             break;
3890         } /* switch */
3891       } /* for */
3892       if (unlikely(err_info != OKAY_NO_ERROR)) {
3893         FREE_STRI(result, escSequenceMax * stri->size + numOfQuotes);
3894         raise_error(err_info);
3895         result = NULL;
3896       } else {
3897         REALLOC_STRI_SIZE_SMALLER(resized_result, result,
3898             escSequenceMax * stri->size + numOfQuotes, outPos);
3899         if (unlikely(resized_result == NULL)) {
3900           FREE_STRI(result, escSequenceMax * stri->size + numOfQuotes);
3901           raise_error(MEMORY_ERROR);
3902           result = NULL;
3903         } else {
3904           result = resized_result;
3905           COUNT3_STRI(escSequenceMax * stri->size + numOfQuotes, outPos);
3906           result->size = outPos;
3907         } /* if */
3908       } /* if */
3909     } /* if */
3910     logFunctionResult(printf("\"%s\"\n", striAsUnquotedCStri(result)););
3911     return result;
3912   } /* cmdShellEscape */
3913 
3914 #else
3915 
3916 
3917 
3918 /**
3919  *  Convert a string, such that it can be used as shell parameter.
3920  *  The function adds escape characters or quotations to a string.
3921  *  The result is useable as parameter for the functions 'cmdShell'
3922  *  and 'filPopen'. Shell parameters must be escaped individually.
3923  *  Afterwards escaped parameters are joined to a space separated
3924  *  list of parameters.
3925  *  @return a string which can be used as shell parameter.
3926  *  @exception MEMORY_ERROR Not enough memory to convert 'stri'.
3927  */
3928 striType cmdShellEscape (const const_striType stri)
3929 
3930   {
3931     /* A shell parameter might start and end with quote ("): */
3932     const memSizeType numOfQuotes = 2;
3933     /* Maximum escape sequence length in shell parameter: */
3934     const memSizeType escSequenceMax = 4;
3935     memSizeType inPos;
3936     memSizeType outPos;
3937     boolType quotation_mode = FALSE;
3938     boolType in_escaped_quotation = FALSE;
3939     memSizeType countBackslash;
3940     errInfoType err_info = OKAY_NO_ERROR;
3941     striType resized_result;
3942     striType result;
3943 
3944   /* cmdShellEscape */
3945     logFunction(printf("cmdShellEscape(\"%s\")", striAsUnquotedCStri(stri));
3946                 fflush(stdout););
3947     if (unlikely(stri->size > (MAX_STRI_LEN - numOfQuotes) / escSequenceMax ||
3948                  !ALLOC_STRI_SIZE_OK(result, escSequenceMax * stri->size + numOfQuotes))) {
3949       raise_error(MEMORY_ERROR);
3950       result = NULL;
3951     } else {
3952       for (inPos = 0, outPos = 0; inPos < stri->size; inPos++, outPos++) {
3953         switch (stri->mem[inPos]) {
3954           case '\t': case '\f': case ' ':  case '%':  case '*':
3955           case ',':  case ';':  case '=':  case '~':  case 160:
3956             if (!quotation_mode) {
3957               quotation_mode = TRUE;
3958               result->mem[outPos] = '"';
3959               outPos++;
3960             } /* if */
3961             result->mem[outPos] = stri->mem[inPos];
3962             break;
3963           case '&':  case '<':  case '>':  case '^':  case '|':
3964             if (!quotation_mode) {
3965               quotation_mode = TRUE;
3966               result->mem[outPos] = '"';
3967               outPos++;
3968             } /* if */
3969             if (in_escaped_quotation) {
3970               result->mem[outPos] = '^';
3971               outPos++;
3972             } /* if */
3973             result->mem[outPos] = stri->mem[inPos];
3974             break;
3975           case '\"':
3976             if (!quotation_mode) {
3977               quotation_mode = TRUE;
3978               result->mem[outPos] = '"';
3979               outPos++;
3980             } /* if */
3981             result->mem[outPos] = '\\';
3982             outPos++;
3983             result->mem[outPos] = stri->mem[inPos];
3984             in_escaped_quotation = !in_escaped_quotation;
3985             break;
3986           case '\\':
3987             result->mem[outPos] = '\\';
3988             outPos++;
3989             result->mem[outPos] = stri->mem[inPos];
3990             break;
3991           case '\0': case '\n': case '\r':
3992             logError(printf("cmdShellEscape: "
3993                             "Illegal character in string ('\\" FMT_U32 ";').\n",
3994                             stri->mem[inPos]););
3995             err_info = RANGE_ERROR;
3996             break;
3997           default:
3998             if (quotation_mode) {
3999               quotation_mode = FALSE;
4000               result->mem[outPos] = '"';
4001               outPos++;
4002             } /* if */
4003             result->mem[outPos] = stri->mem[inPos];
4004             break;
4005         } /* switch */
4006       } /* for */
4007       if (unlikely(err_info != OKAY_NO_ERROR)) {
4008         FREE_STRI(result, escSequenceMax * stri->size + numOfQuotes);
4009         raise_error(err_info);
4010         result = NULL;
4011       } else {
4012         if (quotation_mode) {
4013           result->mem[outPos] = '"';
4014           outPos++;
4015         } /* if */
4016         for (inPos = 0; inPos < outPos; inPos++) {
4017           if (result->mem[inPos] == '\\') {
4018             inPos++;
4019             countBackslash = 1;
4020             while (inPos < outPos && result->mem[inPos] == '\\') {
4021               inPos++;
4022               countBackslash++;
4023             } /* while */
4024             if (inPos == outPos || result->mem[inPos] != '"') {
4025               countBackslash /= 2;
4026               memcpy(&result->mem[inPos - countBackslash], &result->mem[inPos],
4027                      (outPos - inPos) * sizeof(strElemType));
4028               inPos -= countBackslash;
4029               outPos -= countBackslash;
4030             } /* if */
4031             inPos--;
4032           } /* if */
4033         } /* for */
4034         REALLOC_STRI_SIZE_SMALLER(resized_result, result,
4035             escSequenceMax * stri->size + numOfQuotes, outPos);
4036         if (unlikely(resized_result == NULL)) {
4037           FREE_STRI(result, escSequenceMax * stri->size + numOfQuotes);
4038           raise_error(MEMORY_ERROR);
4039           result = NULL;
4040         } else {
4041           result = resized_result;
4042           COUNT3_STRI(escSequenceMax * stri->size + numOfQuotes, outPos);
4043           result->size = outPos;
4044         } /* if */
4045       } /* if */
4046     } /* if */
4047     logFunctionResult(printf("\"%s\"\n", striAsUnquotedCStri(result)););
4048     return result;
4049   } /* cmdShellEscape */
4050 
4051 #endif
4052 
4053 
4054 
4055 /**
4056  *  Create a symbolic link.
4057  *  The symbolic link 'destPath' will refer to 'sourcePath' afterwards.
4058  *  @param sourcePath String to be contained in the symbolic link.
4059  *  @param destPath Name of the symbolic link to be created.
4060  *  @exception MEMORY_ERROR Not enough memory to convert sourcePath or
4061  *             destPath to the system path type.
4062  *  @exception RANGE_ERROR 'sourcePath' or 'destPath' does not use the
4063  *             standard path representation or one of them cannot be
4064  *             converted to the system path type.
4065  *  @exception FILE_ERROR A system function returns an error.
4066  */
4067 void cmdSymlink (const const_striType sourcePath, const const_striType destPath)
4068 
4069   {
4070 #if HAS_SYMBOLIC_LINKS
4071     os_striType os_sourcePath;
4072     os_striType os_destPath;
4073     int path_info;
4074 #endif
4075     errInfoType err_info = OKAY_NO_ERROR;
4076 
4077   /* cmdSymlink */
4078     logFunction(printf("cmdSymlink(\"%s\", ", striAsUnquotedCStri(sourcePath));
4079                 printf("\"%s\")\n", striAsUnquotedCStri(destPath)););
4080 #if HAS_SYMBOLIC_LINKS
4081     os_sourcePath = cp_to_os_path(sourcePath, &path_info, &err_info);
4082     if (likely(os_sourcePath != NULL)) {
4083       os_destPath = cp_to_os_path(destPath, &path_info, &err_info);
4084       if (likely(os_destPath != NULL)) {
4085         if (symlink(os_sourcePath, os_destPath) != 0) {
4086           err_info = FILE_ERROR;
4087         } /* if */
4088         os_stri_free(os_destPath);
4089       } /* if */
4090       os_stri_free(os_sourcePath);
4091     } /* if */
4092 #else
4093     err_info = FILE_ERROR;
4094 #endif
4095     if (unlikely(err_info != OKAY_NO_ERROR)) {
4096       raise_error(err_info);
4097     } /* if */
4098   } /* cmdSymlink */
4099 
4100 
4101 
4102 /**
4103  *  Convert a standard path to the path of the operating system.
4104  *  The result must be escaped with 'cmdShellEscape' to be useable as
4105  *  parameter for the functions 'cmdShell' and 'filPopen'.
4106  *  @param standardPath Path in the standard path representation.
4107  *  @return a string containing an operating system path.
4108  *  @exception MEMORY_ERROR Not enough memory to convert 'standardPath'.
4109  *  @exception RANGE_ERROR 'standardPath' is not representable as operating
4110  *             system path.
4111  */
4112 striType cmdToOsPath (const const_striType standardPath)
4113 
4114   {
4115     errInfoType err_info = OKAY_NO_ERROR;
4116     striType result;
4117 
4118   /* cmdToOsPath */
4119     logFunction(printf("cmdToOsPath(\"%s\")", striAsUnquotedCStri(standardPath));
4120                 fflush(stdout););
4121     if (unlikely(pathIsWrong(standardPath))) {
4122       logError(printf("cmdToOsPath: "
4123                       "\"%s\" uses a drive letter or ends with slash.\n",
4124                       striAsUnquotedCStri(standardPath)););
4125       err_info = RANGE_ERROR;
4126     } else {
4127       if_mapAbsoluteShellPathToDriveLetters(
4128           standardPath->size >= 1 && standardPath->mem[0] == '/', {
4129         /* Absolute path: Try to map the path to a drive letter */
4130         if (unlikely(standardPath->size == 1)) {
4131           /* "/"    cannot be mapped to a drive letter */
4132           logError(printf("cmdToOsPath: "
4133                           "\"%s\" cannot be mapped to a drive letter.\n",
4134                           striAsUnquotedCStri(standardPath)););
4135           err_info = RANGE_ERROR;
4136         } else if (standardPath->mem[1] >= 'a' && standardPath->mem[1] <= 'z') {
4137           if (standardPath->size == 2) {
4138             /* "/c"   is mapped to "c:/"  */
4139             if (unlikely(!ALLOC_STRI_SIZE_OK(result, 3))) {
4140               err_info = MEMORY_ERROR;
4141             } else {
4142               result->size = 3;
4143               result->mem[0] = standardPath->mem[1];
4144               result->mem[1] = ':';
4145               result->mem[2] = '/';
4146             } /* if */
4147           } else if (unlikely(standardPath->mem[2] != '/')) {
4148             /* "/cd"  cannot be mapped to a drive letter */
4149             logError(printf("cmdToOsPath: "
4150                             "\"%s\" cannot be mapped to a drive letter.\n",
4151                             striAsUnquotedCStri(standardPath)););
4152             err_info = RANGE_ERROR;
4153           } else {
4154             /* "/c/d" is mapped to "c:/d" */
4155             if (unlikely(!ALLOC_STRI_SIZE_OK(result, standardPath->size))) {
4156               err_info = MEMORY_ERROR;
4157             } else {
4158               result->size = standardPath->size;
4159               result->mem[0] = standardPath->mem[1];
4160               result->mem[1] = ':';
4161               result->mem[2] = '/';
4162               memcpy(&result->mem[3], &standardPath->mem[3],
4163                      (standardPath->size - 3) * sizeof(strElemType));
4164             } /* if */
4165           } /* if */
4166         } else {
4167           /* "/C"  cannot be mapped to a drive letter */
4168           logError(printf("cmdToOsPath: "
4169                           "\"%s\" cannot be mapped to a drive letter.\n",
4170                           striAsUnquotedCStri(standardPath)););
4171           err_info = RANGE_ERROR;
4172         } /* if */
4173       }, /* else */ {
4174         if (unlikely(!ALLOC_STRI_SIZE_OK(result, standardPath->size))) {
4175           err_info = MEMORY_ERROR;
4176         } else {
4177           result->size = standardPath->size;
4178           memcpy(result->mem, standardPath->mem, standardPath->size * sizeof(strElemType));
4179         } /* if */
4180       });
4181     } /* if */
4182     if (unlikely(err_info != OKAY_NO_ERROR)) {
4183       raise_error(err_info);
4184       result = NULL;
4185     } else {
4186       if_pathDelimiterNotSlash({
4187         memSizeType position;
4188 
4189         for (position = 0; position < result->size; position++) {
4190           if (result->mem[position] == '/') {
4191             result->mem[position] = SHELL_PATH_DELIMITER;
4192           } /* if */
4193         } /* for */
4194       });
4195     } /* if */
4196     logFunctionResult(printf("\"%s\"\n", striAsUnquotedCStri(result)););
4197     return result;
4198   } /* cmdToOsPath */
4199 
4200 
4201 
4202 #ifdef os_unsetenv
4203 /**
4204  *  Deletes the variable 'name' from the environment.
4205  *  If 'name' does not exist in the environment,
4206  *  then the function succeeds, and the environment is unchanged.
4207  *  @exception MEMORY_ERROR Not enough memory to convert 'name' to the
4208  *             system string type.
4209  *  @exception RANGE_ERROR 'name' cannot be converted to the system string
4210  *             type or a system function returns an error.
4211  */
4212 void cmdUnsetenv (const const_striType name)
4213 
4214   {
4215     os_striType env_name;
4216     int unsetenv_result;
4217     errInfoType err_info = OKAY_NO_ERROR;
4218 
4219   /* cmdUnsetenv */
4220     logFunction(printf("cmdUnsetenv(\"%s\")", striAsUnquotedCStri(name));
4221                 fflush(stdout););
4222     env_name = stri_to_os_stri(name, &err_info);
4223     if (unlikely(env_name == NULL)) {
4224       logError(printf("cmdUnsetenv: stri_to_os_stri(\"%s\", *, *) failed:\n"
4225                       "err_info=%d\n",
4226                       striAsUnquotedCStri(name), err_info););
4227       raise_error(err_info);
4228     } else {
4229       unsetenv_result = os_unsetenv(env_name);
4230       if (unlikely(unsetenv_result != 0)) {
4231         logError(printf("cmdUnsetenv: os_unsetenv(\"" FMT_S_OS "\") failed:\n"
4232                         "errno=%d\nerror: %s\n",
4233                         env_name, errno, strerror(errno)););
4234         err_info = RANGE_ERROR;
4235       } /* if */
4236       os_stri_free(env_name);
4237       if (unlikely(err_info != OKAY_NO_ERROR)) {
4238         raise_error(err_info);
4239       } /* if */
4240     } /* if */
4241     logFunction(printf("cmdUnsetenv -->\n"););
4242   } /* cmdUnsetenv */
4243 
4244 #else
4245 
4246 
4247 
4248 /**
4249  *  Deletes the variable 'name' from the environment.
4250  *  If 'name' does not exist in the environment,
4251  *  then the function succeeds, and the environment is unchanged.
4252  *  @exception MEMORY_ERROR Not enough memory to convert 'name' to the
4253  *             system string type.
4254  *  @exception RANGE_ERROR 'name' cannot be converted to the system string
4255  *             type or a system function returns an error.
4256  */
4257 void cmdUnsetenv (const const_striType name)
4258 
4259   {
4260     memSizeType stri_size;
4261     striType stri;
4262     os_striType env_stri;
4263     int putenv_result;
4264     errInfoType err_info = OKAY_NO_ERROR;
4265 
4266   /* cmdUnsetenv */
4267     logFunction(printf("cmdUnsetenv(\"%s\")", striAsUnquotedCStri(name));
4268                 fflush(stdout););
4269     if (strChPos(name, (charType) '=') != 0) {
4270       logError(printf("cmdUnsetenv(\"%s\"): "
4271                       "Name contains '=' (putenv() works with \"name=value\").\n",
4272                       striAsUnquotedCStri(name)););
4273       err_info = RANGE_ERROR;
4274     } else if (unlikely(name->size > MAX_STRI_LEN - 1)) {
4275       /* Number of bytes does not fit into memSizeType. */
4276       err_info = MEMORY_ERROR;
4277     } else {
4278       stri_size = name->size + 1;
4279       if (unlikely(!ALLOC_STRI_SIZE_OK(stri, stri_size))) {
4280         err_info = MEMORY_ERROR;
4281       } else {
4282         stri->size = stri_size;
4283         memcpy(stri->mem, name->mem,
4284             name->size * sizeof(strElemType));
4285         stri->mem[name->size] = (strElemType) '=';
4286         env_stri = stri_to_os_stri(stri, &err_info);
4287         FREE_STRI(stri, stri->size);
4288         if (likely(env_stri != NULL)) {
4289           /* printf("os_putenv(\"" FMT_S_OS "\")\n", env_stri); */
4290           putenv_result = os_putenv(env_stri);
4291           if (unlikely(putenv_result != 0)) {
4292             logError(printf("cmdUnsetenv: os_putenv(\"" FMT_S_OS "\") failed:\n"
4293                             "errno=%d\nerror: %s\n",
4294                             env_stri, errno, strerror(errno)););
4295             err_info = RANGE_ERROR;
4296           } /* if */
4297 #if DELETE_PUTENV_ARGUMENT
4298           os_stri_free(env_stri);
4299 #endif
4300         } /* if */
4301       } /* if */
4302     } /* if */
4303     if (unlikely(err_info != OKAY_NO_ERROR)) {
4304       raise_error(err_info);
4305     } /* if */
4306     logFunction(printf("cmdUnsetenv -->\n"););
4307   } /* cmdUnsetenv */
4308 
4309 #endif
4310