note
	description: "The objects available from the environment at time of execution"
	library: "Free implementation of ELKS library"
	status: "See notice at end of class."
	legal: "See notice at end of class."
	date: "$Date: 2019-02-18 11:07:51 +0000 (Mon, 18 Feb 2019) $"
	revision: "$Revision: 102848 $"

class 
	EXECUTION_ENVIRONMENT

create 
	default_create

feature {NONE} -- Initialization

	default_create
			-- Process instances of classes with no creation clause.
			-- (Default: do nothing.)
			-- (from ANY)
		do
		end
	
feature -- Access

	Arguments: ARGUMENTS_32
			-- Arguments that were used to start current execution.
		once
			create Result
		ensure
			instance_free: class
		end

	available_cpu_count: NATURAL_32
			-- Number of available CPUs.
		external
			"C inline use <eif_system.h>"
		alias
			"[
				#ifdef EIF_WINDOWS
					SYSTEM_INFO SysInfo;
					ZeroMemory (&SysInfo, sizeof (SYSTEM_INFO));
					GetSystemInfo (&SysInfo);
					return (EIF_NATURAL_32) SysInfo.dwNumberOfProcessors;
				#elif defined(EIF_MACOSX)
						/* MacOS X < 10.4 */
					int nm [2];
					size_t len = 4;
					uint32_t count;
					nm [0] = CTL_HW; nm [1] = HW_AVAILCPU;
					sysctl (nm, 2, &count, &len, NULL, 0);
					if(count < 1) {
						nm[1] = HW_NCPU;
						sysctl(nm, 2, &count, &len, NULL, 0);
						if (count < 1) {count = 1;}
					}
					return (EIF_NATURAL_32) count;
				#else
						/* Linux, Solaris, AIX, Mac OS X >=10.4 (i.e. Tiger onwards), ... */
					return (EIF_NATURAL_32) sysconf(_SC_NPROCESSORS_ONLN);
				#endif
			]"
		ensure
			instance_free: class
		end

	Command_line: ARGUMENTS
		obsolete "Use `arguments' instead for handling Unicode command lines. [2017-05-31]"
			-- Command line that was used to start current execution
		once
			create Result
		ensure
			instance_free: class
		end

	current_working_directory: STRING_8
		obsolete "Use `current_working_path' instead to support Unicode path. [2017-05-31]"
			-- Directory of current execution.
			-- Execution of this query on concurrent threads will result in
			-- an unspecified behavior.
		local
			l_count, l_nbytes: INTEGER_32
			l_managed: MANAGED_POINTER
		do
			l_count := 50
			create l_managed.make (l_count)
			l_nbytes := eif_dir_current (l_managed.item, l_count)
			if l_nbytes = -1 then
				Result := "."
			else
				if l_nbytes > l_count then
					l_count := l_nbytes;
					l_managed.resize (l_count)
					l_nbytes := eif_dir_current (l_managed.item, l_count)
				end
				if l_nbytes > 0 and l_nbytes <= l_count then
					Result := File_info.pointer_to_file_name_8 (l_managed.item)
				else
					Result := "."
					check
							False
					end
				end
			end
		ensure
			instance_free: class
			result_not_void: Result /= Void
		end

	current_working_path: PATH
			-- Directory of current execution.
		local
			l_count, l_nbytes: INTEGER_32
			l_managed: MANAGED_POINTER
		do
			l_count := 50
			create l_managed.make (l_count)
			l_nbytes := eif_dir_current (l_managed.item, l_count)
			if l_nbytes = -1 then
				create Result.make_from_string (".")
			else
				if l_nbytes > l_count then
					l_count := l_nbytes;
					l_managed.resize (l_count)
					l_nbytes := eif_dir_current (l_managed.item, l_count)
				end
				if l_nbytes > 0 and l_nbytes <= l_count then
					create Result.make_from_pointer (l_managed.item)
				else
					create Result.make_from_string (".")
				end
			end
		ensure
			instance_free: class
			result_not_void: Result /= Void
		end

	Default_shell: STRING_32
			-- Default shell
		once
			if attached item ("SHELL") as l_shell then
				Result := l_shell
			else
				create Result.make_empty
			end
		ensure
			instance_free: class
		end

	generating_type: TYPE [detachable EXECUTION_ENVIRONMENT]
			-- Type of current object
			-- (type of which it is a direct instance)
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			generating_type_not_void: Result /= Void
		end

	generator: STRING_8
			-- Name of current object's generating class
			-- (base class of the type of which it is a direct instance)
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			generator_not_void: Result /= Void
			generator_not_empty: not Result.is_empty
		end

	get (s: STRING_8): detachable STRING_8
		obsolete "Use `item' instead to retrieve Unicode environment variables. [2017-05-31]"
			-- Value of s if it is an environment variable and has been set;
			-- void otherwise.
		require
			s_exists: s /= Void
			not_has_null_character: not s.has ('%U')
		do
			if attached item (s) as l_val then
				Result := l_val.as_string_8
			end
		ensure
			instance_free: class
		end

	Home_directory_name: detachable STRING_8
		obsolete "Use `home_directory_path' instead to support Unicode path. [2017-05-31]"
			-- Directory name corresponding to the home directory.
		require
			home_directory_supported: Operating_environment.home_directory_supported
		local
			l_count, l_nbytes: INTEGER_32
			l_managed: MANAGED_POINTER
		once
			l_count := 50
			create l_managed.make (l_count)
			l_nbytes := eif_home_directory_name_ptr (l_managed.item, l_count)
			if l_nbytes > l_count then
				l_count := l_nbytes;
				l_managed.resize (l_count)
				l_nbytes := eif_home_directory_name_ptr (l_managed.item, l_count)
			end
			if l_nbytes > 0 and l_nbytes <= l_count then
				Result := File_info.pointer_to_file_name_8 (l_managed.item)
			end
		ensure
			instance_free: class
		end

	Home_directory_path: detachable PATH
			-- Directory name corresponding to the home directory.
		require
			home_directory_supported: Operating_environment.home_directory_supported
		local
			l_count, l_nbytes: INTEGER_32
			l_managed: MANAGED_POINTER
		once
			l_count := 50
			create l_managed.make (l_count)
			l_nbytes := eif_home_directory_name_ptr (l_managed.item, l_count)
			if l_nbytes > l_count then
				l_count := l_nbytes;
				l_managed.resize (l_count)
				l_nbytes := eif_home_directory_name_ptr (l_managed.item, l_count)
			end
			if l_nbytes > 0 and l_nbytes <= l_count then
				create Result.make_from_pointer (l_managed.item)
			end
		ensure
			instance_free: class
		end

	item (s: READABLE_STRING_GENERAL): detachable STRING_32
			-- Value of s if it is an environment variable and has been set;
			-- void otherwise.
		require
			s_exists: s /= Void
			not_has_null_character: not s.has ('%U'.to_character_32)
		local
			l_key: NATIVE_STRING
			c_string: POINTER
		do
			create l_key.make (s)
			c_string := eif_getenv (l_key.item)
			if not c_string.is_default_pointer then
				Result := (create {NATIVE_STRING}.make_from_pointer (c_string)).string
			end
		ensure
			instance_free: class
		end

	Root_directory_name: STRING_8
			-- Directory name corresponding to the root directory.
		require
			root_directory_supported: Operating_environment.root_directory_supported
		once
			if {PLATFORM}.is_windows then
				Result := "\"
			elseif {PLATFORM}.is_vms then
				Result := "[000000]"
			else
				Result := "/"
			end
		ensure
			instance_free: class
			result_not_void: Result /= Void
		end

	starting_environment: HASH_TABLE [STRING_32, STRING_32]
			-- Table of environment variables when current process starts,
			-- indexed by variable name
		local
			l_ptr: POINTER
			i: INTEGER_32
			ns: NATIVE_STRING
		do
			create Result.make (40)
			from
				i := 0
				l_ptr := i_th_environ (i)
				create ns.make_empty (0)
			until
				l_ptr.is_default_pointer
			loop
				ns.set_shared_from_pointer (l_ptr)
				if attached separated_variables (ns.string) as l_curr_var then
					Result.force (l_curr_var.value, l_curr_var.key)
				end
				i := i + 1
				l_ptr := i_th_environ (i)
			end
		ensure
			instance_free: class
			result_attached: Result /= Void
		end

	starting_environment_variables: HASH_TABLE [STRING_8, STRING_8]
		obsolete "Use starting_environment which support unicode. [2017-05-31]"
			-- Table of environment variables when current process starts,
			-- indexed by variable name
		local
			l_ptr: POINTER
			i: INTEGER_32
			ns: NATIVE_STRING
		do
			create Result.make (40)
			from
				i := 0
				l_ptr := i_th_environ (i)
				create ns.make_empty (0)
			until
				l_ptr.is_default_pointer
			loop
				ns.set_shared_from_pointer (l_ptr)
				if attached separated_variables (ns.string) as l_curr_var then
					Result.force (l_curr_var.value.as_string_8, l_curr_var.key.as_string_8)
				end
				i := i + 1
				l_ptr := i_th_environ (i)
			end
		ensure
			instance_free: class
			result_attached: Result /= Void
		end

	Temporary_directory_path: detachable PATH
			-- Temporary directory name.
			-- On Windows:  %SystemDrive%\Users\%USERNAME%\AppData\Local\Temp (%USERPROFILE%\AppData\Local\Temp).
			-- On Unix: /tmp and /var/tmp.
			-- On VMS: /sys$scratch	
			-- Otherwise Void	
		local
			l_count, l_nbytes: INTEGER_32
			ns: NATIVE_STRING
		once
			l_count := 10
			create ns.make_empty (l_count)
			l_nbytes := eif_temporary_directory_name_ptr (ns.item, l_count)
			if l_nbytes > l_count then
				l_count := l_nbytes
				create ns.make_empty (l_count)
				l_nbytes := eif_temporary_directory_name_ptr (ns.item, l_count)
			end
			if l_nbytes > 0 and l_nbytes <= l_count then
				create Result.make_from_string (ns.string)
			end
		ensure
			instance_free: class
		end

	User_directory_name: detachable STRING_8
		obsolete "Use `user_directory_path' instead to support Unicode paths. [2017-05-31]"
			-- Directory name corresponding to the user directory
			-- On Windows: C:\Users\manus\Documents
			-- On Unix & Mac: $HOME
			-- Otherwise Void
		local
			l_count, l_nbytes: INTEGER_32
			l_managed: MANAGED_POINTER
		once
			l_count := 50
			create l_managed.make (50)
			l_nbytes := eif_user_directory_name_ptr (l_managed.item, l_count)
			if l_nbytes > l_count then
				l_count := l_nbytes;
				l_managed.resize (l_count)
				l_nbytes := eif_user_directory_name_ptr (l_managed.item, l_count)
			end
			if l_nbytes > 0 and l_nbytes <= l_count then
				Result := File_info.pointer_to_file_name_8 (l_managed.item)
			end
			if Result /= Void and then not Result.is_empty then
			elseif Operating_environment.home_directory_supported and then attached Home_directory_name as l_home then
				Result := l_home
			else
				Result := Void
			end
		ensure
			instance_free: class
		end

	User_directory_path: detachable PATH
			-- Directory name corresponding to the user directory
			-- On Windows: C:\Users\manus\Documents
			-- On Unix & Mac: $HOME
			-- Otherwise Void
		local
			l_count, l_nbytes: INTEGER_32
			l_managed: MANAGED_POINTER
		once
			l_count := 50
			create l_managed.make (50)
			l_nbytes := eif_user_directory_name_ptr (l_managed.item, l_count)
			if l_nbytes > l_count then
				l_count := l_nbytes;
				l_managed.resize (l_count)
				l_nbytes := eif_user_directory_name_ptr (l_managed.item, l_count)
			end
			if l_nbytes > 0 and l_nbytes <= l_count then
				create Result.make_from_pointer (l_managed.item)
			end
			if Result /= Void and then not Result.is_empty then
			elseif Operating_environment.home_directory_supported and then attached Home_directory_path as l_home then
				Result := l_home
			else
				Result := Void
			end
		ensure
			instance_free: class
		end
	
