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. */
6 * This module implements the operating system specific routines
7 * related to the shell.
10 #define ___INCLUDED_FROM_OS_SHELL
11 #define ___VERSION 406003
19 /*---------------------------------------------------------------------------*/
22 ___shell_module ___shell_mod
=
26 #ifdef ___SHELL_MODULE_INIT
32 /*---------------------------------------------------------------------------*/
34 /* Access to shell environment variables. */
37 /****************** obsolete.... use ___getenv_UCS_2 */
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
),
60 ___UCS_2STRING
*value
;)
67 /* reject strings that contain "=" except as the first character */
76 #if ENV_CHAR_BYTES == 1
78 return ___FIX(___IMPL_LIMIT_ERR
);
81 return ___FIX(___IMPL_LIMIT_ERR
);
86 /* find in the environment a string of the form name=value */
88 e
= ___FIX(___NO_ERR
);
99 while ((p2
= *probe
++) != 0)
103 while (*p1
!= '\0' &&
104 *p1
== ___CAST(___UCS_2
,___CAST(unsigned char,*p2
)))
110 if (*p1
== '\0' && *p2
== '=')
116 while (p2
[len
] != '\0')
119 v
= ___CAST(___UCS_2STRING
,
120 ___alloc_mem (sizeof (___UCS_2
) * (len
+1)));
123 return ___FIX(___HEAP_OVERFLOW_ERR
);
127 v
[len
] = ___CAST(___UCS_2
,___CAST(unsigned char,p2
[len
]));
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
)
151 return ___FIX(___HEAP_OVERFLOW_ERR
);
156 cname_ptr
[name_len
] = name
[name_len
];
157 } while (name_len
-- > 0);
161 ___UCS_2
*cvalue_ptr
= 0;
162 ___UCS_2
*cname_ptr
= name
;
167 #ifndef USE_GetEnvironmentVariable
176 cvalue_ptr
= getenv (cname_ptr
);
182 #ifdef USE_GetEnvironmentVariable
185 ___CHAR_TYPE(___GETENV_CE_SELECT
) cvalue
[GETENV_VALUE_STATIC_SIZE
];
190 n
= GetEnvironmentVariable
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
));
201 n
= GetEnvironmentVariable
208 e
= ___FIX(___HEAP_OVERFLOW_ERR
);
217 while (cvalue_ptr
[len
] != '\0')
220 v
= ___CAST(___UCS_2STRING
,
221 ___alloc_mem (sizeof (___UCS_2
) * (len
+1)));
224 e
= ___FIX(___HEAP_OVERFLOW_ERR
);
229 v
[len
] = ___CAST(___UCS_2
,cvalue_ptr
[len
]);
236 #ifdef USE_GetEnvironmentVariable
238 if (cvalue_ptr
!= cvalue
)
239 ___free_mem (cvalue_ptr
);
244 #if ENV_CHAR_BYTES == 1
246 if (cname_ptr
!= cname
)
247 ___free_mem (cname_ptr
);
258 ___SCMOBJ ___setenv_UCS_2
259 ___P((___UCS_2STRING name
,
260 ___UCS_2STRING value
),
264 ___UCS_2STRING value
;)
271 /* reject strings that contain "=" except as the first character */
280 #if ENV_CHAR_BYTES == 1
282 return ___FIX(___IMPL_LIMIT_ERR
);
285 return ___FIX(___IMPL_LIMIT_ERR
);
288 name_len
= p1
- name
;
294 #if ENV_CHAR_BYTES == 1
296 return ___FIX(___IMPL_LIMIT_ERR
);
301 value_len
= p1
- value
;
303 /* find in the environment a string of the form name=value */
305 e
= ___FIX(___NO_ERR
);
310 char **old_environ
= environ
;
314 char *name_value
= ___CAST(char*,
315 ___alloc_mem (name_len
+ value_len
+ 2));
318 return ___FIX(___HEAP_OVERFLOW_ERR
);
326 *p2
++ = ___CAST(char,*p1
++);
334 while (value_len
> 0)
336 *p2
++ = ___CAST(char,*p1
++);
344 while ((p2
= *probe
++) != 0)
348 while (*p1
!= '\0' &&
349 *p1
== ___CAST(___UCS_2
,___CAST(unsigned char,*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
;
366 ___shell_mod
.environ_unused_at_end
--;
367 return ___FIX(___NO_ERR
);
372 int n
= probe
- old_environ
; /* length including null pointer at end */
374 ___shell_mod
.environ_unused_at_end
= n
/2 + 1;
378 ___alloc_mem ((n
+ ___shell_mod
.environ_unused_at_end
)
381 if (new_environ
== 0)
383 ___free_mem (name_value
);
384 return ___FIX(___HEAP_OVERFLOW_ERR
);
387 environ
= new_environ
;
391 *new_environ
++ = *probe
++;
393 *new_environ
++ = name_value
;
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;
408 #if ENV_CHAR_BYTES == 1
412 char cname
[SETENV_NAME_STATIC_SIZE
];
413 char cvalue
[SETENV_VALUE_STATIC_SIZE
];
415 if (name_len
< SETENV_NAME_STATIC_SIZE
)
419 cname_ptr
= ___CAST(char*,
420 ___alloc_mem (sizeof (*cname_ptr
)
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
)
436 cvalue_ptr
= ___CAST(char*,
437 ___alloc_mem (sizeof (*cvalue_ptr
)
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);
456 ___UCS_2
*cname_ptr
= name
;
457 ___UCS_2
*cvalue_ptr
= value
;
463 if (setenv (cname_ptr
, cvalue_ptr
, 1) < 0)
464 e
= err_code_from_errno ();
468 #ifdef USE_SetEnvironmentVariable
470 if (!SetEnvironmentVariable (cname_ptr
, cvalue_ptr
))
471 e
= err_code_from_GetLastError ();
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
);
492 ___SCMOBJ ___unsetenv_UCS_2
493 ___P((___UCS_2STRING name
),
495 ___UCS_2STRING name
;)
501 /* reject strings that contain "=" except as the first character */
510 #if ENV_CHAR_BYTES == 1
512 return ___FIX(___IMPL_LIMIT_ERR
);
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
);
532 while ((p2
= *probe
++) != 0)
536 while (*p1
!= '\0' &&
537 *p1
== ___CAST(___UCS_2
,___CAST(unsigned char,*p2
)))
543 if (*p1
== '\0' && *p2
== '=')
545 ___shell_mod
.environ_unused_at_end
++;
547 while ((probe
[-1] = probe
[0]) != 0)
550 return ___FIX(___NO_ERR
);
558 #if ENV_CHAR_BYTES == 1
561 char cname
[UNSETENV_NAME_STATIC_SIZE
];
563 if (name_len
< UNSETENV_NAME_STATIC_SIZE
)
567 cname_ptr
= ___CAST(char*,
568 ___alloc_mem (sizeof (*cname_ptr
)
572 return ___FIX(___HEAP_OVERFLOW_ERR
);
577 cname_ptr
[name_len
] = name
[name_len
];
578 } while (name_len
-- > 0);
582 ___UCS_2
*cname_ptr
= name
;
588 if (unsetenv (cname_ptr
) < 0)
589 e
= err_code_from_errno ();
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
);
611 #if ENV_CHAR_BYTES == 1
613 if (cname_ptr
!= cname
)
614 ___free_mem (cname_ptr
);
625 ___SCMOBJ ___os_getenv
626 ___P((___SCMOBJ name
),
632 ___UCS_2STRING cname
;
633 ___UCS_2STRING cvalue
;
635 if ((e
= ___SCMOBJ_to_NONNULLUCS_2STRING
639 != ___FIX(___NO_ERR
))
643 if ((e
= ___getenv_UCS_2 (cname
, &cvalue
)) != ___FIX(___NO_ERR
))
647 if ((e
= ___UCS_2STRING_to_SCMOBJ
651 != ___FIX(___NO_ERR
))
654 ___release_scmobj (result
);
657 ___free_mem (cvalue
);
660 ___release_string (cname
);
667 ___SCMOBJ ___os_setenv
668 ___P((___SCMOBJ name
,
676 ___UCS_2STRING cname
;
677 ___UCS_2STRING cvalue
;
679 if ((e
= ___SCMOBJ_to_NONNULLUCS_2STRING
683 == ___FIX(___NO_ERR
))
685 if (value
== ___ABSENT
)
686 e
= ___unsetenv_UCS_2 (cname
);
687 else if ((e
= ___SCMOBJ_to_NONNULLUCS_2STRING
691 == ___FIX(___NO_ERR
))
693 e
= ___setenv_UCS_2 (cname
, cvalue
);
694 ___release_string (cvalue
);
697 ___release_string (cname
);
704 ___SCMOBJ ___os_environ ___PVOID
710 #ifndef USE_GetEnvironmentStrings
719 if ((e
= ___NONNULLCHARSTRINGLIST_to_SCMOBJ
723 != ___FIX(___NO_ERR
))
726 ___release_scmobj (result
);
730 #ifdef USE_GetEnvironmentStrings
732 ___STRING_TYPE(___ENVIRON_CE_SELECT
) env
;
733 ___STRING_TYPE(___ENVIRON_CE_SELECT
) ptr
;
737 e
= ___FIX(___NO_ERR
);
740 env
= GetEnvironmentStrings ();
742 if (env
!= 0 && *env
!= 0)
746 /* find end of environment strings. */
750 do { ptr
++; } while (*ptr
!= 0);
751 ptr
++; /* skip null char at end of string */
756 ptr
--; /* move ptr to terminating null char of previous string */
758 while (ptr
> env
&& ptr
[-1] != 0)
761 if ((e
= ___NONNULLSTRING_to_SCMOBJ
765 ___CE(___ENVIRON_CE_SELECT
)))
766 != ___FIX(___NO_ERR
))
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
);
783 ___release_scmobj (result
);
787 if (!FreeEnvironmentStrings (env
))
788 e
= err_code_from_GetLastError ();
790 if (e
!= ___FIX(___NO_ERR
))
799 /*---------------------------------------------------------------------------*/
804 ___SCMOBJ ___os_shell_command
817 e
= ___FIX(___UNIMPL_ERR
);
826 if ((e
= ___SCMOBJ_to_NONNULLCHARSTRING
830 == ___FIX(___NO_ERR
))
834 if ((e
= ___SCMOBJ_to_NONNULLSTRING
838 ___CE(___PATH_CE_SELECT
),
840 == ___FIX(___NO_ERR
))
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 ();
850 if (chdir (___CAST(___STRING_TYPE(___PATH_CE_SELECT
),cdir
)) < 0)
851 e
= err_code_from_errno ();
854 ___disable_os_interrupts ();
856 code
= system (ccmd
);
859 e
= err_code_from_errno ();
861 e
= ___FIX(code
& ___MAX_FIX
);
863 ___enable_os_interrupts ();
865 chdir (old_dir
); /* ignore error */
869 ___release_string (cdir
);
872 ___release_string (ccmd
);
880 #define ___SHELL_COMMAND_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) ucs2
882 #define ___SHELL_COMMAND_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
887 if ((e
= ___SCMOBJ_to_NONNULLSTRING
891 ___CE(___SHELL_COMMAND_CE_SELECT
),
893 == ___FIX(___NO_ERR
))
897 if ((e
= ___SCMOBJ_to_STRING
901 ___CE(___PATH_CE_SELECT
),
903 == ___FIX(___NO_ERR
))
907 ___CHAR_TYPE(___PATH_CE_SELECT
) old_dir
[___PATH_MAX_LENGTH
+1];
909 n
= GetCurrentDirectory (___PATH_MAX_LENGTH
+1,
912 if (n
< 1 || n
> ___PATH_MAX_LENGTH
)
913 e
= err_code_from_GetLastError ();
916 if (!SetCurrentDirectory (___CAST(___STRING_TYPE(___PATH_CE_SELECT
),cdir
)))
917 e
= err_code_from_GetLastError ();
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".
932 PROCESS_INFORMATION pi
;
934 ZeroMemory (&si
, sizeof (si
));
936 ZeroMemory (&pi
, sizeof (pi
));
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 ();
952 if (WaitForSingleObject (pi
.hProcess
, INFINITE
) == WAIT_FAILED
||
953 !GetExitCodeProcess (pi
.hProcess
, &code
))
954 e
= err_code_from_GetLastError ();
956 e
= ___FIX(code
& ___MAX_FIX
);
958 CloseHandle (pi
.hProcess
); /* ignore error */
959 CloseHandle (pi
.hThread
); /* ignore error */
967 code
= _wsystem (___CAST(___STRING_TYPE(___SHELL_COMMAND_CE_SELECT
),ccmd
));
969 code
= system (___CAST(___STRING_TYPE(___SHELL_COMMAND_CE_SELECT
),ccmd
));
973 e
= err_code_from_errno ();
975 e
= ___FIX(code
& ___MAX_FIX
);
979 SetCurrentDirectory (old_dir
); /* ignore error */
983 ___release_string (cdir
);
986 ___release_string (ccmd
);
995 /*---------------------------------------------------------------------------*/
997 /* Shell module initialization/finalization. */
1000 ___SCMOBJ ___setup_shell_module ___PVOID
1002 if (!___shell_mod
.setup
)
1006 ___shell_mod
.environ_unused_at_end
= 0;
1007 ___shell_mod
.environ_was_extended
= 0;
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
)
1025 if (___shell_mod
.environ_was_extended
)
1026 ___free_mem (environ
);
1030 ___shell_mod
.setup
= 0;
1035 /*---------------------------------------------------------------------------*/