File : s-valuti.adb


     ------------------------------------------------------------------------------
     --                                                                          --
     --                         GNAT COMPILER COMPONENTS                         --
     --                                                                          --
   5 --                      S Y S T E M . V A L _ U T I L                       --
     --                                                                          --
     --                                 B o d y                                  --
     --                                                                          --
     --                            $Revision: 1.13 $
  10 --                                                                          --
     --          Copyright (C) 1992-2001, Free Software Foundation, Inc.         --
     --                                                                          --
     -- GNAT is free software;  you can  redistribute it  and/or modify it under --
     -- terms of the  GNU General Public License as published  by the Free Soft- --
  15 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
     -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
     -- OUT 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 --
  20 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
     -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
     -- MA 02111-1307, USA.                                                      --
     --                                                                          --
     -- As a special exception,  if other files  instantiate  generics from this --
  25 -- unit, or you link  this unit with other files  to produce an executable, --
     -- this  unit  does not  by itself cause  the resulting  executable  to  be --
     -- covered  by the  GNU  General  Public  License.  This exception does not --
     -- however invalidate  any other reasons why  the executable file  might be --
     -- covered by the  GNU Public License.                                      --
  30 --                                                                          --
     -- GNAT was originally developed  by the GNAT team at  New York University. --
     -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
     --                                                                          --
     ------------------------------------------------------------------------------
  35 
     with GNAT.Case_Util; use GNAT.Case_Util;
     
     package body System.Val_Util is
     
  40    ----------------------
        -- Normalize_String --
        ----------------------
     
        procedure Normalize_String
  45      (S    : in out String;
           F, L : out Integer)
        is
        begin
           F := S'First;
  50       L := S'Last;
     
           --  Scan for leading spaces
     
           while F <= L and then S (F) = ' ' loop
  55          F := F + 1;
           end loop;
     
           --  Check for case when the string contained no characters
     
  60       if F > L then
              raise Constraint_Error;
           end if;
     
           --  Scan for trailing spaces
  65 
           while S (L) = ' ' loop
              L := L - 1;
           end loop;
     
  70       --  Except in the case of a character literal, convert to upper case
     
           if S (F) /= ''' then
              for J in F .. L loop
                 S (J) := To_Upper (S (J));
  75          end loop;
           end if;
     
        end Normalize_String;
     
  80    -------------------
        -- Scan_Exponent --
        -------------------
     
        function Scan_Exponent
  85      (Str  : String;
           Ptr  : access Integer;
           Max  : Integer;
           Real : Boolean := False)
           return Integer
  90    is
           P : Natural := Ptr.all;
           M : Boolean;
           X : Integer;
     
  95    begin
           if P >= Max
             or else (Str (P) /= 'E' and then Str (P) /= 'e')
           then
              return 0;
 100       end if;
     
           --  We have an E/e, see if sign follows
     
           P := P + 1;
 105 
           if Str (P) = '+' then
              P := P + 1;
     
              if P > Max then
 110             return 0;
              else
                 M := False;
              end if;
     
 115       elsif Str (P) = '-' then
              P := P + 1;
     
              if P > Max or else not Real then
                 return 0;
 120          else
                 M := True;
              end if;
     
           else
 125          M := False;
           end if;
     
           if Str (P) not in '0' .. '9' then
              return 0;
 130       end if;
     
           --  Scan out the exponent value as an unsigned integer. Values larger
           --  than (Integer'Last / 10) are simply considered large enough here.
           --  This assumption is correct for all machines we know of (e.g. in
 135       --  the case of 16 bit integers it allows exponents up to 3276, which
           --  is large enough for the largest floating types in base 2.)
     
           X := 0;
     
 140       loop
              if X < (Integer'Last / 10) then
                 X := X * 10 + (Character'Pos (Str (P)) - Character'Pos ('0'));
              end if;
     
 145          P := P + 1;
     
              exit when P > Max;
     
              if Str (P) = '_' then
 150             Scan_Underscore (Str, P, Ptr, Max, False);
              else
                 exit when Str (P) not in '0' .. '9';
              end if;
           end loop;
 155 
           if M then
              X := -X;
           end if;
     
 160       Ptr.all := P;
           return X;
     
        end Scan_Exponent;
     
 165    ---------------
        -- Scan_Sign --
        ---------------
     
        procedure Scan_Sign
 170      (Str   : String;
           Ptr   : access Integer;
           Max   : Integer;
           Minus : out Boolean;
           Start : out Positive)
 175    is
           P : Natural := Ptr.all;
     
        begin
           --  Deal with case of null string (all blanks!). As per spec, we
 180       --  raise constraint error, with Ptr unchanged, and thus > Max.
     
           if P > Max then
              raise Constraint_Error;
           end if;
 185 
           --  Scan past initial blanks
     
           while Str (P) = ' ' loop
              P := P + 1;
 190 
              if P > Max then
                 Ptr.all := P;
                 raise Constraint_Error;
              end if;
 195       end loop;
     
           Start := P;
     
           --  Remember an initial minus sign
 200 
           if Str (P) = '-' then
              Minus := True;
              P := P + 1;
     
 205          if P > Max then
                 Ptr.all := Start;
                 raise Constraint_Error;
              end if;
     
 210       --  Skip past an initial plus sign
     
           elsif Str (P) = '+' then
              Minus := False;
              P := P + 1;
 215 
              if P > Max then
                 Ptr.all := Start;
                 raise Constraint_Error;
              end if;
 220 
           else
              Minus := False;
           end if;
     
 225       Ptr.all := P;
        end Scan_Sign;
     
        --------------------------
        -- Scan_Trailing_Blanks --
 230    --------------------------
     
        procedure Scan_Trailing_Blanks (Str : String; P : Positive) is
        begin
           for J in P .. Str'Last loop
 235          if Str (J) /= ' ' then
                 raise Constraint_Error;
              end if;
           end loop;
        end Scan_Trailing_Blanks;
 240 
        ---------------------
        -- Scan_Underscore --
        ---------------------
     
 245    procedure Scan_Underscore
          (Str : String;
           P   : in out Natural;
           Ptr : access Integer;
           Max : Integer;
 250       Ext : Boolean)
        is
           C : Character;
     
        begin
 255       P := P + 1;
     
           --  If underscore is at the end of string, then this is an error and
           --  we raise Constraint_Error, leaving the pointer past the undescore.
           --  This seems a bit strange. It means e,g, that if the field is:
 260 
           --    345_
     
           --  that Constraint_Error is raised. You might think that the RM in
           --  this case would scan out the 345 as a valid integer, leaving the
 265       --  pointer at the underscore, but the ACVC suite clearly requires
           --  an error in this situation (see for example CE3704M).
     
           if P > Max then
              Ptr.all := P;
 270          raise Constraint_Error;
           end if;
     
           --  Similarly, if no digit follows the underscore raise an error. This
           --  also catches the case of double underscore which is also an error.
 275 
           C := Str (P);
     
           if C in '0' .. '9'
             or else
 280           (Ext and then (C in 'A' .. 'F' or else C in 'a' .. 'f'))
           then
              return;
           else
              Ptr.all := P;
 285          raise Constraint_Error;
           end if;
        end Scan_Underscore;
     
     end System.Val_Util;