feature {NATIVE_STRING_HANDLER} -- Access

	pointer_length_in_bytes (a_ptr: POINTER): INTEGER_32
			-- Length in bytes of a platform specific file name pointer, not
			-- including the null-terminating character. If size is too large
			-- to fit into an {INTEGER} instance, the size is truncated to
			-- {INTEGER_32}.max_value.
			-- (from NATIVE_STRING_HANDLER)
		require -- from NATIVE_STRING_HANDLER
			a_ptr_not_null: a_ptr /= default_pointer
		local
			l_length: NATURAL_64
		do
			l_length := c_pointer_length_in_bytes (a_ptr)
			if l_length <= {INTEGER_32}.max_value.to_natural_64 then
				Result := l_length.to_integer_32
			else
				Result := {INTEGER_32}.max_value
			end
		end
	
feature -- Comparison

	frozen deep_equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void
			-- or attached to isomorphic object structures?
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.is_deep_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			shallow_implies_deep: standard_equal (a, b) implies Result
			both_or_none_void: (a = Void) implies (Result = (b = Void))
			same_type: (Result and (a /= Void)) implies (b /= Void and then a.same_type (b))
			symmetric: Result implies deep_equal (b, a)
		end

	frozen equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void or attached
			-- to objects considered equal?
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.is_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.is_equal (b))
		end

	frozen is_deep_equal alias "≡≡≡" (other: EXECUTION_ENVIRONMENT): BOOLEAN
			-- Are Current and other attached to isomorphic object structures?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			shallow_implies_deep: standard_is_equal (other) implies Result
			same_type: Result implies same_type (other)
			symmetric: Result implies other.is_deep_equal (Current)
		end

	is_equal (other: EXECUTION_ENVIRONMENT): BOOLEAN
			-- Is other attached to an object considered
			-- equal to current object?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			symmetric: Result implies other ~ Current
			consistent: standard_is_equal (other) implies Result
		end

	frozen standard_equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void or attached to
			-- field-by-field identical objects of the same type?
			-- Always uses default object comparison criterion.
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.standard_is_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.standard_is_equal (b))
		end

	frozen standard_is_equal alias "≜" (other: EXECUTION_ENVIRONMENT): BOOLEAN
			-- Is other attached to an object of the same type
			-- as current object, and field-by-field identical to it?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			same_type: Result implies same_type (other)
			symmetric: Result implies other.standard_is_equal (Current)
		end
	
