OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [a-teioed.adb] - Rev 729

Go to most recent revision | Compare with Previous | Blame | View Log

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT RUN-TIME COMPONENTS                         --
--                                                                          --
--                  A D A . T E X T _ I O . E D I T I N G                   --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 1992-2009, 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- --
-- ware  Foundation;  either version 3,  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.                                     --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------
 
with Ada.Strings.Fixed;
package body Ada.Text_IO.Editing is
 
   package Strings renames Ada.Strings;
   package Strings_Fixed renames Ada.Strings.Fixed;
   package Text_IO renames Ada.Text_IO;
 
   ---------------------
   -- Blank_When_Zero --
   ---------------------
 
   function Blank_When_Zero (Pic : Picture) return Boolean is
   begin
      return Pic.Contents.Original_BWZ;
   end Blank_When_Zero;
 
   ------------
   -- Expand --
   ------------
 
   function Expand (Picture : String) return String is
      Result        : String (1 .. MAX_PICSIZE);
      Picture_Index : Integer := Picture'First;
      Result_Index  : Integer := Result'First;
      Count         : Natural;
      Last          : Integer;
 
      package Int_IO is new Ada.Text_IO.Integer_IO (Integer);
 
   begin
      if Picture'Length < 1 then
         raise Picture_Error;
      end if;
 
      if Picture (Picture'First) = '(' then
         raise Picture_Error;
      end if;
 
      loop
         case Picture (Picture_Index) is
 
            when '(' =>
               Int_IO.Get
                 (Picture (Picture_Index + 1 .. Picture'Last), Count, Last);
 
               if Picture (Last + 1) /= ')' then
                  raise Picture_Error;
               end if;
 
               --  In what follows note that one copy of the repeated character
               --  has already been made, so a count of one is a no-op, and a
               --  count of zero erases a character.
 
               if Result_Index + Count - 2 > Result'Last then
                  raise Picture_Error;
               end if;
 
               for J in 2 .. Count loop
                  Result (Result_Index + J - 2) := Picture (Picture_Index - 1);
               end loop;
 
               Result_Index := Result_Index + Count - 1;
 
               --  Last + 1 was a ')' throw it away too
 
               Picture_Index := Last + 2;
 
            when ')' =>
               raise Picture_Error;
 
            when others =>
               if Result_Index > Result'Last then
                  raise Picture_Error;
               end if;
 
               Result (Result_Index) := Picture (Picture_Index);
               Picture_Index := Picture_Index + 1;
               Result_Index := Result_Index + 1;
 
         end case;
 
         exit when Picture_Index > Picture'Last;
      end loop;
 
      return Result (1 .. Result_Index - 1);
 
   exception
      when others =>
         raise Picture_Error;
   end Expand;
 
   -------------------
   -- Format_Number --
   -------------------
 
   function Format_Number
     (Pic                 : Format_Record;
      Number              : String;
      Currency_Symbol     : String;
      Fill_Character      : Character;
      Separator_Character : Character;
      Radix_Point         : Character) return String
   is
      Attrs    : Number_Attributes := Parse_Number_String (Number);
      Position : Integer;
      Rounded  : String := Number;
 
      Sign_Position : Integer := Pic.Sign_Position; --  may float.
 
      Answer : String (1 .. Pic.Picture.Length) := Pic.Picture.Expanded;
      Last          : Integer;
      Currency_Pos  : Integer := Pic.Start_Currency;
      In_Currency   : Boolean := False;
 
      Dollar : Boolean := False;
      --  Overridden immediately if necessary
 
      Zero : Boolean := True;
      --  Set to False when a non-zero digit is output
 
   begin
 
      --  If the picture has fewer decimal places than the number, the image
      --  must be rounded according to the usual rules.
 
      if Attrs.Has_Fraction then
         declare
            R : constant Integer :=
              (Attrs.End_Of_Fraction - Attrs.Start_Of_Fraction + 1)
                - Pic.Max_Trailing_Digits;
            R_Pos : Integer;
 
         begin
            if R > 0 then
               R_Pos := Attrs.End_Of_Fraction - R;
 
               if Rounded (R_Pos + 1) > '4' then
 
                  if Rounded (R_Pos) = '.' then
                     R_Pos := R_Pos - 1;
                  end if;
 
                  if Rounded (R_Pos) /= '9' then
                     Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
                  else
                     Rounded (R_Pos) := '0';
                     R_Pos := R_Pos - 1;
 
                     while R_Pos > 1 loop
                        if Rounded (R_Pos) = '.' then
                           R_Pos := R_Pos - 1;
                        end if;
 
                        if Rounded (R_Pos) /= '9' then
                           Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
                           exit;
                        else
                           Rounded (R_Pos) := '0';
                           R_Pos := R_Pos - 1;
                        end if;
                     end loop;
 
                     --  The rounding may add a digit in front. Either the
                     --  leading blank or the sign (already captured) can
                     --  be overwritten.
 
                     if R_Pos = 1 then
                        Rounded (R_Pos) := '1';
                        Attrs.Start_Of_Int := Attrs.Start_Of_Int - 1;
                     end if;
                  end if;
               end if;
            end if;
         end;
      end if;
 
      if Pic.Start_Currency /= Invalid_Position then
         Dollar := Answer (Pic.Start_Currency) = '$';
      end if;
 
      --  Fix up "direct inserts" outside the playing field. Set up as one
      --  loop to do the beginning, one (reverse) loop to do the end.
 
      Last := 1;
      loop
         exit when Last = Pic.Start_Float;
         exit when Last = Pic.Radix_Position;
         exit when Answer (Last) = '9';
 
         case Answer (Last) is
 
            when '_' =>
               Answer (Last) := Separator_Character;
 
            when 'b' =>
               Answer (Last) := ' ';
 
            when others =>
               null;
 
         end case;
 
         exit when Last = Answer'Last;
 
         Last := Last + 1;
      end loop;
 
      --  Now for the end...
 
      for J in reverse Last .. Answer'Last loop
         exit when J = Pic.Radix_Position;
 
         --  Do this test First, Separator_Character can equal Pic.Floater
 
         if Answer (J) = Pic.Floater then
            exit;
         end if;
 
         case Answer (J) is
 
            when '_' =>
               Answer (J) := Separator_Character;
 
            when 'b' =>
               Answer (J) := ' ';
 
            when '9' =>
               exit;
 
            when others =>
               null;
 
         end case;
      end loop;
 
      --  Non-floating sign
 
      if Pic.Start_Currency /= -1
        and then Answer (Pic.Start_Currency) = '#'
        and then Pic.Floater /= '#'
      then
         if Currency_Symbol'Length >
            Pic.End_Currency - Pic.Start_Currency + 1
         then
            raise Picture_Error;
 
         elsif Currency_Symbol'Length =
            Pic.End_Currency - Pic.Start_Currency + 1
         then
            Answer (Pic.Start_Currency .. Pic.End_Currency) :=
              Currency_Symbol;
 
         elsif Pic.Radix_Position = Invalid_Position
           or else Pic.Start_Currency < Pic.Radix_Position
         then
            Answer (Pic.Start_Currency .. Pic.End_Currency) :=
                                                        (others => ' ');
            Answer (Pic.End_Currency - Currency_Symbol'Length + 1 ..
                    Pic.End_Currency) := Currency_Symbol;
 
         else
            Answer (Pic.Start_Currency .. Pic.End_Currency) :=
                                                        (others => ' ');
            Answer (Pic.Start_Currency ..
                    Pic.Start_Currency + Currency_Symbol'Length - 1) :=
                                                        Currency_Symbol;
         end if;
      end if;
 
      --  Fill in leading digits
 
      if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
                                                Pic.Max_Leading_Digits
      then
         raise Ada.Text_IO.Layout_Error;
      end if;
 
      Position :=
        (if Pic.Radix_Position = Invalid_Position
         then Answer'Last
         else Pic.Radix_Position - 1);
 
      for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop
         while Answer (Position) /= '9'
                 and then
               Answer (Position) /= Pic.Floater
         loop
            if Answer (Position) = '_' then
               Answer (Position) := Separator_Character;
 
            elsif Answer (Position) = 'b' then
               Answer (Position) := ' ';
            end if;
 
            Position := Position - 1;
         end loop;
 
         Answer (Position) := Rounded (J);
 
         if Rounded (J) /= '0' then
            Zero := False;
         end if;
 
         Position := Position - 1;
      end loop;
 
      --  Do lead float
 
      if Pic.Start_Float = Invalid_Position then
 
         --  No leading floats, but need to change '9' to '0', '_' to
         --  Separator_Character and 'b' to ' '.
 
         for J in Last .. Position loop
 
            --  Last set when fixing the "uninteresting" leaders above.
            --  Don't duplicate the work.
 
            if Answer (J) = '9' then
               Answer (J) := '0';
 
            elsif Answer (J) = '_' then
               Answer (J) := Separator_Character;
 
            elsif Answer (J) = 'b' then
               Answer (J) := ' ';
            end if;
         end loop;
 
      elsif Pic.Floater = '<'
              or else
            Pic.Floater = '+'
              or else
            Pic.Floater = '-'
      then
         for J in Pic.End_Float .. Position loop --  May be null range.
            if Answer (J) = '9' then
               Answer (J) := '0';
 
            elsif Answer (J) = '_' then
               Answer (J) := Separator_Character;
 
            elsif Answer (J) = 'b' then
               Answer (J) := ' ';
            end if;
         end loop;
 
         if Position > Pic.End_Float then
            Position := Pic.End_Float;
         end if;
 
         for J in Pic.Start_Float .. Position - 1 loop
            Answer (J) := ' ';
         end loop;
 
         Answer (Position) := Pic.Floater;
         Sign_Position     := Position;
 
      elsif Pic.Floater = '$' then
 
         for J in Pic.End_Float .. Position loop --  May be null range.
            if Answer (J) = '9' then
               Answer (J) := '0';
 
            elsif Answer (J) = '_' then
               Answer (J) := ' ';    --  no separators before leftmost digit.
 
            elsif Answer (J) = 'b' then
               Answer (J) := ' ';
            end if;
         end loop;
 
         if Position > Pic.End_Float then
            Position := Pic.End_Float;
         end if;
 
         for J in Pic.Start_Float .. Position - 1 loop
            Answer (J) := ' ';
         end loop;
 
         Answer (Position) := Pic.Floater;
         Currency_Pos      := Position;
 
      elsif Pic.Floater = '*' then
 
         for J in Pic.End_Float .. Position loop --  May be null range.
            if Answer (J) = '9' then
               Answer (J) := '0';
 
            elsif Answer (J) = '_' then
               Answer (J) := Separator_Character;
 
            elsif Answer (J) = 'b' then
               Answer (J) := Fill_Character;
            end if;
         end loop;
 
         if Position > Pic.End_Float then
            Position := Pic.End_Float;
         end if;
 
         for J in Pic.Start_Float .. Position loop
            Answer (J) := Fill_Character;
         end loop;
 
      else
         if Pic.Floater = '#' then
            Currency_Pos := Currency_Symbol'Length;
            In_Currency := True;
         end if;
 
         for J in reverse Pic.Start_Float .. Position loop
            case Answer (J) is
 
               when '*' =>
                  Answer (J) := Fill_Character;
 
               when 'b' | '/' =>
                  if In_Currency and then Currency_Pos > 0 then
                     Answer (J)   := Currency_Symbol (Currency_Pos);
                     Currency_Pos := Currency_Pos - 1;
                  else
                     Answer (J) := ' ';
                  end if;
 
               when 'Z' | '0' =>
                  Answer (J) := ' ';
 
               when '9' =>
                  Answer (J) := '0';
 
               when '.' | 'V' | 'v' | '<' | '$' | '+' | '-' =>
                  null;
 
               when '#' =>
                  if Currency_Pos = 0 then
                     Answer (J) := ' ';
                  else
                     Answer (J)   := Currency_Symbol (Currency_Pos);
                     Currency_Pos := Currency_Pos - 1;
                  end if;
 
               when '_' =>
 
                  case Pic.Floater is
 
                     when '*' =>
                        Answer (J) := Fill_Character;
 
                     when 'Z' | 'b' =>
                        Answer (J) := ' ';
 
                     when '#' =>
                        if Currency_Pos = 0 then
                           Answer (J) := ' ';
 
                        else
                           Answer (J)   := Currency_Symbol (Currency_Pos);
                           Currency_Pos := Currency_Pos - 1;
                        end if;
 
                     when others =>
                        null;
 
                  end case;
 
               when others =>
                  null;
 
            end case;
         end loop;
 
         if Pic.Floater = '#' and then Currency_Pos /= 0 then
            raise Ada.Text_IO.Layout_Error;
         end if;
      end if;
 
      --  Do sign
 
      if Sign_Position = Invalid_Position then
         if Attrs.Negative then
            raise Ada.Text_IO.Layout_Error;
         end if;
 
      else
         if Attrs.Negative then
            case Answer (Sign_Position) is
               when 'C' | 'D' | '-' =>
                  null;
 
               when '+' =>
                  Answer (Sign_Position) := '-';
 
               when '<' =>
                  Answer (Sign_Position)   := '(';
                  Answer (Pic.Second_Sign) := ')';
 
               when others =>
                  raise Picture_Error;
 
            end case;
 
         else --  positive
 
            case Answer (Sign_Position) is
 
               when '-' =>
                  Answer (Sign_Position) := ' ';
 
               when '<' | 'C' | 'D' =>
                  Answer (Sign_Position)   := ' ';
                  Answer (Pic.Second_Sign) := ' ';
 
               when '+' =>
                  null;
 
               when others =>
                  raise Picture_Error;
 
            end case;
         end if;
      end if;
 
      --  Fill in trailing digits
 
      if Pic.Max_Trailing_Digits > 0 then
 
         if Attrs.Has_Fraction then
            Position := Attrs.Start_Of_Fraction;
            Last     := Pic.Radix_Position + 1;
 
            for J in Last .. Answer'Last loop
               if Answer (J) = '9' or else Answer (J) = Pic.Floater then
                  Answer (J) := Rounded (Position);
 
                  if Rounded (Position) /= '0' then
                     Zero := False;
                  end if;
 
                  Position := Position + 1;
                  Last     := J + 1;
 
                  --  Used up fraction but remember place in Answer
 
                  exit when Position > Attrs.End_Of_Fraction;
 
               elsif Answer (J) = 'b' then
                  Answer (J) := ' ';
 
               elsif Answer (J) = '_' then
                  Answer (J) := Separator_Character;
 
               end if;
 
               Last := J + 1;
            end loop;
 
            Position := Last;
 
         else
            Position := Pic.Radix_Position + 1;
         end if;
 
         --  Now fill remaining 9's with zeros and _ with separators
 
         Last := Answer'Last;
 
         for J in Position .. Last loop
            if Answer (J) = '9' then
               Answer (J) := '0';
 
            elsif Answer (J) = Pic.Floater then
               Answer (J) := '0';
 
            elsif Answer (J) = '_' then
               Answer (J) := Separator_Character;
 
            elsif Answer (J) = 'b' then
               Answer (J) := ' ';
 
            end if;
         end loop;
 
         Position := Last + 1;
 
      else
         if Pic.Floater = '#' and then Currency_Pos /= 0 then
            raise Ada.Text_IO.Layout_Error;
         end if;
 
         --  No trailing digits, but now J may need to stick in a currency
         --  symbol or sign.
 
         Position :=
           (if Pic.Start_Currency = Invalid_Position
            then Answer'Last + 1
            else Pic.Start_Currency);
      end if;
 
      for J in Position .. Answer'Last loop
         if Pic.Start_Currency /= Invalid_Position and then
            Answer (Pic.Start_Currency) = '#' then
            Currency_Pos := 1;
         end if;
 
         case Answer (J) is
            when '*' =>
               Answer (J) := Fill_Character;
 
            when 'b' =>
               if In_Currency then
                  Answer (J) := Currency_Symbol (Currency_Pos);
                  Currency_Pos := Currency_Pos + 1;
 
                  if Currency_Pos > Currency_Symbol'Length then
                     In_Currency := False;
                  end if;
               end if;
 
            when '#' =>
               if Currency_Pos > Currency_Symbol'Length then
                  Answer (J) := ' ';
 
               else
                  In_Currency := True;
                  Answer (J)   := Currency_Symbol (Currency_Pos);
                  Currency_Pos := Currency_Pos + 1;
 
                  if Currency_Pos > Currency_Symbol'Length then
                     In_Currency := False;
                  end if;
               end if;
 
            when '_' =>
               Answer (J) := Currency_Symbol (Currency_Pos);
               Currency_Pos := Currency_Pos + 1;
 
               case Pic.Floater is
 
                  when '*' =>
                     Answer (J) := Fill_Character;
 
                  when 'Z' | 'z' =>
                     Answer (J) := ' ';
 
                  when '#' =>
                     if Currency_Pos > Currency_Symbol'Length then
                        Answer (J) := ' ';
                     else
                        Answer (J)   := Currency_Symbol (Currency_Pos);
                        Currency_Pos := Currency_Pos + 1;
                     end if;
 
                  when others =>
                     null;
 
               end case;
 
            when others =>
               exit;
 
         end case;
      end loop;
 
      --  Now get rid of Blank_when_Zero and complete Star fill
 
      if Zero and then Pic.Blank_When_Zero then
 
         --  Value is zero, and blank it
 
         Last := Answer'Last;
 
         if Dollar then
            Last := Last - 1 + Currency_Symbol'Length;
         end if;
 
         if Pic.Radix_Position /= Invalid_Position and then
            Answer (Pic.Radix_Position) = 'V' then
            Last := Last - 1;
         end if;
 
         return String'(1 .. Last => ' ');
 
      elsif Zero and then Pic.Star_Fill then
         Last := Answer'Last;
 
         if Dollar then
            Last := Last - 1 + Currency_Symbol'Length;
         end if;
 
         if Pic.Radix_Position /= Invalid_Position then
 
            if Answer (Pic.Radix_Position) = 'V' then
               Last := Last - 1;
 
            elsif Dollar then
               if Pic.Radix_Position > Pic.Start_Currency then
                  return String'(1 .. Pic.Radix_Position - 1 => '*') &
                     Radix_Point &
                     String'(Pic.Radix_Position + 1 .. Last => '*');
 
               else
                  return
                     String'
                     (1 ..
                      Pic.Radix_Position + Currency_Symbol'Length - 2 =>
                         '*') & Radix_Point &
                     String'
                     (Pic.Radix_Position + Currency_Symbol'Length .. Last
                      => '*');
               end if;
 
            else
               return String'(1 .. Pic.Radix_Position - 1 => '*') &
                  Radix_Point &
                  String'(Pic.Radix_Position + 1 .. Last => '*');
            end if;
         end if;
 
         return String'(1 .. Last => '*');
      end if;
 
      --  This was once a simple return statement, now there are nine
      --  different return cases.  Not to mention the five above to deal
      --  with zeros.  Why not split things out?
 
      --  Processing the radix and sign expansion separately
      --  would require lots of copying--the string and some of its
      --  indicies--without really simplifying the logic.  The cases are:
 
      --  1) Expand $, replace '.' with Radix_Point
      --  2) No currency expansion, replace '.' with Radix_Point
      --  3) Expand $, radix blanked
      --  4) No currency expansion, radix blanked
      --  5) Elide V
      --  6) Expand $, Elide V
      --  7) Elide V, Expand $ (Two cases depending on order.)
      --  8) No radix, expand $
      --  9) No radix, no currency expansion
 
      if Pic.Radix_Position /= Invalid_Position then
 
         if Answer (Pic.Radix_Position) = '.' then
            Answer (Pic.Radix_Position) := Radix_Point;
 
            if Dollar then
 
               --  1) Expand $, replace '.' with Radix_Point
 
               return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
                  Answer (Currency_Pos + 1 .. Answer'Last);
 
            else
               --  2) No currency expansion, replace '.' with Radix_Point
 
               return Answer;
            end if;
 
         elsif Answer (Pic.Radix_Position) = ' ' then --  blanked radix.
            if Dollar then
 
               --  3) Expand $, radix blanked
 
               return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
                 Answer (Currency_Pos + 1 .. Answer'Last);
 
            else
               --  4) No expansion, radix blanked
 
               return Answer;
            end if;
 
         --  V cases
 
         else
            if not Dollar then
 
               --  5) Elide V
 
               return Answer (1 .. Pic.Radix_Position - 1) &
                  Answer (Pic.Radix_Position + 1 .. Answer'Last);
 
            elsif Currency_Pos < Pic.Radix_Position then
 
               --  6) Expand $, Elide V
 
               return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
                  Answer (Currency_Pos + 1 .. Pic.Radix_Position - 1) &
                  Answer (Pic.Radix_Position + 1 .. Answer'Last);
 
            else
               --  7) Elide V, Expand $
 
               return Answer (1 .. Pic.Radix_Position - 1) &
                  Answer (Pic.Radix_Position + 1 .. Currency_Pos - 1) &
                  Currency_Symbol &
                  Answer (Currency_Pos + 1 .. Answer'Last);
            end if;
         end if;
 
      elsif Dollar then
 
         --  8) No radix, expand $
 
         return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
            Answer (Currency_Pos + 1 .. Answer'Last);
 
      else
         --  9) No radix, no currency expansion
 
         return Answer;
      end if;
   end Format_Number;
 
   -------------------------
   -- Parse_Number_String --
   -------------------------
 
   function Parse_Number_String (Str : String) return Number_Attributes is
      Answer : Number_Attributes;
 
   begin
      for J in Str'Range loop
         case Str (J) is
 
            when ' ' =>
               null; --  ignore
 
            when '1' .. '9' =>
 
               --  Decide if this is the start of a number.
               --  If so, figure out which one...
 
               if Answer.Has_Fraction then
                  Answer.End_Of_Fraction := J;
               else
                  if Answer.Start_Of_Int = Invalid_Position then
                     --  start integer
                     Answer.Start_Of_Int := J;
                  end if;
                  Answer.End_Of_Int := J;
               end if;
 
            when '0' =>
 
               --  Only count a zero before the decimal point if it follows a
               --  non-zero digit.  After the decimal point, zeros will be
               --  counted if followed by a non-zero digit.
 
               if not Answer.Has_Fraction then
                  if Answer.Start_Of_Int /= Invalid_Position then
                     Answer.End_Of_Int := J;
                  end if;
               end if;
 
            when '-' =>
 
               --  Set negative
 
               Answer.Negative := True;
 
            when '.' =>
 
               --  Close integer, start fraction
 
               if Answer.Has_Fraction then
                  raise Picture_Error;
               end if;
 
               --  Two decimal points is a no-no
 
               Answer.Has_Fraction    := True;
               Answer.End_Of_Fraction := J;
 
               --  Could leave this at Invalid_Position, but this seems the
               --  right way to indicate a null range...
 
               Answer.Start_Of_Fraction := J + 1;
               Answer.End_Of_Int        := J - 1;
 
            when others =>
               raise Picture_Error; -- can this happen? probably not!
         end case;
      end loop;
 
      if Answer.Start_Of_Int = Invalid_Position then
         Answer.Start_Of_Int := Answer.End_Of_Int + 1;
      end if;
 
      --  No significant (integer) digits needs a null range
 
      return Answer;
   end Parse_Number_String;
 
   ----------------
   -- Pic_String --
   ----------------
 
   --  The following ensures that we return B and not b being careful not
   --  to break things which expect lower case b for blank. See CXF3A02.
 
   function Pic_String (Pic : Picture) return String is
      Temp : String (1 .. Pic.Contents.Picture.Length) :=
                              Pic.Contents.Picture.Expanded;
   begin
      for J in Temp'Range loop
         if Temp (J) = 'b' then
            Temp (J) := 'B';
         end if;
      end loop;
 
      return Temp;
   end Pic_String;
 
   ------------------
   -- Precalculate --
   ------------------
 
   procedure Precalculate  (Pic : in out Format_Record) is
      Debug : constant Boolean := False;
      --  Set True to generate debug output
 
      Computed_BWZ : Boolean := True;
 
      type Legality is  (Okay, Reject);
 
      State : Legality := Reject;
      --  Start in reject, which will reject null strings
 
      Index : Pic_Index := Pic.Picture.Expanded'First;
 
      function At_End return Boolean;
      pragma Inline (At_End);
 
      procedure Set_State (L : Legality);
      pragma Inline (Set_State);
 
      function Look return Character;
      pragma Inline (Look);
 
      function Is_Insert return Boolean;
      pragma Inline (Is_Insert);
 
      procedure Skip;
      pragma Inline (Skip);
 
      procedure Debug_Start (Name : String);
      pragma Inline (Debug_Start);
 
      procedure Debug_Integer  (Value : Integer; S : String);
      pragma Inline (Debug_Integer);
 
      procedure Trailing_Currency;
      procedure Trailing_Bracket;
      procedure Number_Fraction;
      procedure Number_Completion;
      procedure Number_Fraction_Or_Bracket;
      procedure Number_Fraction_Or_Z_Fill;
      procedure Zero_Suppression;
      procedure Floating_Bracket;
      procedure Number_Fraction_Or_Star_Fill;
      procedure Star_Suppression;
      procedure Number_Fraction_Or_Dollar;
      procedure Leading_Dollar;
      procedure Number_Fraction_Or_Pound;
      procedure Leading_Pound;
      procedure Picture;
      procedure Floating_Plus;
      procedure Floating_Minus;
      procedure Picture_Plus;
      procedure Picture_Minus;
      procedure Picture_Bracket;
      procedure Number;
      procedure Optional_RHS_Sign;
      procedure Picture_String;
      procedure Set_Debug;
 
      ------------
      -- At_End --
      ------------
 
      function At_End return Boolean is
      begin
         Debug_Start ("At_End");
         return Index > Pic.Picture.Length;
      end At_End;
 
      --------------
      -- Set_Debug--
      --------------
 
      --  Needed to have a procedure to pass to pragma Debug
 
      procedure Set_Debug is
      begin
         --  Uncomment this line and make Debug a variable to enable debug
 
         --  Debug := True;
 
         null;
      end Set_Debug;
 
      -------------------
      -- Debug_Integer --
      -------------------
 
      procedure Debug_Integer (Value : Integer; S : String) is
         use Ada.Text_IO; --  needed for >
 
      begin
         if Debug and then Value > 0 then
            if Ada.Text_IO.Col > 70 - S'Length then
               Ada.Text_IO.New_Line;
            end if;
 
            Ada.Text_IO.Put (' ' & S & Integer'Image (Value) & ',');
         end if;
      end Debug_Integer;
 
      -----------------
      -- Debug_Start --
      -----------------
 
      procedure Debug_Start (Name : String) is
      begin
         if Debug then
            Ada.Text_IO.Put_Line ("  In " & Name & '.');
         end if;
      end Debug_Start;
 
      ----------------------
      -- Floating_Bracket --
      ----------------------
 
      --  Note that Floating_Bracket is only called with an acceptable
      --  prefix. But we don't set Okay, because we must end with a '>'.
 
      procedure Floating_Bracket is
      begin
         Debug_Start ("Floating_Bracket");
 
         --  Two different floats not allowed
 
         if Pic.Floater /= '!' and then Pic.Floater /= '<' then
            raise Picture_Error;
 
         else
            Pic.Floater := '<';
         end if;
 
         Pic.End_Float := Index;
         Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
 
         --  First bracket wasn't counted...
 
         Skip; --  known '<'
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '<' =>
                  Pic.End_Float := Index;
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Skip;
 
               when '9' =>
                  Number_Completion;
 
               when '$' =>
                  Leading_Dollar;
 
               when '#' =>
                  Leading_Pound;
 
               when 'V' | 'v' | '.' =>
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction_Or_Bracket;
                  return;
 
               when others =>
               return;
            end case;
         end loop;
      end Floating_Bracket;
 
      --------------------
      -- Floating_Minus --
      --------------------
 
      procedure Floating_Minus is
      begin
         Debug_Start ("Floating_Minus");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '-' =>
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
 
               when '9' =>
                  Number_Completion;
                  return;
 
               when '.' | 'V' | 'v' =>
                  Pic.Radix_Position := Index;
                  Skip; --  Radix
 
                  while Is_Insert loop
                     Skip;
                  end loop;
 
                  if At_End then
                     return;
                  end if;
 
                  if Look = '-' then
                     loop
                        if At_End then
                           return;
                        end if;
 
                        case Look is
 
                           when '-' =>
                              Pic.Max_Trailing_Digits :=
                                Pic.Max_Trailing_Digits + 1;
                              Pic.End_Float := Index;
                              Skip;
 
                           when '_' | '0' | '/' =>
                              Skip;
 
                           when 'B' | 'b'  =>
                              Pic.Picture.Expanded (Index) := 'b';
                              Skip;
 
                           when others =>
                              return;
 
                        end case;
                     end loop;
 
                  else
                     Number_Completion;
                  end if;
 
                  return;
 
               when others =>
                  return;
            end case;
         end loop;
      end Floating_Minus;
 
      -------------------
      -- Floating_Plus --
      -------------------
 
      procedure Floating_Plus is
      begin
         Debug_Start ("Floating_Plus");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '+' =>
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
 
               when '9' =>
                  Number_Completion;
                  return;
 
               when '.' | 'V' | 'v' =>
                  Pic.Radix_Position := Index;
                  Skip; --  Radix
 
                  while Is_Insert loop
                     Skip;
                  end loop;
 
                  if At_End then
                     return;
                  end if;
 
                  if Look = '+' then
                     loop
                        if At_End then
                           return;
                        end if;
 
                        case Look is
 
                           when '+' =>
                              Pic.Max_Trailing_Digits :=
                                Pic.Max_Trailing_Digits + 1;
                              Pic.End_Float := Index;
                              Skip;
 
                           when '_' | '0' | '/' =>
                              Skip;
 
                           when 'B' | 'b'  =>
                              Pic.Picture.Expanded (Index) := 'b';
                              Skip;
 
                           when others =>
                              return;
 
                        end case;
                     end loop;
 
                  else
                     Number_Completion;
                  end if;
 
                  return;
 
               when others =>
                  return;
 
            end case;
         end loop;
      end Floating_Plus;
 
      ---------------
      -- Is_Insert --
      ---------------
 
      function Is_Insert return Boolean is
      begin
         if At_End then
            return False;
         end if;
 
         case Pic.Picture.Expanded (Index) is
 
            when '_' | '0' | '/' => return True;
 
            when 'B' | 'b' =>
               Pic.Picture.Expanded (Index) := 'b'; --  canonical
               return True;
 
            when others => return False;
         end case;
      end Is_Insert;
 
      --------------------
      -- Leading_Dollar --
      --------------------
 
      --  Note that Leading_Dollar can be called in either State.
      --  It will set state to Okay only if a 9 or (second) $
      --  is encountered.
 
      --  Also notice the tricky bit with State and Zero_Suppression.
      --  Zero_Suppression is Picture_Error if a '$' or a '9' has been
      --  encountered, exactly the cases where State has been set.
 
      procedure Leading_Dollar is
      begin
         Debug_Start ("Leading_Dollar");
 
         --  Treat as a floating dollar, and unwind otherwise
 
         if Pic.Floater /= '!' and then Pic.Floater /= '$' then
 
            --  Two floats not allowed
 
            raise Picture_Error;
 
         else
            Pic.Floater := '$';
         end if;
 
         Pic.Start_Currency := Index;
         Pic.End_Currency := Index;
         Pic.Start_Float := Index;
         Pic.End_Float := Index;
 
         --  Don't increment Pic.Max_Leading_Digits, we need one "real"
         --  currency place.
 
         Skip; --  known '$'
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
                  --  A trailing insertion character is not part of the
                  --  floating currency, so need to look ahead.
 
                  if Look /= '$' then
                     Pic.End_Float := Pic.End_Float - 1;
                  end if;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when 'Z' | 'z' =>
                  Pic.Picture.Expanded (Index) := 'Z'; -- consistency
 
                  if State = Okay then
                     raise Picture_Error;
                  else
                     --  Overwrite Floater and Start_Float
 
                     Pic.Floater := 'Z';
                     Pic.Start_Float := Index;
                     Zero_Suppression;
                  end if;
 
               when '*' =>
                  if State = Okay then
                     raise Picture_Error;
                  else
                     --  Overwrite Floater and Start_Float
 
                     Pic.Floater := '*';
                     Pic.Start_Float := Index;
                     Star_Suppression;
                  end if;
 
               when '$' =>
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Pic.End_Float := Index;
                  Pic.End_Currency := Index;
                  Set_State (Okay); Skip;
 
               when '9' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  --  A single dollar does not a floating make
 
                  Number_Completion;
                  return;
 
               when 'V' | 'v' | '.' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  --  Only one dollar before the sign is okay, but doesn't
                  --  float.
 
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction_Or_Dollar;
                  return;
 
               when others =>
                  return;
 
            end case;
         end loop;
      end Leading_Dollar;
 
      -------------------
      -- Leading_Pound --
      -------------------
 
      --  This one is complex!  A Leading_Pound can be fixed or floating,
      --  but in some cases the decision has to be deferred until we leave
      --  this procedure.  Also note that Leading_Pound can be called in
      --  either State.
 
      --  It will set state to Okay only if a 9 or  (second) # is
      --  encountered.
 
      --  One Last note:  In ambiguous cases, the currency is treated as
      --  floating unless there is only one '#'.
 
      procedure Leading_Pound is
 
         Inserts : Boolean := False;
         --  Set to True if a '_', '0', '/', 'B', or 'b' is encountered
 
         Must_Float : Boolean := False;
         --  Set to true if a '#' occurs after an insert
 
      begin
         Debug_Start ("Leading_Pound");
 
         --  Treat as a floating currency. If it isn't, this will be
         --  overwritten later.
 
         if Pic.Floater /= '!' and then Pic.Floater /= '#' then
 
            --  Two floats not allowed
 
            raise Picture_Error;
 
         else
            Pic.Floater := '#';
         end if;
 
         Pic.Start_Currency := Index;
         Pic.End_Currency := Index;
         Pic.Start_Float := Index;
         Pic.End_Float := Index;
 
         --  Don't increment Pic.Max_Leading_Digits, we need one "real"
         --  currency place.
 
         Pic.Max_Currency_Digits := 1; --  we've seen one.
 
         Skip; --  known '#'
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Inserts := True;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Pic.End_Float := Index;
                  Inserts := True;
                  Skip;
 
               when 'Z' | 'z' =>
                  Pic.Picture.Expanded (Index) := 'Z'; -- consistency
 
                  if Must_Float then
                     raise Picture_Error;
                  else
                     Pic.Max_Leading_Digits := 0;
 
                     --  Overwrite Floater and Start_Float
 
                     Pic.Floater := 'Z';
                     Pic.Start_Float := Index;
                     Zero_Suppression;
                  end if;
 
               when '*' =>
                  if Must_Float then
                     raise Picture_Error;
                  else
                     Pic.Max_Leading_Digits := 0;
 
                     --  Overwrite Floater and Start_Float
                     Pic.Floater := '*';
                     Pic.Start_Float := Index;
                     Star_Suppression;
                  end if;
 
               when '#' =>
                  if Inserts then
                     Must_Float := True;
                  end if;
 
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Pic.End_Float := Index;
                  Pic.End_Currency := Index;
                  Set_State (Okay);
                  Skip;
 
               when '9' =>
                  if State /= Okay then
 
                     --  A single '#' doesn't float
 
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  Number_Completion;
                  return;
 
               when 'V' | 'v' | '.' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  --  Only one pound before the sign is okay, but doesn't
                  --  float.
 
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction_Or_Pound;
                  return;
 
               when others =>
                  return;
            end case;
         end loop;
      end Leading_Pound;
 
      ----------
      -- Look --
      ----------
 
      function Look return Character is
      begin
         if At_End then
            raise Picture_Error;
         end if;
 
         return Pic.Picture.Expanded (Index);
      end Look;
 
      ------------
      -- Number --
      ------------
 
      procedure Number is
      begin
         Debug_Start ("Number");
 
         loop
 
            case Look is
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '9' =>
                  Computed_BWZ := False;
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Set_State (Okay);
                  Skip;
 
               when '.' | 'V' | 'v' =>
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction;
                  return;
 
               when others =>
                  return;
 
            end case;
 
            if At_End then
               return;
            end if;
 
            --  Will return in Okay state if a '9' was seen
 
         end loop;
      end Number;
 
      -----------------------
      -- Number_Completion --
      -----------------------
 
      procedure Number_Completion is
      begin
         Debug_Start ("Number_Completion");
 
         while not At_End loop
            case Look is
 
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '9' =>
                  Computed_BWZ := False;
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Set_State (Okay);
                  Skip;
 
               when 'V' | 'v' | '.' =>
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction;
                  return;
 
               when others =>
                  return;
            end case;
         end loop;
      end Number_Completion;
 
      ---------------------
      -- Number_Fraction --
      ---------------------
 
      procedure Number_Fraction is
      begin
         --  Note that number fraction can be called in either State.
         --  It will set state to Valid only if a 9 is encountered.
 
         Debug_Start ("Number_Fraction");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '9' =>
                  Computed_BWZ := False;
                  Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
                  Set_State (Okay); Skip;
 
               when others =>
                  return;
            end case;
         end loop;
      end Number_Fraction;
 
      --------------------------------
      -- Number_Fraction_Or_Bracket --
      --------------------------------
 
      procedure Number_Fraction_Or_Bracket is
      begin
         Debug_Start ("Number_Fraction_Or_Bracket");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' => Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '<' =>
                  Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
 
                  loop
                     if At_End then
                        return;
                     end if;
 
                     case Look is
                        when '_' | '0' | '/' =>
                           Skip;
 
                        when 'B' | 'b'  =>
                           Pic.Picture.Expanded (Index) := 'b';
                           Skip;
 
                        when '<' =>
                           Pic.Max_Trailing_Digits :=
                             Pic.Max_Trailing_Digits + 1;
                           Pic.End_Float := Index;
                           Skip;
 
                        when others =>
                           return;
                     end case;
                  end loop;
 
               when others =>
                  Number_Fraction;
                  return;
            end case;
         end loop;
      end Number_Fraction_Or_Bracket;
 
      -------------------------------
      -- Number_Fraction_Or_Dollar --
      -------------------------------
 
      procedure Number_Fraction_Or_Dollar is
      begin
         Debug_Start ("Number_Fraction_Or_Dollar");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '$' =>
                  Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
 
                  loop
                     if At_End then
                        return;
                     end if;
 
                     case Look is
                        when '_' | '0' | '/' =>
                           Skip;
 
                        when 'B' | 'b'  =>
                           Pic.Picture.Expanded (Index) := 'b';
                           Skip;
 
                        when '$' =>
                           Pic.Max_Trailing_Digits :=
                             Pic.Max_Trailing_Digits + 1;
                           Pic.End_Float := Index;
                           Skip;
 
                        when others =>
                           return;
                     end case;
                  end loop;
 
               when others =>
                  Number_Fraction;
                  return;
            end case;
         end loop;
      end Number_Fraction_Or_Dollar;
 
      ------------------------------
      -- Number_Fraction_Or_Pound --
      ------------------------------
 
      procedure Number_Fraction_Or_Pound is
      begin
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '#' =>
                  Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
 
                  loop
                     if At_End then
                        return;
                     end if;
 
                     case Look is
 
                        when '_' | '0' | '/' =>
                           Skip;
 
                        when 'B' | 'b'  =>
                           Pic.Picture.Expanded (Index) := 'b';
                           Skip;
 
                        when '#' =>
                           Pic.Max_Trailing_Digits :=
                             Pic.Max_Trailing_Digits + 1;
                           Pic.End_Float := Index;
                           Skip;
 
                        when others =>
                           return;
 
                     end case;
                  end loop;
 
               when others =>
                  Number_Fraction;
                  return;
 
            end case;
         end loop;
      end Number_Fraction_Or_Pound;
 
      ----------------------------------
      -- Number_Fraction_Or_Star_Fill --
      ----------------------------------
 
      procedure Number_Fraction_Or_Star_Fill is
      begin
         Debug_Start ("Number_Fraction_Or_Star_Fill");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '*' =>
                  Pic.Star_Fill := True;
                  Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
 
                  loop
                     if At_End then
                        return;
                     end if;
 
                     case Look is
 
                        when '_' | '0' | '/' =>
                           Skip;
 
                        when 'B' | 'b'  =>
                           Pic.Picture.Expanded (Index) := 'b';
                           Skip;
 
                        when '*' =>
                           Pic.Star_Fill := True;
                           Pic.Max_Trailing_Digits :=
                             Pic.Max_Trailing_Digits + 1;
                           Pic.End_Float := Index;
                           Skip;
 
                        when others =>
                           return;
                     end case;
                  end loop;
 
               when others =>
                  Number_Fraction;
                  return;
 
            end case;
         end loop;
      end Number_Fraction_Or_Star_Fill;
 
      -------------------------------
      -- Number_Fraction_Or_Z_Fill --
      -------------------------------
 
      procedure Number_Fraction_Or_Z_Fill is
      begin
         Debug_Start ("Number_Fraction_Or_Z_Fill");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when 'Z' | 'z' =>
                  Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'Z'; -- consistency
 
                  Skip;
 
                  loop
                     if At_End then
                        return;
                     end if;
 
                     case Look is
 
                        when '_' | '0' | '/' =>
                           Skip;
 
                        when 'B' | 'b'  =>
                           Pic.Picture.Expanded (Index) := 'b';
                           Skip;
 
                        when 'Z' | 'z' =>
                           Pic.Picture.Expanded (Index) := 'Z'; -- consistency
 
                           Pic.Max_Trailing_Digits :=
                             Pic.Max_Trailing_Digits + 1;
                           Pic.End_Float := Index;
                           Skip;
 
                        when others =>
                           return;
                     end case;
                  end loop;
 
               when others =>
                  Number_Fraction;
                  return;
            end case;
         end loop;
      end Number_Fraction_Or_Z_Fill;
 
      -----------------------
      -- Optional_RHS_Sign --
      -----------------------
 
      procedure Optional_RHS_Sign is
      begin
         Debug_Start ("Optional_RHS_Sign");
 
         if At_End then
            return;
         end if;
 
         case Look is
 
            when '+' | '-' =>
               Pic.Sign_Position := Index;
               Skip;
               return;
 
            when 'C' | 'c' =>
               Pic.Sign_Position := Index;
               Pic.Picture.Expanded (Index) := 'C';
               Skip;
 
               if Look = 'R' or else Look = 'r' then
                  Pic.Second_Sign := Index;
                  Pic.Picture.Expanded (Index) := 'R';
                  Skip;
 
               else
                  raise Picture_Error;
               end if;
 
               return;
 
            when 'D' | 'd' =>
               Pic.Sign_Position := Index;
               Pic.Picture.Expanded (Index) := 'D';
               Skip;
 
               if Look = 'B' or else Look = 'b' then
                  Pic.Second_Sign := Index;
                  Pic.Picture.Expanded (Index) := 'B';
                  Skip;
 
               else
                  raise Picture_Error;
               end if;
 
               return;
 
            when '>' =>
               if Pic.Picture.Expanded (Pic.Sign_Position) = '<' then
                  Pic.Second_Sign := Index;
                  Skip;
 
               else
                  raise Picture_Error;
               end if;
 
            when others =>
               return;
 
         end case;
      end Optional_RHS_Sign;
 
      -------------
      -- Picture --
      -------------
 
      --  Note that Picture can be called in either State
 
      --  It will set state to Valid only if a 9 is encountered or floating
      --  currency is called.
 
      procedure Picture is
      begin
         Debug_Start ("Picture");
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '$' =>
                  Leading_Dollar;
                  return;
 
               when '#' =>
                  Leading_Pound;
                  return;
 
               when '9' =>
                  Computed_BWZ := False;
                  Set_State (Okay);
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Skip;
 
               when 'V' | 'v' | '.' =>
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction;
                  Trailing_Currency;
                  return;
 
               when others =>
                  return;
 
            end case;
         end loop;
      end Picture;
 
      ---------------------
      -- Picture_Bracket --
      ---------------------
 
      procedure Picture_Bracket is
      begin
         Pic.Sign_Position := Index;
         Debug_Start ("Picture_Bracket");
         Pic.Sign_Position := Index;
 
         --  Treat as a floating sign, and unwind otherwise
 
         Pic.Floater := '<';
         Pic.Start_Float := Index;
         Pic.End_Float := Index;
 
         --  Don't increment Pic.Max_Leading_Digits, we need one "real"
         --  sign place.
 
         Skip; --  Known Bracket
 
         loop
            case Look is
 
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '<' =>
                  Set_State (Okay);  --  "<<>" is enough.
                  Floating_Bracket;
                  Trailing_Currency;
                  Trailing_Bracket;
                  return;
 
               when '$' | '#' | '9' | '*' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  Picture;
                  Trailing_Bracket;
                  Set_State (Okay);
                  return;
 
               when '.' | 'V' | 'v' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  --  Don't assume that state is okay, haven't seen a digit
 
                  Picture;
                  Trailing_Bracket;
                  return;
 
               when others =>
                  raise Picture_Error;
 
            end case;
         end loop;
      end Picture_Bracket;
 
      -------------------
      -- Picture_Minus --
      -------------------
 
      procedure Picture_Minus is
      begin
         Debug_Start ("Picture_Minus");
 
         Pic.Sign_Position := Index;
 
         --  Treat as a floating sign, and unwind otherwise
 
         Pic.Floater := '-';
         Pic.Start_Float := Index;
         Pic.End_Float := Index;
 
         --  Don't increment Pic.Max_Leading_Digits, we need one "real"
         --  sign place.
 
         Skip; --  Known Minus
 
         loop
            case Look is
 
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '-' =>
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
                  Set_State (Okay);  --  "-- " is enough.
                  Floating_Minus;
                  Trailing_Currency;
                  return;
 
               when '$' | '#' | '9' | '*' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  Picture;
                  Set_State (Okay);
                  return;
 
               when 'Z' | 'z' =>
 
                  --  Can't have Z and a floating sign
 
                  if State = Okay then
                     Set_State (Reject);
                  end if;
 
                  Pic.Picture.Expanded (Index) := 'Z'; -- consistency
                  Zero_Suppression;
                  Trailing_Currency;
                  Optional_RHS_Sign;
                  return;
 
               when '.' | 'V' | 'v' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  --  Don't assume that state is okay, haven't seen a digit
 
                  Picture;
                  return;
 
               when others =>
                  return;
 
            end case;
         end loop;
      end Picture_Minus;
 
      ------------------
      -- Picture_Plus --
      ------------------
 
      procedure Picture_Plus is
      begin
         Debug_Start ("Picture_Plus");
         Pic.Sign_Position := Index;
 
         --  Treat as a floating sign, and unwind otherwise
 
         Pic.Floater := '+';
         Pic.Start_Float := Index;
         Pic.End_Float := Index;
 
         --  Don't increment Pic.Max_Leading_Digits, we need one "real"
         --  sign place.
 
         Skip; --  Known Plus
 
         loop
            case Look is
 
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '+' =>
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Pic.End_Float := Index;
                  Skip;
                  Set_State (Okay);  --  "++" is enough
                  Floating_Plus;
                  Trailing_Currency;
                  return;
 
               when '$' | '#' | '9' | '*' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  Picture;
                  Set_State (Okay);
                  return;
 
               when 'Z' | 'z' =>
                  if State = Okay then
                     Set_State (Reject);
                  end if;
 
                  --  Can't have Z and a floating sign
 
                  Pic.Picture.Expanded (Index) := 'Z'; -- consistency
 
                  --  '+Z' is acceptable
 
                  Set_State (Okay);
 
                  --  Overwrite Floater and Start_Float
 
                  Pic.Floater := 'Z';
                  Pic.Start_Float := Index;
 
                  Zero_Suppression;
                  Trailing_Currency;
                  Optional_RHS_Sign;
                  return;
 
               when '.' | 'V' | 'v' =>
                  if State /= Okay then
                     Pic.Floater := '!';
                     Pic.Start_Float := Invalid_Position;
                     Pic.End_Float := Invalid_Position;
                  end if;
 
                  --  Don't assume that state is okay, haven't seen a digit
 
                  Picture;
                  return;
 
               when others =>
                  return;
 
            end case;
         end loop;
      end Picture_Plus;
 
      --------------------
      -- Picture_String --
      --------------------
 
      procedure Picture_String is
      begin
         Debug_Start ("Picture_String");
 
         while Is_Insert loop
            Skip;
         end loop;
 
         case Look is
 
            when '$' | '#' =>
               Picture;
               Optional_RHS_Sign;
 
            when '+' =>
               Picture_Plus;
 
            when '-' =>
               Picture_Minus;
 
            when '<' =>
               Picture_Bracket;
 
            when 'Z' | 'z' =>
               Pic.Picture.Expanded (Index) := 'Z'; -- consistency
               Zero_Suppression;
               Trailing_Currency;
               Optional_RHS_Sign;
 
            when '*' =>
               Star_Suppression;
               Trailing_Currency;
               Optional_RHS_Sign;
 
            when '9' | '.' | 'V' | 'v' =>
               Number;
               Trailing_Currency;
               Optional_RHS_Sign;
 
            when others =>
               raise Picture_Error;
 
         end case;
 
         --  Blank when zero either if the PIC does not contain a '9' or if
         --  requested by the user and no '*'.
 
         Pic.Blank_When_Zero :=
           (Computed_BWZ or else Pic.Blank_When_Zero)
             and then not Pic.Star_Fill;
 
         --  Star fill if '*' and no '9'
 
         Pic.Star_Fill := Pic.Star_Fill and then Computed_BWZ;
 
         if not At_End then
            Set_State (Reject);
         end if;
 
      end Picture_String;
 
      ---------------
      -- Set_State --
      ---------------
 
      procedure Set_State (L : Legality) is
      begin
         if Debug then
            Ada.Text_IO.Put_Line
              ("  Set state from " & Legality'Image (State)
               & " to " & Legality'Image (L));
         end if;
 
         State := L;
      end Set_State;
 
      ----------
      -- Skip --
      ----------
 
      procedure Skip is
      begin
         if Debug then
            Ada.Text_IO.Put_Line ("  Skip " & Pic.Picture.Expanded (Index));
         end if;
 
         Index := Index + 1;
      end Skip;
 
      ----------------------
      -- Star_Suppression --
      ----------------------
 
      procedure Star_Suppression is
      begin
         Debug_Start ("Star_Suppression");
 
         if Pic.Floater /= '!' and then Pic.Floater /= '*' then
 
            --  Two floats not allowed
 
            raise Picture_Error;
 
         else
            Pic.Floater := '*';
         end if;
 
         Pic.Start_Float := Index;
         Pic.End_Float := Index;
         Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
         Set_State (Okay);
 
         --  Even a single * is a valid picture
 
         Pic.Star_Fill := True;
         Skip; --  Known *
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
 
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when '*' =>
                  Pic.End_Float := Index;
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Set_State (Okay); Skip;
 
               when '9' =>
                  Set_State (Okay);
                  Number_Completion;
                  return;
 
               when '.' | 'V' | 'v' =>
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction_Or_Star_Fill;
                  return;
 
               when '#' | '$' =>
                  if Pic.Max_Currency_Digits > 0 then
                     raise Picture_Error;
                  end if;
 
                  --  Cannot have leading and trailing currency
 
                  Trailing_Currency;
                  Set_State (Okay);
                  return;
 
               when others => raise Picture_Error;
            end case;
         end loop;
      end Star_Suppression;
 
      ----------------------
      -- Trailing_Bracket --
      ----------------------
 
      procedure Trailing_Bracket is
      begin
         Debug_Start ("Trailing_Bracket");
 
         if Look = '>' then
            Pic.Second_Sign := Index;
            Skip;
         else
            raise Picture_Error;
         end if;
      end Trailing_Bracket;
 
      -----------------------
      -- Trailing_Currency --
      -----------------------
 
      procedure Trailing_Currency is
      begin
         Debug_Start ("Trailing_Currency");
 
         if At_End then
            return;
         end if;
 
         if Look = '$' then
            Pic.Start_Currency := Index;
            Pic.End_Currency := Index;
            Skip;
 
         else
            while not At_End and then Look = '#' loop
               if Pic.Start_Currency = Invalid_Position then
                  Pic.Start_Currency := Index;
               end if;
 
               Pic.End_Currency := Index;
               Skip;
            end loop;
         end if;
 
         loop
            if At_End then
               return;
            end if;
 
            case Look is
               when '_' | '0' | '/' => Skip;
 
               when 'B' | 'b'  =>
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when others => return;
            end case;
         end loop;
      end Trailing_Currency;
 
      ----------------------
      -- Zero_Suppression --
      ----------------------
 
      procedure Zero_Suppression is
      begin
         Debug_Start ("Zero_Suppression");
 
         Pic.Floater := 'Z';
         Pic.Start_Float := Index;
         Pic.End_Float := Index;
         Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
         Pic.Picture.Expanded (Index) := 'Z'; -- consistency
 
         Skip; --  Known Z
 
         loop
            --  Even a single Z is a valid picture
 
            if At_End then
               Set_State (Okay);
               return;
            end if;
 
            case Look is
               when '_' | '0' | '/' =>
                  Pic.End_Float := Index;
                  Skip;
 
               when 'B' | 'b'  =>
                  Pic.End_Float := Index;
                  Pic.Picture.Expanded (Index) := 'b';
                  Skip;
 
               when 'Z' | 'z' =>
                  Pic.Picture.Expanded (Index) := 'Z'; -- consistency
 
                  Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
                  Pic.End_Float := Index;
                  Set_State (Okay);
                  Skip;
 
               when '9' =>
                  Set_State (Okay);
                  Number_Completion;
                  return;
 
               when '.' | 'V' | 'v' =>
                  Pic.Radix_Position := Index;
                  Skip;
                  Number_Fraction_Or_Z_Fill;
                  return;
 
               when '#' | '$' =>
                  Trailing_Currency;
                  Set_State (Okay);
                  return;
 
               when others =>
                  return;
            end case;
         end loop;
      end Zero_Suppression;
 
   --  Start of processing for Precalculate
 
   begin
      pragma Debug (Set_Debug);
 
      Picture_String;
 
      if Debug then
         Ada.Text_IO.New_Line;
         Ada.Text_IO.Put (" Picture : """ &
                     Pic.Picture.Expanded (1 .. Pic.Picture.Length) & """,");
         Ada.Text_IO.Put (" Floater : '" & Pic.Floater & "',");
      end if;
 
      if State = Reject then
         raise Picture_Error;
      end if;
 
      Debug_Integer (Pic.Radix_Position, "Radix Positon : ");
      Debug_Integer (Pic.Sign_Position, "Sign Positon : ");
      Debug_Integer (Pic.Second_Sign, "Second Sign : ");
      Debug_Integer (Pic.Start_Float, "Start Float : ");
      Debug_Integer (Pic.End_Float, "End Float : ");
      Debug_Integer (Pic.Start_Currency, "Start Currency : ");
      Debug_Integer (Pic.End_Currency, "End Currency : ");
      Debug_Integer (Pic.Max_Leading_Digits, "Max Leading Digits : ");
      Debug_Integer (Pic.Max_Trailing_Digits, "Max Trailing Digits : ");
 
      if Debug then
         Ada.Text_IO.New_Line;
      end if;
 
   exception
 
      when Constraint_Error =>
 
      --  To deal with special cases like null strings
 
      raise Picture_Error;
   end Precalculate;
 
   ----------------
   -- To_Picture --
   ----------------
 
   function To_Picture
     (Pic_String      : String;
      Blank_When_Zero : Boolean := False) return Picture
   is
      Result : Picture;
 
   begin
      declare
         Item : constant String := Expand (Pic_String);
 
      begin
         Result.Contents.Picture         := (Item'Length, Item);
         Result.Contents.Original_BWZ := Blank_When_Zero;
         Result.Contents.Blank_When_Zero := Blank_When_Zero;
         Precalculate (Result.Contents);
         return Result;
      end;
 
   exception
      when others =>
         raise Picture_Error;
   end To_Picture;
 
   -----------
   -- Valid --
   -----------
 
   function Valid
     (Pic_String      : String;
      Blank_When_Zero : Boolean := False) return Boolean
   is
   begin
      declare
         Expanded_Pic : constant String := Expand (Pic_String);
         --  Raises Picture_Error if Item not well-formed
 
         Format_Rec : Format_Record;
 
      begin
         Format_Rec.Picture := (Expanded_Pic'Length, Expanded_Pic);
         Format_Rec.Blank_When_Zero := Blank_When_Zero;
         Format_Rec.Original_BWZ := Blank_When_Zero;
         Precalculate (Format_Rec);
 
         --  False only if Blank_When_Zero is True but the pic string has a '*'
 
         return not Blank_When_Zero
           or else Strings_Fixed.Index (Expanded_Pic, "*") = 0;
      end;
 
   exception
      when others => return False;
   end Valid;
 
   --------------------
   -- Decimal_Output --
   --------------------
 
   package body Decimal_Output is
 
      -----------
      -- Image --
      -----------
 
      function Image
        (Item       : Num;
         Pic        : Picture;
         Currency   : String    := Default_Currency;
         Fill       : Character := Default_Fill;
         Separator  : Character := Default_Separator;
         Radix_Mark : Character := Default_Radix_Mark) return String
      is
      begin
         return Format_Number
            (Pic.Contents, Num'Image (Item),
             Currency, Fill, Separator, Radix_Mark);
      end Image;
 
      ------------
      -- Length --
      ------------
 
      function Length
        (Pic      : Picture;
         Currency : String := Default_Currency) return Natural
      is
         Picstr     : constant String := Pic_String (Pic);
         V_Adjust   : Integer := 0;
         Cur_Adjust : Integer := 0;
 
      begin
         --  Check if Picstr has 'V' or '$'
 
         --  If 'V', then length is 1 less than otherwise
 
         --  If '$', then length is Currency'Length-1 more than otherwise
 
         --  This should use the string handling package ???
 
         for J in Picstr'Range loop
            if Picstr (J) = 'V' then
               V_Adjust := -1;
 
            elsif Picstr (J) = '$' then
               Cur_Adjust := Currency'Length - 1;
            end if;
         end loop;
 
         return Picstr'Length - V_Adjust + Cur_Adjust;
      end Length;
 
      ---------
      -- Put --
      ---------
 
      procedure Put
        (File       : Text_IO.File_Type;
         Item       : Num;
         Pic        : Picture;
         Currency   : String    := Default_Currency;
         Fill       : Character := Default_Fill;
         Separator  : Character := Default_Separator;
         Radix_Mark : Character := Default_Radix_Mark)
      is
      begin
         Text_IO.Put (File, Image (Item, Pic,
                                   Currency, Fill, Separator, Radix_Mark));
      end Put;
 
      procedure Put
        (Item       : Num;
         Pic        : Picture;
         Currency   : String    := Default_Currency;
         Fill       : Character := Default_Fill;
         Separator  : Character := Default_Separator;
         Radix_Mark : Character := Default_Radix_Mark)
      is
      begin
         Text_IO.Put (Image (Item, Pic,
                             Currency, Fill, Separator, Radix_Mark));
      end Put;
 
      procedure Put
        (To         : out String;
         Item       : Num;
         Pic        : Picture;
         Currency   : String    := Default_Currency;
         Fill       : Character := Default_Fill;
         Separator  : Character := Default_Separator;
         Radix_Mark : Character := Default_Radix_Mark)
      is
         Result : constant String :=
           Image (Item, Pic, Currency, Fill, Separator, Radix_Mark);
 
      begin
         if Result'Length > To'Length then
            raise Ada.Text_IO.Layout_Error;
         else
            Strings_Fixed.Move (Source => Result, Target => To,
                                Justify => Strings.Right);
         end if;
      end Put;
 
      -----------
      -- Valid --
      -----------
 
      function Valid
        (Item     : Num;
         Pic      : Picture;
         Currency : String := Default_Currency) return Boolean
      is
      begin
         declare
            Temp : constant String := Image (Item, Pic, Currency);
            pragma Warnings (Off, Temp);
         begin
            return True;
         end;
 
      exception
         when Ada.Text_IO.Layout_Error => return False;
 
      end Valid;
   end Decimal_Output;
 
end Ada.Text_IO.Editing;
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.