Improve GambitREPL iOS example.
[gambit-c.git] / lib / os_shell.c
blob5dd1a3b5bd56943b653ec3d9ec08b8021167d4fa
1 /* File: "os_shell.c", Time-stamp: <2009-03-14 09:15:57 feeley> */
3 /* Copyright (c) 1994-2009 by Marc Feeley, All Rights Reserved. */
5 /*
6 * This module implements the operating system specific routines
7 * related to the shell.
8 */
10 #define ___INCLUDED_FROM_OS_SHELL
11 #define ___VERSION 406003
12 #include "gambit.h"
14 #include "os_base.h"
15 #include "os_shell.h"
16 #include "os_files.h"
19 /*---------------------------------------------------------------------------*/
22 ___shell_module ___shell_mod =
26 #ifdef ___SHELL_MODULE_INIT
27 ___SHELL_MODULE_INIT
28 #endif
32 /*---------------------------------------------------------------------------*/
34 /* Access to shell environment variables. */
37 /****************** obsolete.... use ___getenv_UCS_2 */
38 char *___getenv
39 ___P((char *name),
40 (name)
41 char *name;)
43 return getenv (name);
47 #define GETENV_NAME_STATIC_SIZE 128
48 #define GETENV_VALUE_STATIC_SIZE 128
49 #define SETENV_NAME_STATIC_SIZE 128
50 #define SETENV_VALUE_STATIC_SIZE 128
51 #define UNSETENV_NAME_STATIC_SIZE 128
54 ___SCMOBJ ___getenv_UCS_2
55 ___P((___UCS_2STRING name,
56 ___UCS_2STRING *value),
57 (name,
58 value)
59 ___UCS_2STRING name;
60 ___UCS_2STRING *value;)
62 ___SCMOBJ e;
63 ___UCS_2STRING v;
64 ___UCS_2STRING p1;
65 int name_len;
67 /* reject strings that contain "=" except as the first character */
69 p1 = name;
71 if (*p1 == '=')
72 p1++;
74 while (*p1 != '\0')
76 #if ENV_CHAR_BYTES == 1
77 if (*p1 > 255)
78 return ___FIX(___IMPL_LIMIT_ERR);
79 #endif
80 if (*p1++ == '=')
81 return ___FIX(___IMPL_LIMIT_ERR);
84 name_len = p1 - name;
86 /* find in the environment a string of the form name=value */
88 e = ___FIX(___NO_ERR);
89 *value = 0;
91 #ifdef USE_environ
94 char **probe;
95 char *p2;
97 probe = environ;
99 while ((p2 = *probe++) != 0)
101 p1 = name;
103 while (*p1 != '\0' &&
104 *p1 == ___CAST(___UCS_2,___CAST(unsigned char,*p2)))
106 p1++;
107 p2++;
110 if (*p1 == '\0' && *p2 == '=')
112 int len = 0;
114 p2++;
116 while (p2[len] != '\0')
117 len++;
119 v = ___CAST(___UCS_2STRING,
120 ___alloc_mem (sizeof (___UCS_2) * (len+1)));
122 if (v == 0)
123 return ___FIX(___HEAP_OVERFLOW_ERR);
127 v[len] = ___CAST(___UCS_2,___CAST(unsigned char,p2[len]));
128 } while (len-- > 0);
130 *value = v;
135 #else
138 #if ENV_CHAR_BYTES == 1
140 char *cvalue_ptr = 0;
141 char cname[GETENV_NAME_STATIC_SIZE];
142 char *cname_ptr = cname;
144 if (name_len >= GETENV_NAME_STATIC_SIZE)
146 cname_ptr = ___CAST(char*,
147 ___alloc_mem (sizeof (*cname_ptr)
148 * (name_len+1)));
150 if (cname_ptr == 0)
151 return ___FIX(___HEAP_OVERFLOW_ERR);
156 cname_ptr[name_len] = name[name_len];
157 } while (name_len-- > 0);
159 #else
161 ___UCS_2 *cvalue_ptr = 0;
162 ___UCS_2 *cname_ptr = name;
164 #endif
166 #ifndef USE_getenv
167 #ifndef USE_GetEnvironmentVariable
169 if (cvalue_ptr != 0)
171 #endif
172 #endif
174 #ifdef USE_getenv
176 cvalue_ptr = getenv (cname_ptr);
178 if (cvalue_ptr != 0)
180 #endif
182 #ifdef USE_GetEnvironmentVariable
185 ___CHAR_TYPE(___GETENV_CE_SELECT) cvalue[GETENV_VALUE_STATIC_SIZE];
186 int n;
188 cvalue_ptr = cvalue;
190 n = GetEnvironmentVariable
191 (cname_ptr,
192 cvalue_ptr,
193 GETENV_VALUE_STATIC_SIZE);
195 if (n >= GETENV_VALUE_STATIC_SIZE)
197 cvalue_ptr = ___CAST(___CHAR_TYPE(___GETENV_CE_SELECT)*,
198 ___alloc_mem (sizeof (*cvalue_ptr) * n));
200 if (cvalue_ptr != 0)
201 n = GetEnvironmentVariable
202 (cname_ptr,
203 cvalue_ptr,
207 if (cvalue_ptr == 0)
208 e = ___FIX(___HEAP_OVERFLOW_ERR);
209 else if (n > 0)
211 #endif
214 ___UCS_2STRING v;
215 int len = 0;
217 while (cvalue_ptr[len] != '\0')
218 len++;
220 v = ___CAST(___UCS_2STRING,
221 ___alloc_mem (sizeof (___UCS_2) * (len+1)));
223 if (v == 0)
224 e = ___FIX(___HEAP_OVERFLOW_ERR);
225 else
229 v[len] = ___CAST(___UCS_2,cvalue_ptr[len]);
230 } while (len-- > 0);
232 *value = v;
236 #ifdef USE_GetEnvironmentVariable
238 if (cvalue_ptr != cvalue)
239 ___free_mem (cvalue_ptr);
242 #endif
244 #if ENV_CHAR_BYTES == 1
246 if (cname_ptr != cname)
247 ___free_mem (cname_ptr);
249 #endif
252 #endif
254 return e;
258 ___SCMOBJ ___setenv_UCS_2
259 ___P((___UCS_2STRING name,
260 ___UCS_2STRING value),
261 (name,
262 value)
263 ___UCS_2STRING name;
264 ___UCS_2STRING value;)
266 ___SCMOBJ e;
267 ___UCS_2STRING p1;
268 int name_len;
269 int value_len;
271 /* reject strings that contain "=" except as the first character */
273 p1 = name;
275 if (*p1 == '=')
276 p1++;
278 while (*p1 != '\0')
280 #if ENV_CHAR_BYTES == 1
281 if (*p1 > 255)
282 return ___FIX(___IMPL_LIMIT_ERR);
283 #endif
284 if (*p1++ == '=')
285 return ___FIX(___IMPL_LIMIT_ERR);
288 name_len = p1 - name;
290 p1 = value;
292 while (*p1 != '\0')
294 #if ENV_CHAR_BYTES == 1
295 if (*p1 > 255)
296 return ___FIX(___IMPL_LIMIT_ERR);
297 #endif
298 p1++;
301 value_len = p1 - value;
303 /* find in the environment a string of the form name=value */
305 e = ___FIX(___NO_ERR);
307 #ifdef USE_environ
310 char **old_environ = environ;
311 char **probe;
312 char *p2;
314 char *name_value = ___CAST(char*,
315 ___alloc_mem (name_len + value_len + 2));
317 if (name_value == 0)
318 return ___FIX(___HEAP_OVERFLOW_ERR);
320 p2 = name_value;
322 p1 = name;
324 while (name_len > 0)
326 *p2++ = ___CAST(char,*p1++);
327 name_len--;
330 *p2++ = '=';
332 p1 = value;
334 while (value_len > 0)
336 *p2++ = ___CAST(char,*p1++);
337 value_len--;
340 *p2++ = '\0';
342 probe = old_environ;
344 while ((p2 = *probe++) != 0)
346 p1 = name;
348 while (*p1 != '\0' &&
349 *p1 == ___CAST(___UCS_2,___CAST(unsigned char,*p2)))
351 p1++;
352 p2++;
355 if (*p1 == '\0' && *p2 == '=')
357 probe[-1] = name_value;
358 return ___FIX(___NO_ERR);
362 if (___shell_mod.environ_unused_at_end > 0)
364 probe[-1] = name_value;
365 probe[0] = 0;
366 ___shell_mod.environ_unused_at_end--;
367 return ___FIX(___NO_ERR);
369 else
371 char **new_environ;
372 int n = probe - old_environ; /* length including null pointer at end */
374 ___shell_mod.environ_unused_at_end = n/2 + 1;
376 new_environ =
377 ___CAST(char**,
378 ___alloc_mem ((n + ___shell_mod.environ_unused_at_end)
379 * sizeof (char*)));
381 if (new_environ == 0)
383 ___free_mem (name_value);
384 return ___FIX(___HEAP_OVERFLOW_ERR);
387 environ = new_environ;
388 probe = old_environ;
390 while (--n > 0)
391 *new_environ++ = *probe++;
393 *new_environ++ = name_value;
394 *new_environ++ = 0;
396 ___shell_mod.environ_unused_at_end--;
398 if (___shell_mod.environ_was_extended)
399 ___free_mem (old_environ);
401 ___shell_mod.environ_was_extended = 1;
405 #else
408 #if ENV_CHAR_BYTES == 1
410 char *cname_ptr;
411 char *cvalue_ptr;
412 char cname[SETENV_NAME_STATIC_SIZE];
413 char cvalue[SETENV_VALUE_STATIC_SIZE];
415 if (name_len < SETENV_NAME_STATIC_SIZE)
416 cname_ptr = cname;
417 else
419 cname_ptr = ___CAST(char*,
420 ___alloc_mem (sizeof (*cname_ptr)
421 * (name_len+1)));
423 if (cname_ptr == 0)
424 return ___FIX(___HEAP_OVERFLOW_ERR);
429 cname_ptr[name_len] = name[name_len];
430 } while (name_len-- > 0);
432 if (value_len < SETENV_VALUE_STATIC_SIZE)
433 cvalue_ptr = cvalue;
434 else
436 cvalue_ptr = ___CAST(char*,
437 ___alloc_mem (sizeof (*cvalue_ptr)
438 * (value_len+1)));
440 if (cvalue_ptr == 0)
442 if (cname_ptr != cname)
443 ___free_mem (cname_ptr);
445 return ___FIX(___HEAP_OVERFLOW_ERR);
451 cvalue_ptr[value_len] = value[value_len];
452 } while (value_len-- > 0);
454 #else
456 ___UCS_2 *cname_ptr = name;
457 ___UCS_2 *cvalue_ptr = value;
459 #endif
461 #ifdef USE_setenv
463 if (setenv (cname_ptr, cvalue_ptr, 1) < 0)
464 e = err_code_from_errno ();
466 #endif
468 #ifdef USE_SetEnvironmentVariable
470 if (!SetEnvironmentVariable (cname_ptr, cvalue_ptr))
471 e = err_code_from_GetLastError ();
473 #endif
475 #if ENV_CHAR_BYTES == 1
477 if (cvalue_ptr != cvalue)
478 ___free_mem (cvalue_ptr);
480 if (cname_ptr != cname)
481 ___free_mem (cname_ptr);
483 #endif
486 #endif
488 return e;
492 ___SCMOBJ ___unsetenv_UCS_2
493 ___P((___UCS_2STRING name),
494 (name)
495 ___UCS_2STRING name;)
497 ___SCMOBJ e;
498 ___UCS_2STRING p1;
499 int name_len;
501 /* reject strings that contain "=" except as the first character */
503 p1 = name;
505 if (*p1 == '=')
506 p1++;
508 while (*p1 != '\0')
510 #if ENV_CHAR_BYTES == 1
511 if (*p1 > 255)
512 return ___FIX(___IMPL_LIMIT_ERR);
513 #endif
514 if (*p1++ == '=')
515 return ___FIX(___IMPL_LIMIT_ERR);
518 name_len = p1 - name;
520 /* find in the environment a string of the form name=value */
522 e = ___FIX(___NO_ERR);
524 #ifdef USE_environ
527 char **probe;
528 char *p2;
530 probe = environ;
532 while ((p2 = *probe++) != 0)
534 p1 = name;
536 while (*p1 != '\0' &&
537 *p1 == ___CAST(___UCS_2,___CAST(unsigned char,*p2)))
539 p1++;
540 p2++;
543 if (*p1 == '\0' && *p2 == '=')
545 ___shell_mod.environ_unused_at_end++;
547 while ((probe[-1] = probe[0]) != 0)
548 probe++;
550 return ___FIX(___NO_ERR);
555 #else
558 #if ENV_CHAR_BYTES == 1
560 char *cname_ptr;
561 char cname[UNSETENV_NAME_STATIC_SIZE];
563 if (name_len < UNSETENV_NAME_STATIC_SIZE)
564 cname_ptr = cname;
565 else
567 cname_ptr = ___CAST(char*,
568 ___alloc_mem (sizeof (*cname_ptr)
569 * (name_len+1)));
571 if (cname_ptr == 0)
572 return ___FIX(___HEAP_OVERFLOW_ERR);
577 cname_ptr[name_len] = name[name_len];
578 } while (name_len-- > 0);
580 #else
582 ___UCS_2 *cname_ptr = name;
584 #endif
586 #ifdef USE_unsetenv
588 if (unsetenv (cname_ptr) < 0)
589 e = err_code_from_errno ();
591 #endif
593 #ifdef USE_SetEnvironmentVariable
595 if (!SetEnvironmentVariable (cname_ptr, 0))
597 e = err_code_from_GetLastError ();
600 * Apparently an error is signaled if the environment
601 * variable being removed does not exist (the Microsoft
602 * documentation does not mention this).
605 if (e == ___FIX(___WIN32_ERR(ERROR_ENVVAR_NOT_FOUND)))
606 e = ___FIX(___NO_ERR);
609 #endif
611 #if ENV_CHAR_BYTES == 1
613 if (cname_ptr != cname)
614 ___free_mem (cname_ptr);
616 #endif
619 #endif
621 return e;
625 ___SCMOBJ ___os_getenv
626 ___P((___SCMOBJ name),
627 (name)
628 ___SCMOBJ name;)
630 ___SCMOBJ e;
631 ___SCMOBJ result;
632 ___UCS_2STRING cname;
633 ___UCS_2STRING cvalue;
635 if ((e = ___SCMOBJ_to_NONNULLUCS_2STRING
636 (name,
637 &cname,
639 != ___FIX(___NO_ERR))
640 result = e;
641 else
643 if ((e = ___getenv_UCS_2 (cname, &cvalue)) != ___FIX(___NO_ERR))
644 result = e;
645 else
647 if ((e = ___UCS_2STRING_to_SCMOBJ
648 (cvalue,
649 &result,
650 ___RETURN_POS))
651 != ___FIX(___NO_ERR))
652 result = e;
653 else
654 ___release_scmobj (result);
656 if (cvalue != 0)
657 ___free_mem (cvalue);
660 ___release_string (cname);
663 return result;
667 ___SCMOBJ ___os_setenv
668 ___P((___SCMOBJ name,
669 ___SCMOBJ value),
670 (name,
671 value)
672 ___SCMOBJ name;
673 ___SCMOBJ value;)
675 ___SCMOBJ e;
676 ___UCS_2STRING cname;
677 ___UCS_2STRING cvalue;
679 if ((e = ___SCMOBJ_to_NONNULLUCS_2STRING
680 (name,
681 &cname,
683 == ___FIX(___NO_ERR))
685 if (value == ___ABSENT)
686 e = ___unsetenv_UCS_2 (cname);
687 else if ((e = ___SCMOBJ_to_NONNULLUCS_2STRING
688 (value,
689 &cvalue,
691 == ___FIX(___NO_ERR))
693 e = ___setenv_UCS_2 (cname, cvalue);
694 ___release_string (cvalue);
697 ___release_string (cname);
700 return e;
704 ___SCMOBJ ___os_environ ___PVOID
706 ___SCMOBJ e;
707 ___SCMOBJ result;
709 #ifndef USE_environ
710 #ifndef USE_GetEnvironmentStrings
712 result = ___NUL;
714 #endif
715 #endif
717 #ifdef USE_environ
719 if ((e = ___NONNULLCHARSTRINGLIST_to_SCMOBJ
720 (environ,
721 &result,
722 ___RETURN_POS))
723 != ___FIX(___NO_ERR))
724 result = e;
725 else
726 ___release_scmobj (result);
728 #endif
730 #ifdef USE_GetEnvironmentStrings
732 ___STRING_TYPE(___ENVIRON_CE_SELECT) env;
733 ___STRING_TYPE(___ENVIRON_CE_SELECT) ptr;
734 ___SCMOBJ pair;
735 ___SCMOBJ str;
737 e = ___FIX(___NO_ERR);
738 result = ___NUL;
740 env = GetEnvironmentStrings ();
742 if (env != 0 && *env != 0)
744 ptr = env;
746 /* find end of environment strings. */
750 do { ptr++; } while (*ptr != 0);
751 ptr++; /* skip null char at end of string */
752 } while (*ptr != 0);
754 while (ptr > env)
756 ptr--; /* move ptr to terminating null char of previous string */
758 while (ptr > env && ptr[-1] != 0)
759 ptr--;
761 if ((e = ___NONNULLSTRING_to_SCMOBJ
762 (ptr,
763 &str,
764 ___RETURN_POS,
765 ___CE(___ENVIRON_CE_SELECT)))
766 != ___FIX(___NO_ERR))
767 break;
769 pair = ___make_pair (str, result, ___STILL);
771 ___release_scmobj (str);
772 ___release_scmobj (result);
774 if (___FIXNUMP(pair))
776 e = ___FIX(___CTOS_HEAP_OVERFLOW_ERR+___RETURN_POS);
777 break;
780 result = pair;
783 ___release_scmobj (result);
786 if (env != 0)
787 if (!FreeEnvironmentStrings (env))
788 e = err_code_from_GetLastError ();
790 if (e != ___FIX(___NO_ERR))
791 result = e;
793 #endif
795 return result;
799 /*---------------------------------------------------------------------------*/
801 /* Shell command. */
804 ___SCMOBJ ___os_shell_command
805 ___P((___SCMOBJ cmd,
806 ___SCMOBJ dir),
807 (cmd,
808 dir)
809 ___SCMOBJ cmd;
810 ___SCMOBJ dir;)
812 ___SCMOBJ e;
814 #ifndef USE_POSIX
815 #ifndef USE_WIN32
817 e = ___FIX(___UNIMPL_ERR);
819 #endif
820 #endif
822 #ifdef USE_POSIX
824 char *ccmd;
826 if ((e = ___SCMOBJ_to_NONNULLCHARSTRING
827 (cmd,
828 &ccmd,
830 == ___FIX(___NO_ERR))
832 void *cdir;
834 if ((e = ___SCMOBJ_to_NONNULLSTRING
835 (dir,
836 &cdir,
838 ___CE(___PATH_CE_SELECT),
840 == ___FIX(___NO_ERR))
842 int code;
844 ___CHAR_TYPE(___PATH_CE_SELECT) old_dir[___PATH_MAX_LENGTH+1];
846 if (getcwd (old_dir, ___PATH_MAX_LENGTH) == 0)
847 e = err_code_from_errno ();
848 else
850 if (chdir (___CAST(___STRING_TYPE(___PATH_CE_SELECT),cdir)) < 0)
851 e = err_code_from_errno ();
852 else
854 ___disable_os_interrupts ();
856 code = system (ccmd);
858 if (code == -1)
859 e = err_code_from_errno ();
860 else
861 e = ___FIX(code & ___MAX_FIX);
863 ___enable_os_interrupts ();
865 chdir (old_dir); /* ignore error */
869 ___release_string (cdir);
872 ___release_string (ccmd);
875 #endif
877 #ifdef USE_WIN32
879 #ifdef _UNICODE
880 #define ___SHELL_COMMAND_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) ucs2
881 #else
882 #define ___SHELL_COMMAND_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
883 #endif
885 void *ccmd;
887 if ((e = ___SCMOBJ_to_NONNULLSTRING
888 (cmd,
889 &ccmd,
891 ___CE(___SHELL_COMMAND_CE_SELECT),
893 == ___FIX(___NO_ERR))
895 void *cdir;
897 if ((e = ___SCMOBJ_to_STRING
898 (dir,
899 &cdir,
901 ___CE(___PATH_CE_SELECT),
903 == ___FIX(___NO_ERR))
905 DWORD n;
907 ___CHAR_TYPE(___PATH_CE_SELECT) old_dir[___PATH_MAX_LENGTH+1];
909 n = GetCurrentDirectory (___PATH_MAX_LENGTH+1,
910 old_dir);
912 if (n < 1 || n > ___PATH_MAX_LENGTH)
913 e = err_code_from_GetLastError ();
914 else
916 if (!SetCurrentDirectory (___CAST(___STRING_TYPE(___PATH_CE_SELECT),cdir)))
917 e = err_code_from_GetLastError ();
918 else
921 #ifdef ___DO_NOT_USE_system
924 * This code does not really cause the shell to run
925 * the command. This means that the shell builtin
926 * commands (such as "DIR" cannot be executed. It
927 * is better to use "system" and "_wsystem".
930 DWORD code;
931 STARTUPINFO si;
932 PROCESS_INFORMATION pi;
934 ZeroMemory (&si, sizeof (si));
935 si.cb = sizeof (si);
936 ZeroMemory (&pi, sizeof (pi));
938 if (!CreateProcess
939 (NULL, /* module name */
940 ___CAST(___STRING_TYPE(___SHELL_COMMAND_CE_SELECT),ccmd),
941 NULL, /* process handle not inheritable */
942 NULL, /* thread handle not inheritable */
943 FALSE, /* set handle inheritance to FALSE */
944 0, /* no creation flags */
945 NULL, /* use parent's environment block */
946 NULL, /* use parent's starting directory */
947 &si, /* pointer to STARTUPINFO structure */
948 &pi)) /* pointer to PROCESS_INFORMATION structure */
949 e = err_code_from_GetLastError ();
950 else
952 if (WaitForSingleObject (pi.hProcess, INFINITE) == WAIT_FAILED ||
953 !GetExitCodeProcess (pi.hProcess, &code))
954 e = err_code_from_GetLastError ();
955 else
956 e = ___FIX(code & ___MAX_FIX);
958 CloseHandle (pi.hProcess); /* ignore error */
959 CloseHandle (pi.hThread); /* ignore error */
962 #else
964 int code;
966 #ifdef _UNICODE
967 code = _wsystem (___CAST(___STRING_TYPE(___SHELL_COMMAND_CE_SELECT),ccmd));
968 #else
969 code = system (___CAST(___STRING_TYPE(___SHELL_COMMAND_CE_SELECT),ccmd));
970 #endif
972 if (code == -1)
973 e = err_code_from_errno ();
974 else
975 e = ___FIX(code & ___MAX_FIX);
977 #endif
979 SetCurrentDirectory (old_dir); /* ignore error */
983 ___release_string (cdir);
986 ___release_string (ccmd);
989 #endif
991 return e;
995 /*---------------------------------------------------------------------------*/
997 /* Shell module initialization/finalization. */
1000 ___SCMOBJ ___setup_shell_module ___PVOID
1002 if (!___shell_mod.setup)
1004 #ifdef USE_environ
1006 ___shell_mod.environ_unused_at_end = 0;
1007 ___shell_mod.environ_was_extended = 0;
1009 #endif
1011 ___shell_mod.setup = 1;
1012 return ___FIX(___NO_ERR);
1015 return ___FIX(___UNKNOWN_ERR);
1019 void ___cleanup_shell_module ___PVOID
1021 if (___shell_mod.setup)
1023 #ifdef USE_environ
1025 if (___shell_mod.environ_was_extended)
1026 ___free_mem (environ);
1028 #endif
1030 ___shell_mod.setup = 0;
1035 /*---------------------------------------------------------------------------*/