feature -- Status report

	conforms_to (other: ANY): BOOLEAN
			-- Does type of current object conform to type
			-- of other (as per Eiffel: The Language, chapter 13)?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		end

	same_type (other: ANY): BOOLEAN
			-- Is type of current object identical to type of other?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			definition: Result = (conforms_to (other) and other.conforms_to (Current))
		end
	
feature -- Status setting

	change_working_directory (path: READABLE_STRING_GENERAL)
		obsolete "Use `change_working_path' instead to support Unicode path. [2017-05-31]"
			-- Set the current directory to path
		local
			l_ptr: MANAGED_POINTER
		do
			l_ptr := File_info.file_name_to_pointer (path, Void)
			return_code := eif_chdir (l_ptr.item)
		end

	change_working_path (path: PATH)
			-- Set the current directory to path
		local
			l_ptr: MANAGED_POINTER
		do
			l_ptr := path.to_pointer
			return_code := eif_chdir (l_ptr.item)
		end

	launch (s: READABLE_STRING_GENERAL)
			-- Pass to the operating system an asynchronous request to
			-- execute s interpreted as a Unicode string.
			-- If s is empty, use the default shell as command.
		require
			s_not_void: s /= Void
		local
			l_cstr: NATIVE_STRING
		do
			if s.is_empty then
				create l_cstr.make (Default_shell)
			else
				create l_cstr.make (s)
			end
			asynchronous_system_call (l_cstr.item)
		ensure
			instance_free: class
		end

	put (value, key: READABLE_STRING_GENERAL)
			-- Set the environment variable key to value treating both
			-- value and key as Unicode characters.
		require
			key_exists: key /= Void
			key_meaningful: not key.is_empty
			not_key_has_null_character: not key.has ('%U'.to_character_32)
			value_exists: value /= Void
			not_value_has_null_character: not value.has ('%U'.to_character_32)
		local
			l_env: STRING_32
			l_c_env: NATIVE_STRING
		do
			create l_env.make (value.count + key.count + 1);
			l_env.append_string_general (key);
			l_env.append_character ('='.to_character_32);
			l_env.append_string_general (value)
			create l_c_env.make (l_env);
			Environ.force (l_c_env, create {IMMUTABLE_STRING_32}.make_from_string_general (key))
			return_code := eif_putenv (l_c_env.item)
		ensure
			variable_set: return_code = 0 implies ((value.is_empty and then item (key) = Void) or else not value.is_empty and then attached item (key) as k and then k.same_string_general (value))
		end

	sleep (nanoseconds: INTEGER_64)
			-- Suspend thread execution for interval specified in
			-- nanoseconds (1 nanosecond = 10^(-9) second).
		require
			non_negative_nanoseconds: nanoseconds >= 0
		do
			eif_sleep (nanoseconds)
		ensure
			instance_free: class
		end

	system (s: READABLE_STRING_GENERAL)
			-- Pass to the operating system a request to execute s interpreted as a Unicode string.
			-- If s is empty, use the default shell as command.
		require
			s_exists: s /= Void
		local
			l_cstr: NATIVE_STRING
		do
			if s.is_empty then
				create l_cstr.make (Default_shell)
			else
				create l_cstr.make (s)
			end
			return_code := system_call (l_cstr.item)
		end
	
