note
	description: "Argument parser for all classes compilation tool."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date$"
	revision: "$Revision$"

class
	ARGUMENT_PARSER

inherit
	ARGUMENT_OPTION_PARSER
		rename
			make as make_option_parser
		redefine
			new_argument_source
		end

create
	make

feature {NONE} -- Initialization

	make
			-- Initialize the argument parser
		do
			make_option_parser (False)
			set_is_using_separated_switch_values (True)
		end

feature {NONE} -- Factory

	new_argument_source: ARGUMENT_SOURCE
			-- Creates a new default argument source object for the parser,
			-- in order to include value from potential `ISE_COMPILE_ALL_FLAGS` environment variable.
		do
			create {ENVIRONMENT_ARGUMENTS_SOURCE} Result.make (create {COMPILE_ALL_ARGUMENTS})
		end

feature {NONE} -- Access

	name: STRING_32 = "Compile-All Tool"
			-- Application name

	version: STRING_32
			-- Application version
		once
			create Result.make (5)
			Result.append_integer ({EIFFEL_CONSTANTS}.major_version)
			Result.append_character ('.')
			Result.append ((create {EIFFEL_CONSTANTS}).two_digit_minimum_minor_version)
		end

	copyright: IMMUTABLE_STRING_32
			-- <Precursor>
		once
			Result := {STRING_32} "Copyright Eiffel Software 2006-" + {EIFFEL_ENV}.copyright_year + ". All Rights Reserved."
		end

	switches: ARRAYED_LIST [ARGUMENT_SWITCH]
			-- Argument switches
		once
			create Result.make (9)
			Result.extend (create {ARGUMENT_DIRECTORY_SWITCH}.make (location_switch, "Directory where to look for configuration files.", True, False, "directory", "A directory to look for ecf files", False))
			Result.extend (create {ARGUMENT_DIRECTORY_SWITCH}.make (compdir_switch, "Directory where projects will be compiled.", True, False, "directory", "A directory where the projects will be compiled", False))
			Result.extend (create {ARGUMENT_DIRECTORY_SWITCH}.make (eifgen_switch, "Obsolete: see %"" + compdir_switch  + "%" option.", True, False, "directory", "...", False))
			Result.extend (create {ARGUMENT_DIRECTORY_SWITCH}.make (logdir_switch, "Directory where logs will be stored (if verbose logging is enabled).", True, False, "directory", "A directory where the logs will be stored", False))
			Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (ignore_switch, "Ignore file with files/targets to ignore.", True, False, "ignore.ini", "INI file with the ignores.", False))
			Result.extend (create {ARGUMENT_SWITCH}.make (log_verbose_switch, "Verbose logging of actions?", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (list_failures_switch, "Display a list of failed compilation(s) with associated log filename if available.", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (ecb_switch, "Use ecb instead of ec?", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (experiment_switch, "Use experimental library during compilation?", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (compatible_switch, "Use compatible library during compilation?", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (c_compile_switch, "Compile generated C code?", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (melt_switch, "Melt the project?", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (freeze_switch, "Freeze the project?", True, False))
			Result.extend (create {ARGUMENT_SWITCH}.make (finalize_switch, "Finalize the project?", True, False))

			Result.extend (create {ARGUMENT_SWITCH}.make (clean_switch, "Clean before compilation?", True, False))
			Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (keep_switch, "Keep EIFGENs related data after compilation? (by default they are removed)", True, False, "status", "{all | passed | failed}", True))

			Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (options_switch, "Comma separated option(s)", True, True, "key=value", "dotnet=(true|false),platform=(unix|windows|macintosh|vxworks)%N...", False))
			Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (interface_switch, "Comma separated option(s) to customize the output", True, True,
						"key=value",
						"for instance key %"template%": using any of #action, #target, #uuid, #system, #ecf , #absolute_ecf variables %N...", False))
		end

feature -- Status Report

	use_directory_location: BOOLEAN
			-- Indicates if `location' represents a directory.
		once
			Result := (create {RAW_FILE}.make_with_path (location)).is_directory
		end

feature -- Access

	location: PATH
			-- Location of files to use
		once
			if attached option_of_name (location_switch) as o then
				create Result.make_from_string (o.value)
			else
				Result := {EXECUTION_ENVIRONMENT}.current_working_path
			end
		ensure
			location_not_void: Result /= Void
			location_not_empty: not Result.is_empty
		end

	compilation_dir: detachable PATH
			-- Location where the projects are compiled.
		once
			if attached option_of_name (eifgen_switch) as l_option then
				create Result.make_from_string (l_option.value)
			elseif attached option_of_name (compdir_switch) as l_option then
				create Result.make_from_string (l_option.value)
			end
		end

	logs_dir: detachable PATH
			-- Location where the logs are stored.
		once
			if attached option_of_name (logdir_switch) as l_option then
				create Result.make_from_string (l_option.value)
			end
		end

	ignore: detachable IMMUTABLE_STRING_32
			-- File with the ignores.
		once
			if attached option_of_name (ignore_switch) as o then
				Result := o.value
			end
		end

	is_ecb: BOOLEAN
		once
			Result := has_option (ecb_switch)
		end

	is_experiment: BOOLEAN
			-- Use experimental library?
		once
			Result := has_option (experiment_switch)
		end

	is_compatible: BOOLEAN
			-- Use experimental library?
		once
			Result := has_option (compatible_switch)
		end

	is_parse_only: BOOLEAN
			-- Only parse and check dependencies?
		once
			Result := not is_melt and not is_freeze and not is_finalize
		end

	is_log_verbose: BOOLEAN
			-- Log verbose status information?
		once
			Result := has_option (log_verbose_switch)
		end

	is_clean: BOOLEAN
			-- Clean before compilation?
		once
			Result := has_option (clean_switch)
		end

	has_keep: BOOLEAN
			-- Keep EIFGENs after compilation?
			--| By default: compilation data is removed after related compilation(s)
			--| if we melt+freeze+finalize then
			--| the data are removed only after the last compilation made on the same target
		once
			Result := has_option (keep_switch)
		end

	has_keep_all: BOOLEAN
			-- Keep EIFGENs after any compilation?
		once
			Result :=
				attached option_of_name (keep_switch) as o and then
				((attached o.value as v and then not v.is_empty) implies v.is_case_insensitive_equal ("all"))
		end

	has_keep_failed: BOOLEAN
			-- Keep EIFGENs after Failed compilation?
		once
			Result :=
				attached option_of_name (keep_switch) as o and then
				attached o.value as v and then
				v.is_case_insensitive_equal ("failed")
		end

	has_keep_passed: BOOLEAN
			-- Keep EIFGENs after Passed compilation?
		once
			Result :=
				attached option_of_name (keep_switch) as o and then
				attached o.value as v and then
				v.is_case_insensitive_equal ("passed")
		end

	is_c_compile: BOOLEAN
			-- Compile generated C code?
		once
			Result := has_option (c_compile_switch)
		end

	is_melt: BOOLEAN
			-- Melt the project?
		once
			Result := has_option (melt_switch)
		end

	is_freeze: BOOLEAN
			-- Freeze the project?
		once
			Result := has_option (freeze_switch)
		end

	is_finalize: BOOLEAN
			-- Finalize the project?
		once
			Result := has_option (finalize_switch)
		end

	list_failures: BOOLEAN
			-- Finalize the project?
		once
			Result := has_option (list_failures_switch)
		end

feature -- Access: -interface

	interface_output_action_template: detachable IMMUTABLE_STRING_32
			-- Template for output action
		once
			Result := interface_item ("template")
		end

	interface_text (m: READABLE_STRING_32): IMMUTABLE_STRING_32
			-- Value for -options text.`m'=value
		do
			Result := interface_item ({STRING_32} "text." + m)
			if not attached Result then
				create Result.make_from_string (m)
			end
		end

feature -- Access: -options		

	skip_dotnet: BOOLEAN
			-- Skip dotnet target?
		once
			Result := options_has_false ("dotnet")
		end

	platform_option: IMMUTABLE_STRING_32
			-- `platform' compiler option for any action.
		once
			Result := options_item ("platform")
			if not attached Result then
				create Result.make_empty
			elseif not Result.is_empty and then Result.item (Result.count) = '!' then
				Result := Result.head (Result.count - 1)
			end
		end

	is_platform_exclusive: BOOLEAN
			-- If `platform' option exclusive? That is to say, only ECF that specifies the platform
			-- will be compiled?
		once
			Result := attached options_item ("platform") as l_opt and then
				not l_opt.is_empty and then l_opt.item (l_opt.count) = '!'
		end

	ec_options: IMMUTABLE_STRING_32
			-- 'ec' compiler option for any action
		once
			Result := options_item ("ec")
			if not attached Result then
				create Result.make_empty
			end
		end

	melt_ec_options: IMMUTABLE_STRING_32
			-- 'ec' compiler option when melting
		once
			Result := options_item ("ec.melt")
			if not attached Result then
				create Result.make_empty
			end
		end

	freeze_ec_options: IMMUTABLE_STRING_32
			-- 'ec' compiler option when freezing
		once
			Result := options_item ("ec.freeze")
			if not attached Result then
				create Result.make_empty
			end
		end

	finalize_ec_options: IMMUTABLE_STRING_32
			-- 'ec' compiler option when finalizing
		once
			Result := options_item ("ec.finalize")
			if not attached Result then
				create Result.make_empty
			end
		end

feature {NONE} -- Implementation: -interface	

	interface_item (a_name: READABLE_STRING_GENERAL): detachable IMMUTABLE_STRING_32
		do
			Result := interface_options.item (a_name)
		end

	interface_options: STRING_TABLE [IMMUTABLE_STRING_32]
		once
			Result := concatenated_multiple_options (interface_switch, ',')
		end

feature {NONE} -- Implementation: -options		

	options_has_true (a_name: READABLE_STRING_GENERAL): BOOLEAN
		do
			if attached options_item (a_name) as v then
				Result := v.is_case_insensitive_equal ("true")
			end
		end

	options_has_false (a_name: READABLE_STRING_GENERAL): BOOLEAN
		do
			if attached options_item (a_name) as v then
				Result := v.is_case_insensitive_equal ("false")
			end
		end

	options_item (a_name: READABLE_STRING_GENERAL): detachable IMMUTABLE_STRING_32
		do
			Result := options.item (a_name)
		end

	options: STRING_TABLE [IMMUTABLE_STRING_32]
		once
			Result := concatenated_multiple_options (options_switch, ',')
		end

feature {NONE} -- Concatenated value for multiple switch		

	concatenated_multiple_options (a_switch: READABLE_STRING_GENERAL; a_separator: CHARACTER): STRING_TABLE [IMMUTABLE_STRING_32]
			-- Table of options related to multiple option
		local
			sep: CHARACTER_32
			s,k,v: STRING_32
			p: INTEGER
		do
			if
				has_option (a_switch) and then
			 	attached options_of_name (a_switch) as lst and then
			 	not lst.is_empty
			then
				create Result.make_caseless (lst.count)
				Result.compare_objects
				across
					lst as lst_cursor
				loop
					if lst_cursor.item.has_value then
						s := lst_cursor.item.value
						if not s.is_empty then
								-- If first character is not alpha character, let's take it for separator
							sep := s.item (1)
							if sep.is_alpha then
								sep := a_separator
							else
								s := s.substring (2, s.count)
							end
							across
								s.split (sep) as c
							loop
								s := c.item
								s.left_adjust
								p := s.index_of ('=', 1)
								if p > 0 then
									k := s.substring (1, p - 1)
									k.right_adjust
									v := s.substring (p + 1, s.count)
									if
										not v.is_empty and then
										v.item (1) = '"' and then
										v.item (v.count) = '"'
									then
										v := v.substring (2, v.count - 1)
									end
									Result.force (v, k)
								else
									Result.force ("true", s)
								end
							end
						end
					end
				end
			else
				create Result.make (0)
			end
		end

feature {NONE} -- Switch names

	location_switch: STRING = "l"
	eifgen_switch: STRING = "eifgen"
	compdir_switch: STRING = "compdir"
	logdir_switch: STRING = "logdir"
	experiment_switch: STRING = "experiment"
	compatible_switch: STRING = "compat"
	ignore_switch: STRING = "ignore"
	log_verbose_switch: STRING = "log_verbose"
	ecb_switch: STRING = "ecb"
	clean_switch: STRING = "clean"
	keep_switch: STRING = "keep"
	c_compile_switch: STRING = "c_compile"
	melt_switch: STRING = "melt"
	freeze_switch: STRING = "freeze"
	finalize_switch: STRING = "finalize"
	options_switch: STRING = "options"
	interface_switch: STRING = "interface"
	list_failures_switch: STRING = "list_failures"
	;

note
	copyright:	"Copyright (c) 1984-2020, Eiffel Software"
	license:	"GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
	licensing_options:	"http://www.eiffel.com/licensing"
	copying: "[
			This file is part of Eiffel Software's Eiffel Development Environment.
			
			Eiffel Software's Eiffel Development Environment is free
			software; you can redistribute it and/or modify it under
			the terms of the GNU General Public License as published
			by the Free Software Foundation, version 2 of the License
			(available at the URL listed under "license" above).
			
			Eiffel Software's Eiffel Development Environment is
			distributed in the hope that it will be useful, but
			WITHOUT ANY WARRANTY; without even the implied warranty
			of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
			See the GNU General Public License for more details.
			
			You should have received a copy of the GNU General Public
			License along with Eiffel Software's Eiffel Development
			Environment; if not, write to the Free Software Foundation,
			Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
		]"
	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