File : switch-m.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT COMPILER COMPONENTS                         --
   4 --                                                                          --
   5 --                             S W I T C H - M                              --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --          Copyright (C) 2001-2016, Free Software Foundation, Inc.         --
  10 --                                                                          --
  11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  12 -- terms of the  GNU General Public License as published  by the Free Soft- --
  13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  17 -- for  more details.  You should have  received  a copy of the GNU General --
  18 -- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
  19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
  20 --                                                                          --
  21 -- GNAT was originally developed  by the GNAT team at  New York University. --
  22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  23 --                                                                          --
  24 ------------------------------------------------------------------------------
  25 
  26 with Debug;    use Debug;
  27 with Makeutl;  use Makeutl;
  28 with Osint;    use Osint;
  29 with Opt;      use Opt;
  30 with Prj;      use Prj;
  31 with Prj.Env;  use Prj.Env;
  32 with Table;
  33 
  34 with System.Multiprocessors; use System.Multiprocessors;
  35 
  36 package body Switch.M is
  37 
  38    package Normalized_Switches is new Table.Table
  39      (Table_Component_Type => String_Access,
  40       Table_Index_Type     => Integer,
  41       Table_Low_Bound      => 1,
  42       Table_Initial        => 20,
  43       Table_Increment      => 100,
  44       Table_Name           => "Switch.M.Normalized_Switches");
  45    --  This table is used to keep the normalized switches, so that they may be
  46    --  reused for subsequent invocations of Normalize_Compiler_Switches with
  47    --  similar switches.
  48 
  49    Initial_Number_Of_Switches : constant := 10;
  50 
  51    Global_Switches : Argument_List_Access := null;
  52    --  Used by function Normalize_Compiler_Switches
  53 
  54    ---------------------------------
  55    -- Normalize_Compiler_Switches --
  56    ---------------------------------
  57 
  58    procedure Normalize_Compiler_Switches
  59      (Switch_Chars : String;
  60       Switches     : in out Argument_List_Access;
  61       Last         : out Natural)
  62    is
  63       Switch_Starts_With_Gnat : Boolean;
  64 
  65       Ptr : Integer := Switch_Chars'First;
  66       Max : constant Integer := Switch_Chars'Last;
  67       C   : Character := ' ';
  68 
  69       Storing      : String := Switch_Chars;
  70       First_Stored : Positive := Ptr + 1;
  71       Last_Stored  : Positive := First_Stored;
  72 
  73       procedure Add_Switch_Component (S : String);
  74       --  Add a new String_Access component in Switches. If a string equal
  75       --  to S is already stored in the table Normalized_Switches, use it.
  76       --  Otherwise add a new component to the table.
  77 
  78       --------------------------
  79       -- Add_Switch_Component --
  80       --------------------------
  81 
  82       procedure Add_Switch_Component (S : String) is
  83       begin
  84          --  If Switches is null, allocate a new array
  85 
  86          if Switches = null then
  87             Switches := new Argument_List (1 .. Initial_Number_Of_Switches);
  88 
  89          --  Otherwise, if Switches is full, extend it
  90 
  91          elsif Last = Switches'Last then
  92             declare
  93                New_Switches : constant Argument_List_Access :=
  94                                 new Argument_List
  95                                       (1 .. Switches'Length + Switches'Length);
  96             begin
  97                New_Switches (1 .. Switches'Length) := Switches.all;
  98                Last := Switches'Length;
  99                Switches := New_Switches;
 100             end;
 101          end if;
 102 
 103          --  If this is the first switch, Last designates the first component
 104 
 105          if Last = 0 then
 106             Last := Switches'First;
 107          else
 108             Last := Last + 1;
 109          end if;
 110 
 111          --  Look into the table Normalized_Switches for a similar string.
 112          --  If one is found, put it at the added component, and return.
 113 
 114          for Index in 1 .. Normalized_Switches.Last loop
 115             if S = Normalized_Switches.Table (Index).all then
 116                Switches (Last) := Normalized_Switches.Table (Index);
 117                return;
 118             end if;
 119          end loop;
 120 
 121          --  No string equal to S was found in the table Normalized_Switches.
 122          --  Add a new component in the table.
 123 
 124          Switches (Last) := new String'(S);
 125          Normalized_Switches.Append (Switches (Last));
 126       end Add_Switch_Component;
 127 
 128    --  Start of processing for Normalize_Compiler_Switches
 129 
 130    begin
 131       Last := 0;
 132 
 133       if Ptr = Max or else Switch_Chars (Ptr) /= '-' then
 134          return;
 135       end if;
 136 
 137       Ptr := Ptr + 1;
 138 
 139       Switch_Starts_With_Gnat :=
 140          Ptr + 3 <= Max and then Switch_Chars (Ptr .. Ptr + 3) = "gnat";
 141 
 142       if Switch_Starts_With_Gnat then
 143          Ptr := Ptr + 4;
 144          First_Stored := Ptr;
 145       end if;
 146 
 147       while Ptr <= Max loop
 148          C := Switch_Chars (Ptr);
 149 
 150          --  Processing for a switch
 151 
 152          case Switch_Starts_With_Gnat is
 153 
 154             when False =>
 155 
 156                --  All switches that don't start with -gnat stay as is,
 157                --  except -pg, -Wall, -k8, -w
 158 
 159                if Switch_Chars = "-pg" or else Switch_Chars = "-p" then
 160 
 161                   --  The gcc driver converts -pg to -p, so that is what
 162                   --  is stored in the ALI file.
 163 
 164                   Add_Switch_Component ("-p");
 165 
 166                elsif Switch_Chars = "-Wall" then
 167 
 168                   --  The gcc driver adds -gnatwa when -Wall is used
 169 
 170                   Add_Switch_Component ("-gnatwa");
 171                   Add_Switch_Component ("-Wall");
 172 
 173                elsif Switch_Chars = "-k8" then
 174 
 175                   --  The gcc driver transforms -k8 into -gnatk8
 176 
 177                   Add_Switch_Component ("-gnatk8");
 178 
 179                elsif Switch_Chars = "-w" then
 180 
 181                   --  The gcc driver adds -gnatws when -w is used
 182 
 183                   Add_Switch_Component ("-gnatws");
 184                   Add_Switch_Component ("-w");
 185 
 186                elsif Switch_Chars'Length > 6
 187                  and then
 188                    Switch_Chars (Switch_Chars'First .. Switch_Chars'First + 5)
 189                                                              = "--RTS="
 190                then
 191                   Add_Switch_Component (Switch_Chars);
 192 
 193                   --  When --RTS=mtp is used, the gcc driver adds -mrtp
 194 
 195                   if Switch_Chars = "--RTS=mtp" then
 196                      Add_Switch_Component ("-mrtp");
 197                   end if;
 198 
 199                --  Special case for -fstack-check (alias for
 200                --  -fstack-check=specific)
 201 
 202                elsif Switch_Chars = "-fstack-check" then
 203                   Add_Switch_Component ("-fstack-check=specific");
 204 
 205                --  Take only into account switches that are transmitted to
 206                --  gnat1 by the gcc driver and stored by gnat1 in the ALI file.
 207 
 208                else
 209                   case C is
 210                      when 'O' | 'W' | 'w' | 'f' | 'd' | 'g' | 'm' =>
 211                         Add_Switch_Component (Switch_Chars);
 212 
 213                      when others =>
 214                         null;
 215                   end case;
 216                end if;
 217 
 218                return;
 219 
 220             when True =>
 221 
 222                case C is
 223 
 224                   --  One-letter switches
 225 
 226                   when 'a' | 'A' | 'b' | 'B' | 'c' | 'C' | 'E' | 'f' |
 227                        'F' | 'g' | 'h' | 'H' | 'I' | 'L' | 'N' | 'p' |
 228                        'P' | 'q' | 'Q' | 'r' | 's' | 'S' | 't' | 'u' |
 229                        'U' | 'v' | 'x' | 'X' | 'Z' =>
 230                      Storing (First_Stored) := C;
 231                      Add_Switch_Component
 232                        (Storing (Storing'First .. First_Stored));
 233                      Ptr := Ptr + 1;
 234 
 235                   --  One-letter switches followed by a positive number
 236 
 237                   when 'D' | 'G' | 'j' | 'k' | 'm' | 'T' =>
 238                      Storing (First_Stored) := C;
 239                      Last_Stored := First_Stored;
 240 
 241                      if Ptr <= Max and then Switch_Chars (Ptr) = '=' then
 242                         Ptr := Ptr + 1;
 243                      end if;
 244 
 245                      loop
 246                         Ptr := Ptr + 1;
 247                         exit when Ptr > Max
 248                           or else Switch_Chars (Ptr) not in '0' .. '9';
 249                         Last_Stored := Last_Stored + 1;
 250                         Storing (Last_Stored) := Switch_Chars (Ptr);
 251                      end loop;
 252 
 253                      Add_Switch_Component
 254                        (Storing (Storing'First .. Last_Stored));
 255 
 256                   when 'd' =>
 257                      Storing (First_Stored) := 'd';
 258 
 259                      while Ptr < Max loop
 260                         Ptr := Ptr + 1;
 261                         C := Switch_Chars (Ptr);
 262                         exit when C = ASCII.NUL or else C = '/'
 263                           or else C = '-';
 264 
 265                         if C in '1' .. '9' or else
 266                            C in 'a' .. 'z' or else
 267                            C in 'A' .. 'Z'
 268                         then
 269                            Storing (First_Stored + 1) := C;
 270                            Add_Switch_Component
 271                              (Storing (Storing'First .. First_Stored + 1));
 272 
 273                         else
 274                            Last := 0;
 275                            return;
 276                         end if;
 277                      end loop;
 278 
 279                      return;
 280 
 281                   when 'e' =>
 282 
 283                      --  Some of the gnate... switches are not stored
 284 
 285                      Storing (First_Stored) := 'e';
 286                      Ptr := Ptr + 1;
 287 
 288                      if Ptr > Max then
 289                         Last := 0;
 290                         return;
 291 
 292                      else
 293                         case Switch_Chars (Ptr) is
 294 
 295                            when 'A' =>
 296                               Ptr := Ptr + 1;
 297                               Add_Switch_Component ("-gnateA");
 298 
 299                            when 'D' =>
 300                               Storing (First_Stored + 1 ..
 301                                          First_Stored + Max - Ptr + 1) :=
 302                                   Switch_Chars (Ptr .. Max);
 303                               Add_Switch_Component
 304                                 (Storing (Storing'First ..
 305                                    First_Stored + Max - Ptr + 1));
 306                               Ptr := Max + 1;
 307 
 308                            when 'E' | 'F' | 'G' | 'S' | 'u' | 'V' | 'Y' =>
 309                               Add_Switch_Component
 310                                 ("-gnate" & Switch_Chars (Ptr));
 311                               Ptr := Ptr + 1;
 312 
 313                            when 'i' | 'I' =>
 314                               declare
 315                                  First : constant Positive := Ptr;
 316 
 317                               begin
 318                                  Ptr := Ptr + 1;
 319 
 320                                  if Ptr <= Max and then
 321                                    Switch_Chars (Ptr) = '='
 322                                  then
 323                                     Ptr := Ptr + 1;
 324                                  end if;
 325 
 326                                  while Ptr <= Max and then
 327                                        Switch_Chars (Ptr) in '0' .. '9'
 328                                  loop
 329                                     Ptr := Ptr + 1;
 330                                  end loop;
 331 
 332                                  Storing (First_Stored + 1 ..
 333                                             First_Stored + Ptr - First) :=
 334                                      Switch_Chars (First .. Ptr - 1);
 335                                  Add_Switch_Component
 336                                    (Storing (Storing'First ..
 337                                       First_Stored + Ptr - First));
 338                               end;
 339 
 340                            when 'l' =>
 341                               Ptr := Ptr + 1;
 342                               Add_Switch_Component ("-gnatel");
 343 
 344                            when 'L' =>
 345                               Ptr := Ptr + 1;
 346                               Add_Switch_Component ("-gnateL");
 347 
 348                            when 'p' =>
 349                               Ptr := Ptr + 1;
 350 
 351                               if Ptr = Max then
 352                                  Last := 0;
 353                                  return;
 354                               end if;
 355 
 356                               if Switch_Chars (Ptr) = '=' then
 357                                  Ptr := Ptr + 1;
 358                               end if;
 359 
 360                                  --  To normalize, always put a '=' after
 361                                  --  -gnatep. Because that could lengthen the
 362                                  --  switch string, declare a local variable.
 363 
 364                               declare
 365                                  To_Store : String (1 .. Max - Ptr + 9);
 366                               begin
 367                                  To_Store (1 .. 8) := "-gnatep=";
 368                                  To_Store (9 .. Max - Ptr + 9) :=
 369                                    Switch_Chars (Ptr .. Max);
 370                                  Add_Switch_Component (To_Store);
 371                               end;
 372 
 373                               return;
 374 
 375                            when others =>
 376                               Last := 0;
 377                               return;
 378                         end case;
 379                      end if;
 380 
 381                   when 'i' =>
 382                      Storing (First_Stored) := 'i';
 383 
 384                      Ptr := Ptr + 1;
 385 
 386                      if Ptr > Max then
 387                         Last := 0;
 388                         return;
 389                      end if;
 390 
 391                      C := Switch_Chars (Ptr);
 392 
 393                      if C in '1' .. '5'
 394                        or else C = '8'
 395                        or else C = 'p'
 396                        or else C = 'f'
 397                        or else C = 'n'
 398                        or else C = 'w'
 399                      then
 400                         Storing (First_Stored + 1) := C;
 401                         Add_Switch_Component
 402                           (Storing (Storing'First .. First_Stored + 1));
 403                         Ptr := Ptr + 1;
 404 
 405                      else
 406                         Last := 0;
 407                         return;
 408                      end if;
 409 
 410                   --  -gnatl may be -gnatl=<file name>
 411 
 412                   when 'l' =>
 413                      Ptr := Ptr + 1;
 414 
 415                      if Ptr > Max or else Switch_Chars (Ptr) /= '=' then
 416                         Add_Switch_Component ("-gnatl");
 417 
 418                      else
 419                         Add_Switch_Component
 420                           ("-gnatl" & Switch_Chars (Ptr .. Max));
 421                         return;
 422                      end if;
 423 
 424                   --  -gnatn may be -gnatn, -gnatn1, or -gnatn2
 425 
 426                   when 'n' =>
 427                      Last_Stored := First_Stored;
 428                      Storing (Last_Stored) := 'n';
 429                      Ptr := Ptr + 1;
 430 
 431                      if Ptr <= Max
 432                        and then Switch_Chars (Ptr) in '1' .. '2'
 433                      then
 434                         Last_Stored := Last_Stored + 1;
 435                         Storing (Last_Stored) := Switch_Chars (Ptr);
 436                         Ptr := Ptr + 1;
 437                      end if;
 438 
 439                      Add_Switch_Component
 440                        (Storing (Storing'First .. Last_Stored));
 441 
 442                   --  -gnato may be -gnatox or -gnatoxx, with x=0/1/2/3
 443 
 444                   when 'o' =>
 445                      Last_Stored := First_Stored;
 446                      Storing (Last_Stored) := 'o';
 447                      Ptr := Ptr + 1;
 448 
 449                      if Ptr <= Max
 450                        and then Switch_Chars (Ptr) in '0' .. '3'
 451                      then
 452                         Last_Stored := Last_Stored + 1;
 453                         Storing (Last_Stored) := Switch_Chars (Ptr);
 454                         Ptr := Ptr + 1;
 455 
 456                         if Ptr <= Max
 457                           and then Switch_Chars (Ptr) in '0' .. '3'
 458                         then
 459                            Last_Stored := Last_Stored + 1;
 460                            Storing (Last_Stored) := Switch_Chars (Ptr);
 461                            Ptr := Ptr + 1;
 462                         end if;
 463                      end if;
 464 
 465                      Add_Switch_Component
 466                        (Storing (Storing'First .. Last_Stored));
 467 
 468                   --  -gnatR may be followed by '0', '1', '2' or '3',
 469                   --  then by 's'
 470 
 471                   when 'R' =>
 472                      Last_Stored := First_Stored;
 473                      Storing (Last_Stored) := 'R';
 474                      Ptr := Ptr + 1;
 475 
 476                      if Ptr <= Max
 477                        and then Switch_Chars (Ptr) in '0' .. '9'
 478                      then
 479                         C := Switch_Chars (Ptr);
 480 
 481                         if C in '4' .. '9' then
 482                            Last := 0;
 483                            return;
 484 
 485                         else
 486                            Last_Stored := Last_Stored + 1;
 487                            Storing (Last_Stored) := C;
 488                            Ptr := Ptr + 1;
 489 
 490                            if Ptr <= Max
 491                              and then Switch_Chars (Ptr) = 's'
 492                            then
 493                               Last_Stored := Last_Stored + 1;
 494                               Storing (Last_Stored) := 's';
 495                               Ptr := Ptr + 1;
 496                            end if;
 497                         end if;
 498                      end if;
 499 
 500                      Add_Switch_Component
 501                        (Storing (Storing'First .. Last_Stored));
 502 
 503                   --  -gnatWx, x = 'h'. 'u', 's', 'e', '8' or 'b'
 504 
 505                   when 'W' =>
 506                      Storing (First_Stored) := 'W';
 507                      Ptr := Ptr + 1;
 508 
 509                      if Ptr <= Max then
 510                         case Switch_Chars (Ptr) is
 511                            when 'h' | 'u' | 's' | 'e' | '8' | 'b' =>
 512                               Storing (First_Stored + 1) := Switch_Chars (Ptr);
 513                               Add_Switch_Component
 514                                 (Storing (Storing'First .. First_Stored + 1));
 515                               Ptr := Ptr + 1;
 516 
 517                            when others =>
 518                               Last := 0;
 519                               return;
 520                         end case;
 521                      end if;
 522 
 523                   --  Multiple switches
 524 
 525                   when 'V' | 'w' | 'y' =>
 526                      Storing (First_Stored) := C;
 527                      Ptr := Ptr + 1;
 528 
 529                      if Ptr > Max then
 530                         if C = 'y' then
 531                            Add_Switch_Component
 532                              (Storing (Storing'First .. First_Stored));
 533 
 534                         else
 535                            Last := 0;
 536                            return;
 537                         end if;
 538                      end if;
 539 
 540                      --  Loop through remaining switch characters in string
 541 
 542                      while Ptr <= Max loop
 543                         C := Switch_Chars (Ptr);
 544                         Ptr := Ptr + 1;
 545 
 546                         --  -gnatyMxxx
 547 
 548                         if C = 'M' and then Storing (First_Stored) = 'y' then
 549                            Last_Stored := First_Stored + 1;
 550                            Storing (Last_Stored) := 'M';
 551                            while Ptr <= Max loop
 552                               C := Switch_Chars (Ptr);
 553                               exit when C not in '0' .. '9';
 554                               Last_Stored := Last_Stored + 1;
 555                               Storing (Last_Stored) := C;
 556                               Ptr := Ptr + 1;
 557                            end loop;
 558 
 559                            --  If there is no digit after -gnatyM,
 560                            --  the switch is invalid.
 561 
 562                            if Last_Stored = First_Stored + 1 then
 563                               Last := 0;
 564                               return;
 565 
 566                            else
 567                               Add_Switch_Component
 568                                 (Storing (Storing'First .. Last_Stored));
 569                            end if;
 570 
 571                         --  --gnatx.x
 572 
 573                         elsif C = '.' and then Ptr <= Max then
 574                            Storing (First_Stored + 1) := '.';
 575                            Storing (First_Stored + 2) := Switch_Chars (Ptr);
 576                            Ptr := Ptr + 1;
 577                            Add_Switch_Component
 578                              (Storing (Storing'First .. First_Stored + 2));
 579 
 580                         --  All other switches are -gnatxx
 581 
 582                         else
 583                            Storing (First_Stored + 1) := C;
 584                            Add_Switch_Component
 585                              (Storing (Storing'First .. First_Stored + 1));
 586                         end if;
 587                      end loop;
 588 
 589                   --  -gnat95 -gnat05
 590 
 591                   when '0' | '9' =>
 592                      Last_Stored := First_Stored;
 593                      Storing (Last_Stored) := C;
 594                      Ptr := Ptr + 1;
 595 
 596                      if Ptr /= Max or else Switch_Chars (Ptr) /= '5' then
 597 
 598                         --  Invalid switch
 599 
 600                         Last := 0;
 601                         return;
 602 
 603                      else
 604                         Last_Stored := Last_Stored + 1;
 605                         Storing (Last_Stored) := '5';
 606                         Add_Switch_Component
 607                           (Storing (Storing'First .. Last_Stored));
 608                         Ptr := Ptr + 1;
 609                      end if;
 610 
 611                      --  -gnat12
 612 
 613                   when '1' =>
 614                      Last_Stored := First_Stored;
 615                      Storing (Last_Stored) := C;
 616                      Ptr := Ptr + 1;
 617 
 618                      if Ptr /= Max or else Switch_Chars (Ptr) /= '2' then
 619 
 620                         --  Invalid switch
 621 
 622                         Last := 0;
 623                         return;
 624 
 625                      else
 626                         Last_Stored := Last_Stored + 1;
 627                         Storing (Last_Stored) := '2';
 628                         Add_Switch_Component
 629                           (Storing (Storing'First .. Last_Stored));
 630                         Ptr := Ptr + 1;
 631                      end if;
 632 
 633                      --  -gnat2005 -gnat2012
 634 
 635                   when '2' =>
 636                      if Ptr + 3 /= Max then
 637                         Last := 0;
 638                         return;
 639 
 640                      elsif Switch_Chars (Ptr + 1 .. Ptr + 3) = "005" then
 641                         Last_Stored := First_Stored + 3;
 642                         Storing (First_Stored .. Last_Stored) := "2005";
 643                         Add_Switch_Component
 644                           (Storing (Storing'First .. Last_Stored));
 645                         Ptr := Max + 1;
 646 
 647                      elsif Switch_Chars (Ptr + 1 .. Ptr + 3) = "012" then
 648                         Last_Stored := First_Stored + 3;
 649                         Storing (First_Stored .. Last_Stored) := "2012";
 650                         Add_Switch_Component
 651                           (Storing (Storing'First .. Last_Stored));
 652                         Ptr := Max + 1;
 653 
 654                      else
 655 
 656                         --  Invalid switch
 657 
 658                         Last := 0;
 659                         return;
 660 
 661                      end if;
 662 
 663                   --  -gnat83
 664 
 665                   when '8' =>
 666                      Last_Stored := First_Stored;
 667                      Storing (Last_Stored) := '8';
 668                      Ptr := Ptr + 1;
 669 
 670                      if Ptr /= Max or else Switch_Chars (Ptr) /= '3' then
 671 
 672                         --  Invalid switch
 673 
 674                         Last := 0;
 675                         return;
 676 
 677                      else
 678                         Last_Stored := Last_Stored + 1;
 679                         Storing (Last_Stored) := '3';
 680                         Add_Switch_Component
 681                           (Storing (Storing'First .. Last_Stored));
 682                         Ptr := Ptr + 1;
 683                      end if;
 684 
 685                   --  Not a valid switch
 686 
 687                   when others =>
 688                      Last := 0;
 689                      return;
 690 
 691                end case;
 692 
 693          end case;
 694       end loop;
 695    end Normalize_Compiler_Switches;
 696 
 697    function Normalize_Compiler_Switches
 698      (Switch_Chars : String) return Argument_List
 699    is
 700       Last : Natural;
 701 
 702    begin
 703       Normalize_Compiler_Switches (Switch_Chars, Global_Switches, Last);
 704 
 705       if Last = 0 then
 706          return (1 .. 0 => null);
 707       else
 708          return Global_Switches (Global_Switches'First .. Last);
 709       end if;
 710    end Normalize_Compiler_Switches;
 711 
 712    ------------------------
 713    -- Scan_Make_Switches --
 714    ------------------------
 715 
 716    procedure Scan_Make_Switches
 717      (Env               : in out Prj.Tree.Environment;
 718       Switch_Chars      : String;
 719       Success           : out Boolean)
 720    is
 721       Ptr : Integer          := Switch_Chars'First;
 722       Max : constant Integer := Switch_Chars'Last;
 723       C   : Character        := ' ';
 724 
 725    begin
 726       --  Assume a good switch
 727 
 728       Success := True;
 729 
 730       --  Skip past the initial character (must be the switch character)
 731 
 732       if Ptr = Max then
 733          Bad_Switch (Switch_Chars);
 734 
 735       else
 736          Ptr := Ptr + 1;
 737       end if;
 738 
 739       --  A little check, "gnat" at the start of a switch is for the compiler
 740 
 741       if Switch_Chars'Length >= Ptr + 3
 742         and then Switch_Chars (Ptr .. Ptr + 3) = "gnat"
 743       then
 744          Success := False;
 745          return;
 746       end if;
 747 
 748       C := Switch_Chars (Ptr);
 749 
 750       --  Multiple character switches
 751 
 752       if Switch_Chars'Length > 2 then
 753          if Switch_Chars = "--create-missing-dirs" then
 754             Setup_Projects := True;
 755 
 756          elsif Switch_Chars'Length > Subdirs_Option'Length
 757            and then
 758              Switch_Chars
 759                (Switch_Chars'First ..
 760                 Switch_Chars'First + Subdirs_Option'Length - 1) =
 761                                                             Subdirs_Option
 762          then
 763             Subdirs :=
 764               new String'
 765                 (Switch_Chars
 766                   (Switch_Chars'First + Subdirs_Option'Length ..
 767                    Switch_Chars'Last));
 768 
 769          elsif Switch_Chars = Makeutl.Unchecked_Shared_Lib_Imports then
 770             Opt.Unchecked_Shared_Lib_Imports := True;
 771 
 772          elsif Switch_Chars = Makeutl.Single_Compile_Per_Obj_Dir_Switch then
 773             Opt.One_Compilation_Per_Obj_Dir := True;
 774 
 775          elsif Switch_Chars = Makeutl.No_Exit_Message_Option then
 776             Opt.No_Exit_Message := True;
 777 
 778          elsif Switch_Chars = Makeutl.Keep_Temp_Files_Option then
 779             Opt.Keep_Temporary_Files := True;
 780 
 781          elsif Switch_Chars (Ptr) = '-' then
 782             Bad_Switch (Switch_Chars);
 783 
 784          elsif Switch_Chars'Length > 3
 785            and then Switch_Chars (Ptr .. Ptr + 1) = "aP"
 786          then
 787             Add_Directories
 788               (Env.Project_Path,
 789                Switch_Chars (Ptr + 2 .. Switch_Chars'Last));
 790 
 791          elsif C = 'v' and then Switch_Chars'Length = 3 then
 792             Ptr := Ptr + 1;
 793             Verbose_Mode := True;
 794 
 795             case Switch_Chars (Ptr) is
 796                when 'l' =>
 797                   Verbosity_Level := Opt.Low;
 798 
 799                when 'm' =>
 800                   Verbosity_Level := Opt.Medium;
 801 
 802                when 'h' =>
 803                   Verbosity_Level := Opt.High;
 804 
 805                when others =>
 806                   Success := False;
 807             end case;
 808 
 809          elsif C = 'd' then
 810 
 811             --  Note: for the debug switch, the remaining characters in this
 812             --  switch field must all be debug flags, since all valid switch
 813             --  characters are also valid debug characters. This switch is not
 814             --  documented on purpose because it is only used by the
 815             --  implementors.
 816 
 817             --  Loop to scan out debug flags
 818 
 819             while Ptr < Max loop
 820                Ptr := Ptr + 1;
 821                C := Switch_Chars (Ptr);
 822 
 823                if C in 'a' .. 'z' or else C in 'A' .. 'Z' then
 824                   Set_Debug_Flag (C);
 825                else
 826                   Bad_Switch (Switch_Chars);
 827                end if;
 828             end loop;
 829 
 830          elsif C = 'e' then
 831             Ptr := Ptr + 1;
 832 
 833             case Switch_Chars (Ptr) is
 834 
 835                --  Processing for eI switch
 836 
 837                when 'I' =>
 838                   Ptr := Ptr + 1;
 839                   Scan_Pos (Switch_Chars, Max, Ptr, Main_Index, C);
 840 
 841                   if Ptr <= Max then
 842                      Bad_Switch (Switch_Chars);
 843                   end if;
 844 
 845                --  Processing for eL switch
 846 
 847                when 'L' =>
 848                   if Ptr /= Max then
 849                      Bad_Switch (Switch_Chars);
 850 
 851                   else
 852                      Follow_Links_For_Files := True;
 853                      Follow_Links_For_Dirs  := True;
 854                   end if;
 855 
 856                --  Processing for eS switch
 857 
 858                when 'S' =>
 859                   if Ptr /= Max then
 860                      Bad_Switch (Switch_Chars);
 861 
 862                   else
 863                      Commands_To_Stdout := True;
 864                   end if;
 865 
 866                when others =>
 867                   Bad_Switch (Switch_Chars);
 868             end case;
 869 
 870          elsif C = 'j' then
 871             Ptr := Ptr + 1;
 872 
 873             declare
 874                Max_Proc : Nat;
 875 
 876             begin
 877                Scan_Nat (Switch_Chars, Max, Ptr, Max_Proc, C);
 878 
 879                if Ptr <= Max then
 880                   Bad_Switch (Switch_Chars);
 881 
 882                else
 883                   if Max_Proc = 0 then
 884                      Max_Proc := Nat (Number_Of_CPUs);
 885 
 886                      if Max_Proc = 0 then
 887                         Max_Proc := 1;
 888                      end if;
 889                   end if;
 890 
 891                   Maximum_Processes := Positive (Max_Proc);
 892                end if;
 893             end;
 894 
 895          elsif C = 'w' and then Switch_Chars'Length = 3 then
 896             Ptr := Ptr + 1;
 897 
 898             if Switch_Chars = "-we" then
 899                Warning_Mode := Treat_As_Error;
 900 
 901             elsif Switch_Chars = "-wn" then
 902                Warning_Mode := Normal;
 903 
 904             elsif Switch_Chars = "-ws" then
 905                Warning_Mode  := Suppress;
 906 
 907             else
 908                Success := False;
 909             end if;
 910 
 911          else
 912             Success := False;
 913          end if;
 914 
 915       --  Single-character switches
 916 
 917       else
 918          Check_Switch : begin
 919 
 920             case C is
 921 
 922                when 'a' =>
 923                   Check_Readonly_Files := True;
 924 
 925                --  Processing for b switch
 926 
 927                when 'b' =>
 928                   Bind_Only  := True;
 929                   Make_Steps := True;
 930 
 931                --  Processing for B switch
 932 
 933                when 'B' =>
 934                   Build_Bind_And_Link_Full_Project := True;
 935 
 936                --  Processing for c switch
 937 
 938                when 'c' =>
 939                   Compile_Only := True;
 940                   Make_Steps   := True;
 941 
 942                --  Processing for C switch
 943 
 944                when 'C' =>
 945                   Opt.Create_Mapping_File := True;
 946 
 947                --  Processing for D switch
 948 
 949                when 'D' =>
 950                   if Object_Directory_Present then
 951                      Osint.Fail ("duplicate -D switch");
 952 
 953                   else
 954                      Object_Directory_Present := True;
 955                   end if;
 956 
 957                --  Processing for f switch
 958 
 959                when 'f' =>
 960                   Force_Compilations := True;
 961 
 962                --  Processing for F switch
 963 
 964                when 'F' =>
 965                   Full_Path_Name_For_Brief_Errors := True;
 966 
 967                --  Processing for h switch
 968 
 969                when 'h' =>
 970                   Usage_Requested := True;
 971 
 972                --  Processing for i switch
 973 
 974                when 'i' =>
 975                   In_Place_Mode := True;
 976 
 977                --  Processing for j switch
 978 
 979                when 'j' =>
 980                   --  -j not followed by a number is an error
 981 
 982                   Bad_Switch (Switch_Chars);
 983 
 984                --  Processing for k switch
 985 
 986                when 'k' =>
 987                   Keep_Going := True;
 988 
 989                --  Processing for l switch
 990 
 991                when 'l' =>
 992                   Link_Only  := True;
 993                   Make_Steps := True;
 994 
 995                --  Processing for M switch
 996 
 997                when 'M' =>
 998                   List_Dependencies := True;
 999 
1000                --  Processing for n switch
1001 
1002                when 'n' =>
1003                   Do_Not_Execute := True;
1004 
1005                --  Processing for o switch
1006 
1007                when 'o' =>
1008                   if Output_File_Name_Present then
1009                      Osint.Fail ("duplicate -o switch");
1010                   else
1011                      Output_File_Name_Present := True;
1012                   end if;
1013 
1014                --  Processing for p switch
1015 
1016                when 'p' =>
1017                   Setup_Projects := True;
1018 
1019                --  Processing for q switch
1020 
1021                when 'q' =>
1022                   Quiet_Output := True;
1023 
1024                --  Processing for R switch
1025 
1026                when 'R' =>
1027                   Run_Path_Option := False;
1028 
1029                --  Processing for s switch
1030 
1031                when 's' =>
1032                   Ptr := Ptr + 1;
1033                   Check_Switches := True;
1034 
1035                --  Processing for v switch
1036 
1037                when 'v' =>
1038                   Verbose_Mode := True;
1039                   Verbosity_Level := Opt.High;
1040 
1041                   --  Processing for x switch
1042 
1043                when 'x' =>
1044                   External_Unit_Compilation_Allowed := True;
1045                   Use_Include_Path_File := True;
1046 
1047                   --  Processing for z switch
1048 
1049                when 'z' =>
1050                   No_Main_Subprogram := True;
1051 
1052                   --  Any other small letter is an illegal switch
1053 
1054                when others =>
1055                   if C in 'a' .. 'z' then
1056                      Bad_Switch (Switch_Chars);
1057 
1058                   else
1059                      Success := False;
1060                   end if;
1061 
1062             end case;
1063          end Check_Switch;
1064       end if;
1065    end Scan_Make_Switches;
1066 
1067 end Switch.M;