feature -- Duplication

	frozen clone (other: detachable ANY): like other
		obsolete "Use `twin' instead. [2017-05-31]"
			-- Void if other is void; otherwise new object
			-- equal to other
			--
			-- For non-void other, clone calls copy;
			-- to change copying/cloning semantics, redefine copy.
			-- (from ANY)
		do
			if other /= Void then
				Result := other.twin
			end
		ensure -- from ANY
			instance_free: class
			equal: Result ~ other
		end

	copy (other: EXECUTION_ENVIRONMENT)
			-- Update current object using fields of object attached
			-- to other, so as to yield equal objects.
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
			type_identity: same_type (other)
		external
			"built_in"
		ensure -- from ANY
			is_equal: Current ~ other
		end

	frozen deep_clone (other: detachable ANY): like other
		obsolete "Use `deep_twin' instead. [2017-05-31]"
			-- Void if other is void: otherwise, new object structure
			-- recursively duplicated from the one attached to other
			-- (from ANY)
		do
			if other /= Void then
				Result := other.deep_twin
			end
		ensure -- from ANY
			instance_free: class
			deep_equal: deep_equal (other, Result)
		end

	frozen deep_copy (other: EXECUTION_ENVIRONMENT)
			-- Effect equivalent to that of:
			--		copy (other . deep_twin)
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		do
			copy (other.deep_twin)
		ensure -- from ANY
			deep_equal: deep_equal (Current, other)
		end

	frozen deep_twin: EXECUTION_ENVIRONMENT
			-- New object structure recursively duplicated from Current.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			deep_twin_not_void: Result /= Void
			deep_equal: deep_equal (Current, Result)
		end

	frozen standard_clone (other: detachable ANY): like other
		obsolete "Use `standard_twin' instead. [2017-05-31]"
			-- Void if other is void; otherwise new object
			-- field-by-field identical to other.
			-- Always uses default copying semantics.
			-- (from ANY)
		do
			if other /= Void then
				Result := other.standard_twin
			end
		ensure -- from ANY
			instance_free: class
			equal: standard_equal (Result, other)
		end

	frozen standard_copy (other: EXECUTION_ENVIRONMENT)
			-- Copy every field of other onto corresponding field
			-- of current object.
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
			type_identity: same_type (other)
		external
			"built_in"
		ensure -- from ANY
			is_standard_equal: standard_is_equal (other)
		end

	frozen standard_twin: EXECUTION_ENVIRONMENT
			-- New object field-by-field identical to other.
			-- Always uses default copying semantics.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			standard_twin_not_void: Result /= Void
			equal: standard_equal (Result, Current)
		end

	frozen twin: EXECUTION_ENVIRONMENT
			-- New object equal to Current
			-- twin calls copy; to change copying/twinning semantics, redefine copy.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			twin_not_void: Result /= Void
			is_equal: Result ~ Current
		end
	
