note
	description: "[
		Objects that provide settings for executing an EQA_TEST_SET. A settings conists of an
		key-value pair of type {STRING}.
		The settings are once per thread, meaning that any EQA_ENVIRONMENT instances will have
		the same state if they are accessed in the same thread.
	]"
	author: ""
	date: "$Date: 2017-05-03 14:51:35 +0000 (Wed, 03 May 2017) $"
	revision: "$Revision: 100315 $"

class 
	EQA_ENVIRONMENT

create 
	default_create

feature -- Access

	item (a_key: READABLE_STRING_GENERAL): detachable IMMUTABLE_STRING_32
			-- Retrieve setting for given key
			--
			-- a_key: Key for which setting should be returned.
			-- Result: Value associated with a_key.
		require
			a_key_attached: a_key /= Void
		do
			Table.search (a_key)
			if Table.found then
				Result := Table.found_item
			end
		end

	item_attached (a_key: READABLE_STRING_GENERAL; an_asserter: EQA_ASSERTIONS): IMMUTABLE_STRING_32
			-- Retrieve setting for given key or rise exception if no value for given key has been defined.
			--
			-- a_key: Key for which setting should be returned.
			-- an_asserter: Asserter in which exceptions are raised if value could not be retrieved.
			-- Result: Value associated with a_key.
		require
			a_key_attached: a_key /= Void
			an_asserter_attached: an_asserter /= Void
		do
			if attached item (a_key) as l_v then
				Result := l_v
			else
				an_asserter.assert (a_key + " not defined", False)
				create Result.make_empty
			end
		ensure
			result_attached: Result /= Void
		end

	item_not_empty (a_key: READABLE_STRING_GENERAL; an_asserter: EQA_ASSERTIONS): IMMUTABLE_STRING_32
			-- Retrieve setting for given key or rise exception if no value for given key has been defined
			-- or the value defined is empty.
			--
			-- a_key: Key for which setting should be returned.
			-- an_asserter: Asserter in which exceptions are raised if value could not be retrieved.
			-- Result: Non-empty value associated with a_key.
		require
			a_key_attached: a_key /= Void
			an_asserter_attached: an_asserter /= Void
		do
			Result := item_attached (a_key, an_asserter)
			an_asserter.assert (a_key + " is empty", not Result.is_empty)
		end
	
feature -- Access: obsolete

	get (a_key: READABLE_STRING_GENERAL): detachable IMMUTABLE_STRING_8
		obsolete "Use `item` [2017-05-31]"
			-- Retrieve setting for given key
			--
			-- a_key: Key for which setting should be returned.
			-- Result: Value associated with a_key..
		require
			a_key_attached: a_key /= Void
		do
			if attached item (a_key) as v then
				create Result.make_from_string (v.as_string_8)
			end
		end

	get_attached (a_key: READABLE_STRING_GENERAL; an_asserter: EQA_ASSERTIONS): IMMUTABLE_STRING_8
		obsolete "Use `item_attached` [2017-05-31]"
			-- Retrieve setting for given key or rise exception if no value for given key has been defined.
			--
			-- a_key: Key for which setting should be returned.
			-- an_asserter: Asserter in which exceptions are raised if value could not be retrieved.
			-- Result: Value associated with a_key.
		require
			a_key_attached: a_key /= Void
			an_asserter_attached: an_asserter /= Void
		do
			create Result.make_from_string (item_attached (a_key, an_asserter).as_string_8)
		ensure
			result_attached: Result /= Void
		end

	get_not_empty (a_key: READABLE_STRING_GENERAL; an_asserter: EQA_ASSERTIONS): IMMUTABLE_STRING_8
		obsolete "Use `item_not_empty` [2017-05-31]"
			-- Retrieve setting for given key or rise exception if no value for given key has been defined
			-- or the value defined is empty.
			--
			-- a_key: Key for which setting should be returned.
			-- an_asserter: Asserter in which exceptions are raised if value could not be retrieved.
			-- Result: Non-empty value associated with a_key.
		require
			a_key_attached: a_key /= Void
			an_asserter_attached: an_asserter /= Void
		do
			create Result.make_from_string (item_not_empty (a_key, an_asserter).as_string_8)
		end
	
