------------------------------------------------------------------------------
-- --
--- GNAT RUNTIME COMPONENTS --
+-- GNAT RUN-TIME COMPONENTS --
-- --
-- A D A . T E X T _ I O . E D I T I N G --
-- --
-- B o d y --
-- --
--- $Revision: 1.18 $
--- --
--- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
+-- 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 2, or (at your option) any later ver- --
+-- 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. See the GNU General Public License --
--- for more details. You should have received a copy of the GNU General --
--- Public License distributed with GNAT; see file COPYING. If not, write --
--- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
--- MA 02111-1307, USA. --
+-- 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. --
-- --
--- As a special exception, if other files instantiate generics from this --
--- 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. --
+-- 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. --
--- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
-- Blank_When_Zero --
---------------------
- function Blank_When_Zero (Pic : in Picture) return Boolean is
+ function Blank_When_Zero (Pic : Picture) return Boolean is
begin
return Pic.Contents.Original_BWZ;
end Blank_When_Zero;
-- Expand --
------------
- function Expand (Picture : in String) return String is
+ function Expand (Picture : String) return String is
Result : String (1 .. MAX_PICSIZE);
Picture_Index : Integer := Picture'First;
Result_Index : Integer := Result'First;
-- 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.
+ -- Last + 1 was a ')' throw it away too
Picture_Index := Last + 2;
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;
exception
when others =>
raise Picture_Error;
-
end Expand;
-------------------
Currency_Symbol : String;
Fill_Character : Character;
Separator_Character : Character;
- Radix_Point : Character)
- return String
+ Radix_Point : Character) return String
is
Attrs : Number_Attributes := Parse_Number_String (Number);
Position : Integer;
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.
+ -- Overridden immediately if necessary
Zero : Boolean := True;
- -- Set to False when a non-zero digit is output.
+ -- Set to False when a non-zero digit is output
begin
for J in reverse Last .. Answer'Last loop
exit when J = Pic.Radix_Position;
- -- Do this test First, Separator_Character can equal Pic.Floater.
+ -- Do this test First, Separator_Character can equal Pic.Floater
if Answer (J) = Pic.Floater then
exit;
if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
Pic.Max_Leading_Digits
then
- raise Layout_Error;
+ raise Ada.Text_IO.Layout_Error;
end if;
if Pic.Radix_Position = Invalid_Position then
Answer (J) := Separator_Character;
elsif Answer (J) = 'b' then
- Answer (J) := '*';
+ Answer (J) := Fill_Character;
end if;
end loop;
end if;
for J in Pic.Start_Float .. Position loop
- Answer (J) := '*';
+ 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
when '*' =>
Answer (J) := Fill_Character;
- when 'Z' | 'b' | '/' | '0' =>
+ 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' =>
end loop;
if Pic.Floater = '#' and then Currency_Pos /= 0 then
- raise Layout_Error;
+ raise Ada.Text_IO.Layout_Error;
end if;
end if;
if Sign_Position = Invalid_Position then
if Attrs.Negative then
- raise Layout_Error;
+ raise Ada.Text_IO.Layout_Error;
end if;
else
else
if Pic.Floater = '#' and then Currency_Pos /= 0 then
- raise Layout_Error;
+ raise Ada.Text_IO.Layout_Error;
end if;
-- No trailing digits, but now J may need to stick in a currency
Currency_Pos := 1;
end if;
- -- Note: There are some weird cases J can imagine with 'b' or '#'
- -- in currency strings where the following code will cause
- -- glitches. The trick is to tell when the character in the
- -- answer should be checked, and when to look at the original
- -- string. Some other time. RIE 11/26/96 ???
-
case Answer (J) is
when '*' =>
Answer (J) := Fill_Character;
when 'b' =>
- Answer (J) := ' ';
+ 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
end case;
end loop;
- -- Now get rid of Blank_when_Zero and complete Star fill.
+ -- Now get rid of Blank_when_Zero and complete Star fill
if Zero and Pic.Blank_When_Zero then
- -- Value is zero, and blank it.
+ -- Value is zero, and blank it
Last := Answer'Last;
Last := Last - 1;
end if;
- return String' (1 .. Last => ' ');
+ return String'(1 .. Last => ' ');
elsif Zero and Pic.Star_Fill then
Last := Answer'Last;
elsif Dollar then
if Pic.Radix_Position > Pic.Start_Currency then
- return String' (1 .. Pic.Radix_Position - 1 => '*') &
+ return String'(1 .. Pic.Radix_Position - 1 => '*') &
Radix_Point &
- String' (Pic.Radix_Position + 1 .. Last => '*');
+ String'(Pic.Radix_Position + 1 .. Last => '*');
else
return
end if;
else
- return String' (1 .. Pic.Radix_Position - 1 => '*') &
+ return String'(1 .. Pic.Radix_Position - 1 => '*') &
Radix_Point &
- String' (Pic.Radix_Position + 1 .. Last => '*');
+ String'(Pic.Radix_Position + 1 .. Last => '*');
end if;
end if;
- return String' (1 .. Last => '*');
+ return String'(1 .. Last => '*');
end if;
-- This was once a simple return statement, now there are nine
return Answer;
end if;
-
end Format_Number;
-------------------------
raise Picture_Error;
end if;
- -- Two decimal points is a no-no.
+ -- Two decimal points is a no-no
Answer.Has_Fraction := True;
Answer.End_Of_Fraction := J;
Answer.Start_Of_Int := Answer.End_Of_Int + 1;
end if;
- -- No significant (intger) digits needs a null range.
+ -- No significant (integer) digits needs a null range
return Answer;
-
end Parse_Number_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 : in Picture) return String is
+ 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;
+ if Temp (J) = 'b' then
+ Temp (J) := 'B';
+ end if;
end loop;
return Temp;
------------------
procedure Precalculate (Pic : in out Format_Record) is
+ Debug : constant Boolean := False;
+ -- Set True to generate debug output
Computed_BWZ : Boolean := True;
- Debug : Boolean := False;
type Legality is (Okay, Reject);
+
State : Legality := Reject;
- -- Start in reject, which will reject null strings.
+ -- Start in reject, which will reject null strings
Index : Pic_Index := Pic.Picture.Expanded'First;
procedure Debug_Start (Name : String);
pragma Inline (Debug_Start);
- procedure Debug_Integer (Value : in Integer; S : String);
+ procedure Debug_Integer (Value : Integer; S : String);
pragma Inline (Debug_Integer);
procedure Trailing_Currency;
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 : in Integer; S : String) is
+ procedure Debug_Integer (Value : Integer; S : String) is
use Ada.Text_IO; -- needed for >
begin
procedure Floating_Bracket is
begin
Debug_Start ("Floating_Bracket");
- Pic.Floater := '<';
+
+ -- 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;
end loop;
end Floating_Bracket;
-
--------------------
-- Floating_Minus --
--------------------
begin
Debug_Start ("Leading_Dollar");
- -- Treat as a floating dollar, and unwind otherwise.
+ -- 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.Floater := '$';
Pic.Start_Currency := Index;
Pic.End_Currency := Index;
Pic.Start_Float := Index;
if State = Okay then
raise Picture_Error;
else
- -- Will overwrite Floater and Start_Float
+ -- Overwrite Floater and Start_Float
+ Pic.Floater := 'Z';
+ Pic.Start_Float := Index;
Zero_Suppression;
end if;
if State = Okay then
raise Picture_Error;
else
- -- Will overwrite Floater and Start_Float
+ -- Overwrite Floater and Start_Float
+ Pic.Floater := '*';
+ Pic.Start_Float := Index;
Star_Suppression;
end if;
Pic.End_Float := Invalid_Position;
end if;
- -- A single dollar does not a floating make.
+ -- A single dollar does not a floating make
Number_Completion;
return;
Pic.End_Float := Invalid_Position;
end if;
- -- Only one dollar before the sign is okay,
- -- but doesn't float.
+ -- Only one dollar before the sign is okay, but doesn't
+ -- float.
Pic.Radix_Position := Index;
Skip;
-- Set to True if a '_', '0', '/', 'B', or 'b' is encountered
Must_Float : Boolean := False;
- -- Set to true if a '#' occurs after an insert.
+ -- 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.
- Pic.Floater := '#';
+ 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;
else
Pic.Max_Leading_Digits := 0;
- -- Will overwrite Floater and Start_Float
+ -- Overwrite Floater and Start_Float
+ Pic.Floater := 'Z';
+ Pic.Start_Float := Index;
Zero_Suppression;
end if;
else
Pic.Max_Leading_Digits := 0;
- -- Will overwrite Floater and Start_Float
-
+ -- Overwrite Floater and Start_Float
+ Pic.Floater := '*';
+ Pic.Start_Float := Index;
Star_Suppression;
end if;
when '9' =>
if State /= Okay then
- -- A single '#' doesn't float.
+ -- A single '#' doesn't float
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.
+ -- Only one pound before the sign is okay, but doesn't
+ -- float.
Pic.Radix_Position := Index;
Skip;
return;
end if;
- -- Will return in Okay state if a '9' was seen.
+ -- Will return in Okay state if a '9' was seen
end loop;
end Number;
-- Picture --
-------------
- -- Note that Picture can be called in either State.
+ -- 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.
Debug_Start ("Picture_Bracket");
Pic.Sign_Position := Index;
- -- Treat as a floating sign, and unwind otherwise.
+ -- Treat as a floating sign, and unwind otherwise
Pic.Floater := '<';
Pic.Start_Float := Index;
Pic.Sign_Position := Index;
- -- Treat as a floating sign, and unwind otherwise.
+ -- Treat as a floating sign, and unwind otherwise
Pic.Floater := '-';
Pic.Start_Float := Index;
when 'Z' | 'z' =>
- -- Can't have Z and a floating sign.
+ -- Can't have Z and a floating sign
if State = Okay then
Set_State (Reject);
Pic.End_Float := Invalid_Position;
end if;
- -- Don't assume that state is okay, haven't seen a digit.
+ -- Don't assume that state is okay, haven't seen a digit
Picture;
return;
Debug_Start ("Picture_Plus");
Pic.Sign_Position := Index;
- -- Treat as a floating sign, and unwind otherwise.
+ -- Treat as a floating sign, and unwind otherwise
Pic.Floater := '+';
Pic.Start_Float := Index;
Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
Pic.End_Float := Index;
Skip;
- Set_State (Okay); -- "++" is enough.
+ Set_State (Okay); -- "++" is enough
Floating_Plus;
Trailing_Currency;
return;
Set_State (Reject);
end if;
- -- Can't have Z and a floating sign.
+ -- Can't have Z and a floating sign
Pic.Picture.Expanded (Index) := 'Z'; -- consistency
Set_State (Okay);
+ -- Overwrite Floater and Start_Float
+
+ Pic.Floater := 'Z';
+ Pic.Start_Float := Index;
+
Zero_Suppression;
Trailing_Currency;
Optional_RHS_Sign;
Pic.End_Float := Invalid_Position;
end if;
- -- Don't assume that state is okay, haven't seen a digit.
+ -- Don't assume that state is okay, haven't seen a digit
Picture;
return;
end case;
-- Blank when zero either if the PIC does not contain a '9' or if
- -- requested by the user and no '*'
+ -- requested by the user and no '*'.
Pic.Blank_When_Zero :=
(Computed_BWZ or Pic.Blank_When_Zero) and not Pic.Star_Fill;
- -- Star fill if '*' and no '9'.
+ -- Star fill if '*' and no '9'
Pic.Star_Fill := Pic.Star_Fill and Computed_BWZ;
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));
+ if Debug then
+ Ada.Text_IO.Put_Line
+ (" Set state from " & Legality'Image (State)
+ & " to " & Legality'Image (L));
end if;
State := L;
procedure Skip is
begin
- if Debug then Ada.Text_IO.Put_Line
- (" Skip " & Pic.Picture.Expanded (Index));
+ if Debug then
+ Ada.Text_IO.Put_Line (" Skip " & Pic.Picture.Expanded (Index));
end if;
Index := Index + 1;
procedure Star_Suppression is
begin
Debug_Start ("Star_Suppression");
- Pic.Floater := '*';
+
+ 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;
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;
-- Start of processing for Precalculate
begin
+ pragma Debug (Set_Debug);
+
Picture_String;
if Debug then
when Constraint_Error =>
- -- To deal with special cases like null strings.
+ -- To deal with special cases like null strings
raise Picture_Error;
-
end Precalculate;
----------------
----------------
function To_Picture
- (Pic_String : in String;
- Blank_When_Zero : in Boolean := False)
- return Picture
+ (Pic_String : String;
+ Blank_When_Zero : Boolean := False) return Picture
is
Result : Picture;
exception
when others =>
raise Picture_Error;
-
end To_Picture;
-----------
-----------
function Valid
- (Pic_String : in String;
- Blank_When_Zero : in Boolean := False)
- return Boolean
+ (Pic_String : String;
+ Blank_When_Zero : Boolean := False) return Boolean
is
begin
declare
Format_Rec.Original_BWZ := Blank_When_Zero;
Precalculate (Format_Rec);
- -- False only if Blank_When_0 is True but the pic string has a '*'
+ -- False only if Blank_When_Zero is True but the pic string has a '*'
- return not Blank_When_Zero or
- Strings_Fixed.Index (Expanded_Pic, "*") = 0;
+ return not Blank_When_Zero
+ or else Strings_Fixed.Index (Expanded_Pic, "*") = 0;
end;
exception
when others => return False;
-
end Valid;
--------------------
-----------
function Image
- (Item : in Num;
- Pic : in Picture;
- Currency : in String := Default_Currency;
- Fill : in Character := Default_Fill;
- Separator : in Character := Default_Separator;
- Radix_Mark : in Character := Default_Radix_Mark)
- return String
+ (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
------------
function Length
- (Pic : in Picture;
- Currency : in String := Default_Currency)
- return Natural
+ (Pic : Picture;
+ Currency : String := Default_Currency) return Natural
is
Picstr : constant String := Pic_String (Pic);
V_Adjust : Integer := 0;
---------
procedure Put
- (File : in Text_IO.File_Type;
- Item : in Num;
- Pic : in Picture;
- Currency : in String := Default_Currency;
- Fill : in Character := Default_Fill;
- Separator : in Character := Default_Separator;
- Radix_Mark : in Character := Default_Radix_Mark)
+ (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,
end Put;
procedure Put
- (Item : in Num;
- Pic : in Picture;
- Currency : in String := Default_Currency;
- Fill : in Character := Default_Fill;
- Separator : in Character := Default_Separator;
- Radix_Mark : in Character := Default_Radix_Mark)
+ (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,
procedure Put
(To : out String;
- Item : in Num;
- Pic : in Picture;
- Currency : in String := Default_Currency;
- Fill : in Character := Default_Fill;
- Separator : in Character := Default_Separator;
- Radix_Mark : in Character := Default_Radix_Mark)
+ 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 Text_IO.Layout_Error;
+ raise Ada.Text_IO.Layout_Error;
else
Strings_Fixed.Move (Source => Result, Target => To,
Justify => Strings.Right);
function Valid
(Item : Num;
- Pic : in Picture;
- Currency : in String := Default_Currency)
- return Boolean
+ Pic : Picture;
+ Currency : String := Default_Currency) return Boolean
is
begin
declare
end;
exception
- when Layout_Error => return False;
+ when Ada.Text_IO.Layout_Error => return False;
end Valid;
-
end Decimal_Output;
end Ada.Text_IO.Editing;