feature -- Basic operations

	frozen as_attached: attached EXECUTION_ENVIRONMENT
		obsolete "Remove calls to this feature. [2017-05-31]"
			-- Attached version of Current.
			-- (Can be used during transitional period to convert
			-- non-void-safe classes to void-safe ones.)
			-- (from ANY)
		do
			Result := Current
		end

	frozen default: detachable EXECUTION_ENVIRONMENT
			-- Default value of object's type
			-- (from ANY)
		do
		end

	frozen default_pointer: POINTER
			-- Default value of type POINTER
			-- (Avoid the need to write p.default for
			-- some p of type POINTER.)
			-- (from ANY)
		do
		ensure -- from ANY
			instance_free: class
		end

	default_rescue
			-- Process exception for routines with no Rescue clause.
			-- (Default: do nothing.)
			-- (from ANY)
		do
		end

	frozen do_nothing
			-- Execute a null action.
			-- (from ANY)
		do
		ensure -- from ANY
			instance_free: class
		end
	
feature {NONE} -- Implementation

	c_pointer_length_in_bytes (a_ptr: POINTER): NATURAL_64
			-- Length in bytes of a platform specific file name pointer, not
			-- including the null-terminating character.
			-- (from NATIVE_STRING_HANDLER)
		require -- from NATIVE_STRING_HANDLER
			a_ptr_not_null: a_ptr /= default_pointer
		external
			"C inline use %"eif_eiffel.h%""
		alias
			"{
			#ifdef EIF_WINDOWS
				return (EIF_NATURAL_64) wcslen($a_ptr) * sizeof(wchar_t);
			#else
				return (EIF_NATURAL_64) strlen($a_ptr) * sizeof(char);
			#endif
			}"
		end

	Environ: HASH_TABLE [NATIVE_STRING, IMMUTABLE_STRING_32]
			-- Environment variable memory set by current execution,
			-- indexed by environment variable name. Needed otherwise
			-- we would corrupt memory after freeing memory used by
			-- NATIVE_STRING instance since not referenced anywhere else.
		once
			create Result.make (10)
		end

	File_info: FILE_INFO
		obsolete "Remove when all obsolete routines using it will be removed.  [2017-05-31]"
			-- Platform specific helper of filenames.
		once
			create Result.make
		ensure
			instance_free: class
		end

	i_th_environ (i: INTEGER_32): POINTER
			-- Environment variable at i-th position of eif_environ.
		require
			i_valid: i >= 0
		external
			"C inline use <string.h>"
		alias
			"[
				if (eif_environ) {
					#ifdef EIF_WINDOWS
						EIF_NATIVE_CHAR *vars = (EIF_NATIVE_CHAR *) eif_environ;
						int cnt = 0;
						for (; *vars; vars++) {
						   if ($i==cnt) return vars;
						   while (*vars) { vars++; }
						   cnt++;
						}
						return NULL;
					#else
						return ((EIF_NATIVE_CHAR **)eif_environ)[$i];
					#endif
				} else {
					return NULL;
				}
			]"
		ensure
			instance_free: class
		end

	separated_variables (a_var: STRING_32): detachable TUPLE [value: STRING_32; key: STRING_32]
			-- Given an environment variable a_var in form of "key=value",
			-- return separated key and value.
			-- Return Void if a_var is in incorrect format.
		require
			a_var_attached: a_var /= Void
		local
			i, j: INTEGER_32
			done: BOOLEAN
		do
			j := a_var.count
			from
				i := 1
			until
				i > j or done
			loop
				if a_var.item (i) = '='.to_character_32 then
					done := True
				else
					i := i + 1
				end
			end
			if i > 1 and then i < j then
				Result := [a_var.substring (i + 1, j), a_var.substring (1, i - 1)]
			end
		ensure
			instance_free: class
		end
	