feature {NONE} -- Access

	Table: STRING_TABLE [IMMUTABLE_STRING_32]
			-- Table in which settings are stored.
		once
			create Result.make (Default_table_size)
		end
	
feature -- Status setting

	put (a_value: READABLE_STRING_GENERAL; a_key: READABLE_STRING_GENERAL)
			-- Set the value for a given key.
			--
			-- a_value: Value for new setting.
			-- a_key: Key for new setting.
		require
			a_value_attached: a_value /= Void
			a_key_attached: a_key /= Void
		local
			l_ivalue: IMMUTABLE_STRING_32
		do
			if attached {IMMUTABLE_STRING_32} a_value as l_v then
				l_ivalue := l_v
			else
				create l_ivalue.make_from_string_general (a_value)
			end
			Table.force (l_ivalue, a_key)
		ensure
			set: attached item (a_key) as l_value and then a_value.same_string (l_value)
		end
	
feature {EQA_EVALUATOR} -- Status setting

	reset
			-- Reset all settings.
		do
			Table.wipe_out
		end
	
feature {NONE} -- Query

	is_identifier_char (c: CHARACTER_32): BOOLEAN
			-- Is c an identifier character?
		do
			Result := (c >= 'A'.to_character_32 and c <= 'Z'.to_character_32) or (c >= 'a'.to_character_32 and c <= 'z'.to_character_32) or (c >= '0'.to_character_32 and c <= '9'.to_character_32) or (c = '_'.to_character_32)
		end
	
feature -- Basic operations

	substitute_recursive (a_line: READABLE_STRING_GENERAL): STRING_32
			-- Call substitute recursively util no '$' found anymore
		require
			not_void: a_line /= Void
		local
			l_temp: STRING_32
			l_stop: BOOLEAN
		do
			from
				create Result.make_from_string_general (a_line)
			until
				not Result.has ('$'.to_character_32) or l_stop
			loop
				l_temp := substitute (Result)
				if l_temp.same_string (Result) then
					l_stop := True
				else
					l_stop := False
					Result := l_temp
				end
			end
		ensure
			not_void: Result /= Void
		end

	substitute (a_line: READABLE_STRING_GENERAL): STRING_32
			-- line with all environment variables replaced
			-- by their values (or left alone if not in
			-- environment)
		require
			line_not_void: a_line /= Void
		local
			k, l_count, l_start: INTEGER_32
			c: CHARACTER_32
			l_word: READABLE_STRING_GENERAL
			l_subst_started, l_in_group: BOOLEAN
		do
			create Result.make (a_line.count)
			from
				l_count := a_line.count
				k := 1
			until
				k > l_count
			loop
				c := a_line.item (k)
				if c = Substitute_char then
					if l_subst_started then
						l_subst_started := False
						Result.extend (c)
					else
						l_subst_started := True
					end
				elseif l_subst_started then
					if c = Left_group_char then
						l_in_group := True
					else
						from
							l_start := k
						until
							k > l_count or not is_identifier_char (a_line.item (k))
						loop
							k := k + 1
						end
						k := k - 1
						l_word := a_line.substring (l_start, k)
						if attached item (l_word) as l_replacement then
							Result.append (l_replacement)
						else
							Result.extend (Substitute_char)
							Result.append_string_general (l_word)
						end
						if l_in_group then
							l_in_group := False
							k := k + 1
						end
						l_subst_started := False
					end
				else
					Result.extend (c)
				end
				k := k + 1
			end
			if l_subst_started then
				Result.extend (c)
			end
		end
	
feature {NONE} -- Constants

	Default_table_size: INTEGER_32 = 10
			-- Default number of settings stored in Table

	Substitute_char: CHARACTER_32 = '$'
			-- Character which triggers environment variable
			-- substitution

	Left_group_char: CHARACTER_32 = '('

	Right_group_char: CHARACTER_32 = ')'
			-- Characters which are used for setting environment
			-- variable name off from surrounding text
	
note
	copyright: "Copyright (c) 1984-2017, 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 EQA_ENVIRONMENT

Generated by ISE EiffelStudio