------------------------------------------------------------------------------
--                                                                          --
--                          GNATMETRIC COMPONENTS                           --
--                                                                          --
--  A S I S _ U L . E N V I R O N M E N T . S C A N _ P A R A M E T E R S   --
--                                                                          --
--            (adapted for gnatmetric from ASIS Utility Library)            --
--                                 B o d y                                  --
--                                                                          --
--                                                                          --
--                     Copyright (C) 2009-2011, AdaCore                     --
--                                                                          --
-- GNAT Metrics Toolset  is free software;  you can  redistribute it and/or --
-- modify it under terms of the  GNU General Public License as published by --
-- the Free Software Foundation;  either version 2, or (at your option) any --
-- later version.  GNAT Metrics Toolset is  distributed in the hope that it --
-- will be useful, but  WITHOUT ANY WARRANTY; without even the implied war- --
-- ranty 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 distributed with  GNAT; see file --
-- COPYING.  If not,  write to the  Free Software  Foundation,  51 Franklin --
-- Street, Fifth Floor, Boston, MA 02110-1301, USA.                         --
--                                                                          --
-- GNAT Metrics Toolset is maintained by AdaCore (http://www.adacore.com).  --
--                                                                          --
------------------------------------------------------------------------------

with ASIS_UL.Metrics.Definitions; use ASIS_UL.Metrics.Definitions;
with ASIS_UL.Options;             use ASIS_UL.Options;
with ASIS_UL.Source_Table;

with METRICS.Common;              use METRICS.Common;
with METRICS.Output;              use METRICS.Output;
with METRICS.Options;             use METRICS.Options;

separate (ASIS_UL.Environment)
procedure Scan_Parameters is
   Next_Metric_Option : String_Access;
   Selective_Mode     : Boolean := False;

   Line_Metrics_Set_On    : Boolean := True;
   Element_Metrics_Set_On : Boolean := True;
   --  The corresponding flag is set ON when the first specific metric option
   --  is processed and all the line or element metrics are turned off. It
   --  prevents from turning all the metric all again when the next specific
   --  metric is set on

--   function More_Arguments return Boolean;
   --  Is supposed to be called when Getop returns ASCII.NUL. Tries to read
   --  arguments and store them (if any). returns True if at least one argument
   --  is found and False otherwise

--   function More_Arguments return Boolean is
--      First_Iteration : Boolean := True;
--      Result          : Boolean;
--   begin
--      loop
--         Store_Sources_To_Process
--           (Get_Argument (Do_Expansion => True), No_More_Args);

--         if First_Iteration then
--            Result          := not No_More_Args;
--            First_Iteration := False;
--         end if;

--         exit when No_More_Args;
--      end loop;

--      return Result;
--   end More_Arguments;
begin

   Initialize_Option_Scan
     (Stop_At_First_Non_Switch => False,
      Section_Delimiters       => "cargs");

   loop
      case GNAT.Command_Line.Getopt
        (
         --  Complexity metrics options:
         "-complexity-cyclomatic -no-complexity-cyclomatic " &
         "-complexity-essential  -no-complexity-essential "  &
         "-complexity-average    -no-complexity-average "    &
         "-loop-nesting          -no-loop-nesting  "         &
         "-extra-exit-points     -no-extra-exit-points  "    &
         "-complexity-all        -no-complexity-all  "       &
         "-no-static-loop "                                  &

         --  Line metrics options:
         " -lines             -no-lines             " &
         " -lines-code        -no-lines-code        " &
         " -lines-comment     -no-lines-comment     " &
         " -lines-eol-comment -no-lines-eol-comment " &
         " -lines-ratio       -no-lines-ratio       " &
         " -lines-blank       -no-lines-blank       " &
         " -lines-average     -no-lines-average     " &
         " -lines-all         -no-lines-all         " &

         --  Syntax element metrics options:
         "-declarations       -no-declarations        " &
         "-statements         -no-statements          " &
         "-public-subprograms -no-public-subprograms  " &
         "-all-subprograms    -no-all-subprograms     " &
         "-public-types       -no-public-types        " &
         "-all-types          -no-all-types           " &
         "-unit-nesting       -no-unit-nesting        " &
         "-construct-nesting  -no-construct-nesting   " &
         "-syntax-all         -no-syntax-all          " &

         --  Coupling metrics
         "-coupling-all " &
         "-tagged-coupling-out     -tagged-coupling-in    " &
         "-hierarchy-coupling-out  -hierarchy-coupling-in " &
         "-unit-coupling-out       -unit-coupling-in      " &
         "-control-coupling-out    -control-coupling-in   " &

         --  Old coupling metric control options, kept for upward compatibility
         --  reasons (as non-documented feature)

         "-package-efferent-coupling  -no-package-efferent-coupling  " &
         "-package-afferent-coupling  -no-package-afferent-coupling  " &
         "-category-efferent-coupling -no-category-efferent-coupling " &
         "-category-afferent-coupling -no-category-afferent-coupling " &
         "--no-coupling-all                                          " &

         --  Old metric control options, are kept for upward compatibility
         --  reasons (as non-documented feature)
         "la lcode lcomm leol lb lratio lav " &
         "enu "                               &
         "es ed eps eas ept eat ec "          &
         "nocc noec nonl "                    &

         --  Other options:
         "ne nolocal  "                       &
         "d= o= files= og= ox= x xs nt sfn "  &
         "gnat05 "                            & --  Ada 2005 mode
         "a q v dd debug!")
      is

         when ASCII.NUL =>
            exit when not More_Arguments;
         when  'a' =>
            Process_RTL_Units := True;
         when  'd' =>

            if Full_Switch = "dd" then
               Progress_Indicator_Mode := True;
            elsif Full_Switch = "d" then
               Free (Output_Dir);
               Output_Dir := new String'(Parameter);
            elsif Full_Switch = "debug" then
               Set_Debug_Options (Parameter);
            end if;

         when  'e' =>

            --  Old non-documented syntax element metrics options:

            if Element_Metrics_Set_On then
               Element_Metrics_Off;
               Element_Metrics_Set_On := False;
            end if;

            if Full_Switch = "es" then
               Compute_All_Statements := True;
            elsif Full_Switch = "ed" then
               Compute_All_Declarations := True;
            elsif Full_Switch = "eps" then
               Compute_Public_Subprograms := True;
            elsif Full_Switch = "eas" then
               Compute_All_Subprograms := True;
            elsif Full_Switch = "ept" then
               Compute_Public_Types := True;
            elsif Full_Switch = "eat" then
               Compute_All_Types := True;
            elsif Full_Switch = "enu" then
               Compute_Progam_Unit_Nesting := True;
            elsif Full_Switch = "ec" then
               Compute_Construct_Nesting := True;
            end if;

         when 'f' =>

            if Full_Switch = "files" then
               Read_Args_From_File (Parameter, Store_With_No_Check => True);
            end if;

         when 'g' =>

            if Full_Switch = "gnat05" then
               ASIS_UL.Options.ASIS_2005_Mode := True;
            end if;

         when 'l' =>

            --  Old non-documented line metrics options:
            if Line_Metrics_Set_On then
               Line_Metrics_Off;
               Line_Metrics_Set_On := False;
            end if;

            if Full_Switch = "la" then
               Compute_All_Lines := True;
            elsif Full_Switch = "lcode" then
               Compute_Code_Lines := True;
            elsif Full_Switch = "lcomm" then
               Compute_Comment_Lines := True;
            elsif Full_Switch = "leol" then
               Compute_EOL_Comments := True;
            elsif Full_Switch = "lb" then
               Compute_Blank_Lines := True;
            elsif Full_Switch = "lratio" then
               Compute_Comment_Code_Ratio := True;
            elsif Full_Switch = "lav" then
               Compute_Average_Lines_In_Bodies := True;
            end if;

         when 'n' =>

            if Full_Switch = "ne" then
               ASIS_UL.Metrics.Definitions.Treat_Exit_As_Goto := False;
            elsif Full_Switch = "nolocal" then
               Compute_Local_Metrics := False;

            --  Old non-documented complexity metrics options:
            elsif Full_Switch = "nocc" then
               Compute_Cyclomatic_Complexity := False;
            elsif Full_Switch = "noec" then
               Compute_Essential_Complexity := False;
            elsif Full_Switch = "nonl" then
               Compute_Loop_Nesting := False;
            elsif Full_Switch = "nt" then
               Generate_Text_Output := False;
               Generate_XML_Output  := True;
            end if;

         when 'o' =>

            if Full_Switch = "o" then
               Out_Suffix  := new String'(Parameter);
            elsif Full_Switch = "og" then
               Global_File_Name := new String'(Parameter);
            elsif Full_Switch = "ox" then
               Generate_XML_Output := True;
               XML_File_Name       := new String'(Parameter);
            else
               Brief_Help;
               raise Parameter_Error;
            end if;

         when 'q' =>

            if Full_Switch = "q" then
               Quiet_Mode := True;
            end if;

         when 's' =>

            if Full_Switch = "sfn" then
               Short_SFN_In_Output := True;
            end if;

         when 'v' =>

            if Full_Switch = "v" then
               Verbose_Mode := True;
               Print_Version_Info (2005);
            end if;

         when 'x' =>
            Generate_XML_Output := True;

            if Full_Switch = "xs" then
               Generate_XML_Schema := True;
            end if;

         when '-' =>
            --  Metric options:

            Next_Metric_Option := new String'(Full_Switch);

            if not Selective_Mode
              and then
                Next_Metric_Option'Length > 5
              and then
                Next_Metric_Option
                 (Next_Metric_Option'First .. Next_Metric_Option'First + 3)
                 /= "-no-"
            then
               Selective_Mode := True;
               Complexity_Metrics_Off;
               Element_Metrics_Off;
               Line_Metrics_Off;
            end if;

            --  Complexity metrics options:
            if Next_Metric_Option.all = "-complexity-cyclomatic" then
               Compute_Cyclomatic_Complexity := True;
            elsif Next_Metric_Option.all = "-no-complexity-cyclomatic" then
               Compute_Cyclomatic_Complexity := False;
            elsif Next_Metric_Option.all = "-complexity-essential" then
               Compute_Essential_Complexity := True;
            elsif Next_Metric_Option.all = "-no-complexity-essential" then
               Compute_Essential_Complexity := False;
            elsif Next_Metric_Option.all = "-complexity-average" then
               Compute_Average_Complexity := True;
            elsif Next_Metric_Option.all = "-no-complexity-average" then
               Compute_Average_Complexity := False;
            elsif Next_Metric_Option.all = "-loop-nesting" then
               Compute_Loop_Nesting := True;
            elsif Next_Metric_Option.all = "-no-loop-nesting" then
               Compute_Loop_Nesting := False;
            elsif Next_Metric_Option.all = "-extra-exit-points" then
               Compute_Extra_Exit_Points := True;
            elsif Next_Metric_Option.all = "-no-extra-exit-points" then
               Compute_Extra_Exit_Points := False;
            elsif Next_Metric_Option.all = "-complexity-all" then
               Complexity_Metrics_On;
            elsif Next_Metric_Option.all = "-no-complexity-all" then
               Complexity_Metrics_Off;
            elsif Next_Metric_Option.all = "-no-static-loop" then
               Count_Static_Loop := False;

            --  Line metrics options:
            elsif Next_Metric_Option.all = "-lines" then
               Compute_All_Lines := True;
            elsif Next_Metric_Option.all = "-no-lines" then
               Compute_All_Lines := False;
            elsif Next_Metric_Option.all = "-lines-code" then
               Compute_Code_Lines := True;
            elsif Next_Metric_Option.all = "-no-lines-code" then
               Compute_Code_Lines := False;
            elsif Next_Metric_Option.all = "-lines-comment" then
               Compute_Comment_Lines := True;
            elsif Next_Metric_Option.all = "-no-lines-comment" then
               Compute_Comment_Lines := False;
            elsif Next_Metric_Option.all = "-lines-eol-comment" then
               Compute_EOL_Comments := True;
            elsif Next_Metric_Option.all = "-no-lines-eol-comment" then
               Compute_EOL_Comments := False;
            elsif Next_Metric_Option.all = "-lines-ratio" then
               Compute_Comment_Code_Ratio := True;
            elsif Next_Metric_Option.all = "-no-lines-ratio" then
               Compute_Comment_Code_Ratio := False;
            elsif Next_Metric_Option.all = "-lines-blank" then
               Compute_Blank_Lines := True;
            elsif Next_Metric_Option.all = "-no-lines-blank" then
               Compute_Blank_Lines := False;
            elsif Next_Metric_Option.all = "-lines-average" then
               Compute_Average_Lines_In_Bodies := True;
            elsif Next_Metric_Option.all = "-no-lines-average" then
               Compute_Average_Lines_In_Bodies := False;
            elsif Next_Metric_Option.all = "-lines-all" then
               Line_Metrics_On;
            elsif Next_Metric_Option.all = "-no-lines-all" then
               Line_Metrics_Off;

            --  Syntax element metrics options:
            elsif Next_Metric_Option.all = "-declarations" then
               Compute_All_Declarations := True;
            elsif Next_Metric_Option.all = "-no-declarations" then
               Compute_All_Declarations := False;
            elsif Next_Metric_Option.all = "-statements" then
               Compute_All_Statements := True;
            elsif Next_Metric_Option.all = "-no-statements" then
               Compute_All_Statements := False;
            elsif Next_Metric_Option.all = "-public-subprograms" then
               Compute_Public_Subprograms := True;
            elsif Next_Metric_Option.all = "-no-public-subprograms" then
               Compute_Public_Subprograms := False;
            elsif Next_Metric_Option.all = "-all-subprograms" then
               Compute_All_Subprograms := True;
            elsif Next_Metric_Option.all = "-no-all-subprograms" then
               Compute_All_Subprograms := False;
            elsif Next_Metric_Option.all = "-public-types" then
               Compute_Public_Types := True;
            elsif Next_Metric_Option.all = "-no-public-types" then
               Compute_Public_Types := False;
            elsif Next_Metric_Option.all = "-all-types" then
               Compute_All_Types := True;
            elsif Next_Metric_Option.all = "-no-all-types" then
               Compute_All_Types := False;
            elsif Next_Metric_Option.all = "-unit-nesting" then
               Compute_Progam_Unit_Nesting := True;
            elsif Next_Metric_Option.all = "-no-unit-nesting" then
               Compute_Progam_Unit_Nesting := False;
            elsif Next_Metric_Option.all = "-construct-nesting" then
               Compute_Construct_Nesting := True;
            elsif Next_Metric_Option.all = "-no-construct-nesting" then
               Compute_Construct_Nesting := False;
            elsif Next_Metric_Option.all = "-syntax-all" then
               Element_Metrics_On;
            elsif Next_Metric_Option.all = "-no-syntax-all" then
               Element_Metrics_Off;

            --  Coupling metrics
            elsif Next_Metric_Option.all = "-package-efferent-coupling"
               or else
                  Next_Metric_Option.all = "-tagged-coupling-out"
            then
               Compute_OO_Package_Efferent_Coupling := True;
            elsif Next_Metric_Option.all =
              "-no-package-efferent-coupling"
            then
               Compute_OO_Package_Efferent_Coupling := False;
            elsif Next_Metric_Option.all = "-package-afferent-coupling"
               or else
                  Next_Metric_Option.all = "-tagged-coupling-in"
            then
               Compute_OO_Package_Afferent_Coupling := True;
            elsif Next_Metric_Option.all =
              "-no-package-afferent-coupling"
            then
               Compute_OO_Package_Afferent_Coupling := False;
            elsif Next_Metric_Option.all = "-category-efferent-coupling"
               or else
                  Next_Metric_Option.all = "-hierarchy-coupling-out"
            then
               Compute_Category_Efferent_Coupling := True;
            elsif Next_Metric_Option.all =
              "-no-category-efferent-coupling"
            then
               Compute_Category_Efferent_Coupling := False;
            elsif Next_Metric_Option.all = "-category-afferent-coupling"
               or else
                  Next_Metric_Option.all = "-hierarchy-coupling-in"
            then
               Compute_Category_Afferent_Coupling := True;
            elsif Next_Metric_Option.all =
              "-no-category-afferent-coupling"
            then
               Compute_Category_Afferent_Coupling := False;
            elsif Next_Metric_Option.all = "-control-coupling-out" then
               Compute_Control_Efferent_Coupling := True;
            elsif Next_Metric_Option.all = "-control-coupling-in" then
               Compute_Control_Afferent_Coupling := True;
            elsif Next_Metric_Option.all = "-unit-coupling-out" then
               Compute_Unit_Efferent_Coupling := True;
            elsif Next_Metric_Option.all = "-unit-coupling-in" then
               Compute_Unit_Afferent_Coupling := True;
            elsif Next_Metric_Option.all = "-coupling-all" then
               Coupling_Metric_On;
            elsif Next_Metric_Option.all = "-no-coupling-all" then
               Coupling_Metric_Off;
            else
               null;
               pragma Assert (False);
            end if;

            Free (Next_Metric_Option);

         when others =>
            Brief_Help;
            raise Parameter_Error;
      end case;
   end loop;

   Process_cargs_Section;

exception
   when GNAT.Command_Line.Invalid_Switch =>
      Error ("invalid switch : " & Full_Switch);
      raise Parameter_Error;

   when GNAT.Command_Line.Invalid_Parameter =>
      Error ("parameter missed for : -" & Full_Switch);
      raise Parameter_Error;

end Scan_Parameters;