feature {NONE} -- External

	asynchronous_system_call (s: POINTER)
			-- Pass to the operating system an asynchronous request to execute s.
		external
			"C blocking use %"eif_misc.h%""
		alias
			"eif_system_asynchronous"
		end

	eif_chdir (path: POINTER): INTEGER_32
			-- Set the current directory to path
		external
			"C signature (EIF_FILENAME): EIF_INTEGER use %"eif_dir.h%""
		end

	eif_dir_current (a_ptr: POINTER; a_count: INTEGER_32): INTEGER_32
			-- Store platform specific path of current working directory in a_ptr with a_count bytes. If
			-- there is a need for more bytes than a_count, or if a_ptr is the default_pointer, nothing is done with a_ptr.
			-- We always return the number of bytes required including the null-terminating character, or -1 on error.
		external
			"C signature (EIF_FILENAME, EIF_INTEGER): EIF_INTEGER use %"eif_dir.h%""
		end

	eif_getenv (s: POINTER): POINTER
			-- Value of environment variable s
		external
			"C inline use <stdlib.h>"
		alias
			"[
				#ifdef EIF_WINDOWS
					return _wgetenv ((EIF_NATIVE_CHAR *) $s);
				#else
					return getenv ((EIF_NATIVE_CHAR *) $s);
				#endif
			]"
		end

	eif_home_directory_name_ptr (a_ptr: POINTER; a_count: INTEGER_32): INTEGER_32
			-- Stored directory name corresponding to the home directory in a_ptr with a_count bytes. If
			-- there is a need for more bytes than a_count, or if a_ptr is the default_pointer, nothing is done with a_ptr.
			-- We always return the number of bytes required including the null-terminating character.
		external
			"C signature (EIF_FILENAME, EIF_INTEGER): EIF_INTEGER use %"eif_path_name.h%""
		end

	eif_putenv (v: POINTER): INTEGER_32
			-- Set v in environment.
		external
			"C inline use <stdlib.h>"
		alias
			"[
				#ifdef EIF_WINDOWS
					return _wputenv ((EIF_NATIVE_CHAR *) $v);
				#else
					return putenv ((EIF_NATIVE_CHAR *) $v);
				#endif
			]"
		end

	eif_sleep (nanoseconds: INTEGER_64)
			-- Suspend thread execution for interval specified in
			-- nanoseconds (1 nanosecond = 10^(-9) second).
		require
			non_negative_nanoseconds: nanoseconds >= 0
		external
			"C blocking use %"eif_misc.h%""
		ensure
			instance_free: class
		end

	eif_temporary_directory_name_ptr (a_ptr: POINTER; a_count: INTEGER_32): INTEGER_32
			-- Stored directory name corresponding to the temporary directory in a_ptr with a_count bytes.
			-- If there is a need for more bytes than a_count, or if a_ptr is the default_pointer,
			-- nothing is done with a_ptr.
			-- We always return the number of bytes required including the null-terminating character.
		external
			"C signature (EIF_FILENAME, EIF_INTEGER): EIF_INTEGER use %"eif_path_name.h%""
		end

	eif_user_directory_name_ptr (a_buffer: POINTER; a_count: INTEGER_32): INTEGER_32
			-- Directory name corresponding to the user directory that will be stored in buffer a_buffer
			-- of size a_count bytes. Returns the number of bytes necessary in a_buffer to get the full copy.
		external
			"C signature (EIF_FILENAME, EIF_INTEGER): EIF_INTEGER use %"eif_path_name.h%""
		end

	system_call (s: POINTER): INTEGER_32
			-- Pass to the operating system a request to execute s.
		external
			"C blocking use %"eif_misc.h%""
		alias
			"eif_system"
		end
	
feature -- Output

	Io: STD_FILES
			-- Handle to standard file setup
			-- (from ANY)
		once
			create Result;
			Result.set_output_default
		ensure -- from ANY
			instance_free: class
			io_not_void: Result /= Void
		end

	out: STRING_8
			-- New string containing terse printable representation
			-- of current object
			-- (from ANY)
		do
			Result := tagged_out
		ensure -- from ANY
			out_not_void: Result /= Void
		end

	print (o: detachable ANY)
			-- Write terse external representation of o
			-- on standard output.
			-- (from ANY)
		local
			s: READABLE_STRING_8
		do
			if attached o then
				s := o.out
				if attached {READABLE_STRING_32} s as s32 then
					Io.put_string_32 (s32)
				elseif attached {READABLE_STRING_8} s as s8 then
					Io.put_string (s8)
				else
					Io.put_string_32 (s.as_string_32)
				end
			end
		ensure -- from ANY
			instance_free: class
		end

	frozen tagged_out: STRING_8
			-- New string containing terse printable representation
			-- of current object
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			tagged_out_not_void: Result /= Void
		end
	
feature -- Platform

	Operating_environment: OPERATING_ENVIRONMENT
			-- Objects available from the operating system
			-- (from ANY)
		once
			create Result
		ensure -- from ANY
			instance_free: class
			operating_environment_not_void: Result /= Void
		end
	
feature {NONE} -- Retrieval

	frozen internal_correct_mismatch
			-- Called from runtime to perform a proper dynamic dispatch on correct_mismatch
			-- from MISMATCH_CORRECTOR.
			-- (from ANY)
		local
			l_msg: STRING_32
			l_exc: EXCEPTIONS
		do
			if attached {MISMATCH_CORRECTOR} Current as l_corrector then
				l_corrector.correct_mismatch
			else
				create l_msg.make_from_string ("Mismatch: ".as_string_32)
				create l_exc;
				l_msg.append (generating_type.name_32);
				l_exc.raise_retrieval_exception (l_msg)
			end
		end
	
feature -- Status

	return_code: INTEGER_32
			-- Status code set by last call to system or put
	
invariant
		-- from ANY
	reflexive_equality: standard_is_equal (Current)
	reflexive_conformance: conforms_to (Current)

note
	copyright: "Copyright (c) 1984-2019, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
		Eiffel Software
		5949 Hollister Ave., Goleta, CA 93117 USA
		Telephone 805-685-1006, Fax 805-685-6869
		Website http://www.eiffel.com
		Customer support http://support.eiffel.com
	]"

end -- class EXECUTION_ENVIRONMENT

Generated by ISE EiffelStudio