1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . F O R M A T T E D _ S T R I N G --
9 -- Copyright (C) 2014-2023, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada
.Characters
.Handling
;
33 with Ada
.Float_Text_IO
;
34 with Ada
.Integer_Text_IO
;
35 with Ada
.Long_Float_Text_IO
;
36 with Ada
.Long_Integer_Text_IO
;
38 with Ada
.Strings
.Fixed
;
39 with Ada
.Unchecked_Deallocation
;
41 with System
.Address_Image
;
43 package body GNAT
.Formatted_String
is
45 type F_Kind
is (Decimal_Int
, -- %d %i
46 Unsigned_Decimal_Int
, -- %u
48 Unsigned_Hexadecimal_Int
, -- %x
49 Unsigned_Hexadecimal_Int_Up
, -- %X
50 Decimal_Float
, -- %f %F
51 Decimal_Scientific_Float
, -- %e
52 Decimal_Scientific_Float_Up
, -- %E
60 type Sign_Kind
is (Neg
, Zero
, Pos
);
62 subtype Is_Number
is F_Kind
range Decimal_Int
.. G_Specifier_Up
;
64 type F_Sign
is (If_Neg
, Forced
, Space
) with Default_Value
=> If_Neg
;
66 type F_Base
is (None
, C_Style
, Ada_Style
) with Default_Value
=> None
;
68 Unset
: constant Integer := -1;
73 Precision
: Integer := Unset
;
74 Left_Justify
: Boolean := False;
77 Zero_Pad
: Boolean := False;
78 Value_Needed
: Natural range 0 .. 2 := 0;
81 type Notation
is (Decimal
, Scientific
);
83 procedure Advance_And_Accumulate_Until_Next_Specifier
84 (Format
: Formatted_String
);
85 -- Advance Format.D.Index until either the next format specifier is
86 -- encountered, or the end of Format.D.Format is reached. The characters
87 -- advanced over are appended to Format.D.Result.
90 (Format
: Formatted_String
;
92 Start
: out Positive);
93 -- Parse the next format specifier, a format specifier has the following
94 -- syntax: %[flags][width][.precision][length]specifier
96 procedure Determine_Notation_And_Aft
98 Precision
: Text_IO
.Field
;
100 Aft
: out Text_IO
.Field
);
101 -- Determine whether to use scientific or decimal notation and the value of
102 -- Aft given the exponent and precision of a real number, as described in
103 -- the C language specification, section 7.21.6.1.
105 function Get_Formatted
108 Len
: Positive) return String;
109 -- Returns Value formatted given the information in F_Spec
111 procedure Increment_Integral_Part
112 (Buffer
: in out String;
113 First_Non_Blank
: in out Positive;
114 Last_Digit_Position
: Positive);
115 -- Buffer must contain the textual representation of a number.
116 -- Last_Digit_Position must be the position of the rightmost digit of the
117 -- integral part. Buffer must have at least one padding blank. Increment
118 -- the integral part.
120 procedure Raise_Wrong_Format
(Format
: Formatted_String
) with No_Return
;
121 -- Raise the Format_Error exception which information about the context
130 Exp
: Text_IO
.Field
);
131 function P_Flt_Format
132 (Format
: Formatted_String
;
133 Var
: Flt
) return Formatted_String
;
134 -- Generic routine which handles all floating point numbers
139 with function To_Integer
(Item
: Int
) return Integer;
141 with function Sign
(Item
: Int
) return Sign_Kind
;
146 Base
: Text_IO
.Number_Base
);
147 function P_Int_Format
148 (Format
: Formatted_String
;
149 Var
: Int
) return Formatted_String
;
150 -- Generic routine which handles all the integer numbers
152 procedure Remove_Extraneous_Decimal_Digit
153 (Textual_Rep
: in out String;
154 First_Non_Blank
: in out Positive);
155 -- Remove the unique digit to the right of the point in Textual_Rep
157 procedure Trim_Fractional_Part
158 (Textual_Rep
: in out String;
159 First_Non_Blank
: in out Positive);
160 -- Remove trailing zeros from Textual_Rep, which must be the textual
161 -- representation of a real number. If the fractional part only contains
162 -- zeros, also remove the point.
168 function "+" (Format
: String) return Formatted_String
is
170 return Formatted_String
'
171 (Finalization.Controlled with
172 D => new Data'(Format
'Length, 1, 1,
173 Null_Unbounded_String
, 0, 0, [0, 0], Format
));
180 function "-" (Format
: Formatted_String
) return String is
182 -- Make sure we get the remaining character up to the next unhandled
185 Advance_And_Accumulate_Until_Next_Specifier
(Format
);
187 return To_String
(Format
.D
.Result
);
195 (Format
: Formatted_String
;
196 Var
: Character) return Formatted_String
202 Next_Format
(Format
, F
, Start
);
204 if F
.Value_Needed
> 0 then
205 Raise_Wrong_Format
(Format
);
210 Append
(Format
.D
.Result
, Get_Formatted
(F
, String'(1 => Var), 1));
212 Raise_Wrong_Format (Format);
219 (Format : Formatted_String;
220 Var : String) return Formatted_String
226 Next_Format (Format, F, Start);
228 if F.Value_Needed > 0 then
229 Raise_Wrong_Format (Format);
235 S : constant String := Get_Formatted (F, Var, Var'Length);
237 if F.Precision = Unset then
238 Append (Format.D.Result, S);
242 S (S'First .. S'First + F.Precision - 1));
247 Raise_Wrong_Format (Format);
254 (Format : Formatted_String;
255 Var : Boolean) return Formatted_String is
257 return Format & Boolean'Image (Var);
261 (Format : Formatted_String;
262 Var : Float) return Formatted_String
264 function Float_Format is new Flt_Format (Float, Float_Text_IO.Put);
266 return Float_Format (Format, Var);
270 (Format : Formatted_String;
271 Var : Long_Float) return Formatted_String
273 function Float_Format is
274 new Flt_Format (Long_Float, Long_Float_Text_IO.Put);
276 return Float_Format (Format, Var);
280 (Format : Formatted_String;
281 Var : Duration) return Formatted_String
283 package Duration_Text_IO is new Text_IO.Fixed_IO (Duration);
284 function Duration_Format is
285 new P_Flt_Format (Duration, Duration_Text_IO.Put);
287 return Duration_Format (Format, Var);
291 (Format : Formatted_String;
292 Var : Integer) return Formatted_String
294 function Integer_Format is
295 new Int_Format (Integer, Integer_Text_IO.Put);
297 return Integer_Format (Format, Var);
301 (Format : Formatted_String;
302 Var : Long_Integer) return Formatted_String
304 function Integer_Format is
305 new Int_Format (Long_Integer, Long_Integer_Text_IO.Put);
307 return Integer_Format (Format, Var);
311 (Format : Formatted_String;
312 Var : System.Address) return Formatted_String
314 A_Img : constant String := System.Address_Image (Var);
319 Next_Format (Format, F, Start);
321 if F.Value_Needed > 0 then
322 Raise_Wrong_Format (Format);
327 Append (Format.D.Result, Get_Formatted (F, A_Img, A_Img'Length));
329 Raise_Wrong_Format (Format);
339 overriding procedure Adjust (F : in out Formatted_String) is
341 F.D.Ref_Count := F.D.Ref_Count + 1;
344 -------------------------------------------------
345 -- Advance_And_Accumulate_Until_Next_Specifier --
346 -------------------------------------------------
348 procedure Advance_And_Accumulate_Until_Next_Specifier
349 (Format : Formatted_String)
353 if Format.D.Index > Format.D.Format'Last then
357 if Format.D.Format (Format.D.Index) /= '%' then
358 Append (Format.D.Result, Format.D.Format (Format.D.Index));
359 Format.D.Index := Format.D.Index + 1;
360 elsif Format.D.Index + 1 <= Format.D.Format'Last
361 and then Format.D.Format (Format.D.Index + 1) = '%'
363 Append (Format.D.Result, '%');
364 Format.D.Index := Format.D.Index + 2;
369 end Advance_And_Accumulate_Until_Next_Specifier;
371 --------------------------------
372 -- Determine_Notation_And_Aft --
373 --------------------------------
375 procedure Determine_Notation_And_Aft
377 Precision : Text_IO.Field;
379 Aft : out Text_IO.Field)
381 -- The constants use the same names as those from the C specification
382 -- in order to match the description of the predicate.
383 P : constant Text_IO.Field := (if Precision /= 0 then Precision else 1);
384 X : constant Integer := Exponent;
386 if P > X and X >= -4 then
393 end Determine_Notation_And_Aft;
399 function Decimal_Format
400 (Format : Formatted_String;
401 Var : Flt) return Formatted_String
403 function Flt_Format is new P_Flt_Format (Flt, Put);
405 return Flt_Format (Format, Var);
413 (Format : Formatted_String;
414 Var : Enum) return Formatted_String is
416 return Format & Enum'Image (Var);
423 overriding procedure Finalize (F : in out Formatted_String) is
424 procedure Unchecked_Free is
425 new Unchecked_Deallocation (Data, Data_Access);
427 D : Data_Access := F.D;
432 D.Ref_Count := D.Ref_Count - 1;
434 if D.Ref_Count = 0 then
443 function Fixed_Format
444 (Format : Formatted_String;
445 Var : Flt) return Formatted_String
447 function Flt_Format is new P_Flt_Format (Flt, Put);
449 return Flt_Format (Format, Var);
457 (Format : Formatted_String;
458 Var : Flt) return Formatted_String
460 function Flt_Format is new P_Flt_Format (Flt, Put);
462 return Flt_Format (Format, Var);
469 function Get_Formatted
472 Len : Positive) return String
474 use Ada.Strings.Fixed;
476 Res : Unbounded_String;
477 S : Positive := Value'First;
482 if F_Spec.Kind in Is_Number then
483 if F_Spec.Sign = Forced and then Value (Value'First) /= '-' then
485 elsif F_Spec.Sign = Space and then Value (Value'First) /= '-' then
489 if Value (Value'First) = '-' then
495 -- Zero padding if required and possible
497 if not F_Spec.Left_Justify
498 and then F_Spec.Zero_Pad
499 and then F_Spec.Width > Len + Value'First - S
501 Append (Res, String'((F_Spec
.Width
- (Len
+ Value
'First - S
)) * '0'));
506 Append
(Res
, Value
(S
.. Value
'Last));
509 R
: String (1 .. Natural'Max (Natural'Max (F_Spec
.Width
, Len
),
510 Length
(Res
))) := [others => ' '];
512 if F_Spec
.Left_Justify
then
513 R
(1 .. Length
(Res
)) := To_String
(Res
);
515 R
(R
'Last - Length
(Res
) + 1 .. R
'Last) := To_String
(Res
);
522 -----------------------------
523 -- Increment_Integral_Part --
524 -----------------------------
526 procedure Increment_Integral_Part
527 (Buffer
: in out String;
528 First_Non_Blank
: in out Positive;
529 Last_Digit_Position
: Positive)
531 Cursor
: Natural := Last_Digit_Position
;
533 while Buffer
(Cursor
) = '9' loop
534 Buffer
(Cursor
) := '0';
535 Cursor
:= Cursor
- 1;
538 pragma Assert
(Cursor
> 0);
540 if Buffer
(Cursor
) in '0' .. '8' then
541 Buffer
(Cursor
) := Character'Succ (Buffer
(Cursor
));
543 Ada
.Strings
.Fixed
.Insert
547 First_Non_Blank
:= First_Non_Blank
- 1;
549 end Increment_Integral_Part
;
556 (Format
: Formatted_String
;
557 Var
: Int
) return Formatted_String
559 function Sign
(Var
: Int
) return Sign_Kind
is
560 (if Var
< 0 then Neg
elsif Var
= 0 then Zero
else Pos
);
562 function To_Integer
(Var
: Int
) return Integer is
565 function Int_Format
is new P_Int_Format
(Int
, To_Integer
, Sign
, Put
);
568 return Int_Format
(Format
, Var
);
576 (Format
: Formatted_String
;
577 Var
: Int
) return Formatted_String
579 function Sign
(Var
: Int
) return Sign_Kind
is
580 (if Var
< 0 then Neg
elsif Var
= 0 then Zero
else Pos
);
582 function To_Integer
(Var
: Int
) return Integer is
585 function Int_Format
is new P_Int_Format
(Int
, To_Integer
, Sign
, Put
);
588 return Int_Format
(Format
, Var
);
595 procedure Next_Format
596 (Format
: Formatted_String
;
598 Start
: out Positive)
600 F
: String renames Format
.D
.Format
;
601 J
: Natural renames Format
.D
.Index
;
603 Width_From_Var
: Boolean := False;
606 Format
.D
.Current
:= Format
.D
.Current
+ 1;
607 F_Spec
.Value_Needed
:= 0;
611 Advance_And_Accumulate_Until_Next_Specifier
(Format
);
613 if J
>= F
'Last or else F
(J
) /= '%' then
614 raise Format_Error
with "no format specifier found for parameter"
615 & Positive'Image (Format
.D
.Current
);
622 -- Check for any flags
624 Flags_Check
: while J
< F
'Last loop
626 F_Spec
.Left_Justify
:= True;
627 elsif F
(J
) = '+' then
628 F_Spec
.Sign
:= Forced
;
629 elsif F
(J
) = ' ' then
630 F_Spec
.Sign
:= Space
;
631 elsif F
(J
) = '#' then
632 F_Spec
.Base
:= C_Style
;
633 elsif F
(J
) = '~' then
634 F_Spec
.Base
:= Ada_Style
;
635 elsif F
(J
) = '0' then
636 F_Spec
.Zero_Pad
:= True;
642 end loop Flags_Check
;
644 -- Check width if any
646 if F
(J
) in '0' .. '9' then
648 -- We have a width parameter
652 while J
< F
'Last and then F
(J
+ 1) in '0' .. '9' loop
656 F_Spec
.Width
:= Natural'Value (F
(S
.. J
));
660 elsif F
(J
) = '*' then
662 -- The width will be taken from the integer parameter
664 F_Spec
.Value_Needed
:= 1;
665 Width_From_Var
:= True;
672 -- We have a precision parameter
676 if F
(J
) in '0' .. '9' then
679 while J
< F
'Length and then F
(J
+ 1) in '0' .. '9' loop
685 -- No precision, 0 is assumed
687 F_Spec
.Precision
:= 0;
690 F_Spec
.Precision
:= Natural'Value (F
(S
.. J
));
695 elsif F
(J
) = '*' then
697 -- The prevision will be taken from the integer parameter
699 F_Spec
.Value_Needed
:= F_Spec
.Value_Needed
+ 1;
704 -- Skip the length specifier, this is not needed for this implementation
705 -- but yet for compatibility reason it is handled.
709 and then F
(J
) in 'h' |
'l' |
'j' |
'z' |
't' |
'L'
712 end loop Length_Check
;
715 Raise_Wrong_Format
(Format
);
718 -- Read next character which should be the expected type
721 when 'c' => F_Spec
.Kind
:= Char
;
722 when 's' => F_Spec
.Kind
:= Str
;
723 when 'd' |
'i' => F_Spec
.Kind
:= Decimal_Int
;
724 when 'u' => F_Spec
.Kind
:= Unsigned_Decimal_Int
;
725 when 'f' |
'F' => F_Spec
.Kind
:= Decimal_Float
;
726 when 'e' => F_Spec
.Kind
:= Decimal_Scientific_Float
;
727 when 'E' => F_Spec
.Kind
:= Decimal_Scientific_Float_Up
;
728 when 'g' => F_Spec
.Kind
:= G_Specifier
;
729 when 'G' => F_Spec
.Kind
:= G_Specifier_Up
;
730 when 'o' => F_Spec
.Kind
:= Unsigned_Octal
;
731 when 'x' => F_Spec
.Kind
:= Unsigned_Hexadecimal_Int
;
732 when 'X' => F_Spec
.Kind
:= Unsigned_Hexadecimal_Int_Up
;
735 raise Format_Error
with "unknown format specified for parameter"
736 & Positive'Image (Format
.D
.Current
);
741 if F_Spec
.Value_Needed
> 0
742 and then F_Spec
.Value_Needed
= Format
.D
.Stored_Value
744 if F_Spec
.Value_Needed
= 1 then
745 if Width_From_Var
then
746 F_Spec
.Width
:= Format
.D
.Stack
(1);
748 F_Spec
.Precision
:= Format
.D
.Stack
(1);
752 F_Spec
.Width
:= Format
.D
.Stack
(1);
753 F_Spec
.Precision
:= Format
.D
.Stack
(2);
762 function P_Flt_Format
763 (Format
: Formatted_String
;
764 Var
: Flt
) return Formatted_String
766 procedure Compute_Exponent
769 Exponent
: out Integer);
770 -- If Var is invalid (for example, a NaN of an inf), set Valid False and
771 -- set Exponent to 0. Otherwise, set Valid True, and store the exponent
772 -- of the scientific notation representation of Var in Exponent. The
773 -- exponent can also be defined as:
775 -- - Otherwise, Floor (Log_10 (Abs (Var))).
777 procedure Format_With_Notation
781 Buffer
: out String);
782 -- Fill buffer with the formatted value of Var following the notation
783 -- specified through Nota.
785 procedure Handle_G_Specifier
786 (Buffer
: out String;
787 First_Non_Blank
: out Positive;
788 Aft
: Text_IO
.Field
);
789 -- Fill Buffer with the formatted value of Var according to the rules of
790 -- the "%g" specifier. Buffer is right-justified and padded with blanks.
792 ----------------------
793 -- Compute_Exponent --
794 ----------------------
796 procedure Compute_Exponent
799 Exponent
: out Integer)
801 -- The way the exponent is computed is convoluted. It is not possible
802 -- to use the logarithm in base 10 of Var and floor it, because the
803 -- math functions for this are not available for fixed point types.
804 -- Instead, use the generic Put procedure to produce a scientific
805 -- representation of Var, and parse the exponent part of that back
807 Scientific_Rep
: String (1 .. 50);
809 E_Position
: Natural;
811 Put
(Scientific_Rep
, Var
, Aft
=> 1, Exp
=> 1);
813 E_Position
:= Ada
.Strings
.Fixed
.Index
(Scientific_Rep
, "E");
815 if E_Position
= 0 then
822 (Scientific_Rep
(E_Position
+ 1 .. Scientific_Rep
'Last));
824 end Compute_Exponent
;
826 --------------------------
827 -- Format_With_Notation --
828 --------------------------
830 procedure Format_With_Notation
836 Exp
: constant Text_IO
.Field
:=
837 (case Nota
is when Decimal
=> 0, when Scientific
=> 3);
839 Put
(Buffer
, Var
, Aft
, Exp
);
840 end Format_With_Notation
;
842 ------------------------
843 -- Handle_G_Specifier --
844 ------------------------
846 procedure Handle_G_Specifier
847 (Buffer
: out String;
848 First_Non_Blank
: out Positive;
851 -- There is nothing that is directly equivalent to the "%g" specifier
852 -- in the standard Ada functionality provided by Ada.Text_IO. The
853 -- procedure Put will still be used, but significant postprocessing
854 -- will be performed on the output of that procedure.
856 -- The following code is intended to match the behavior of C's printf
857 -- for %g, as described by paragraph "7.21.6.1 The fprintf function"
858 -- of the C language specification.
860 -- As explained in the C specification, we're going to have to make a
861 -- choice between decimal notation and scientific notation. One of
862 -- the elements we need in order to make that choice is the value of
863 -- the exponent in the decimal representation of Var. We will store
864 -- that value in Exponent.
870 -- The value of the formal Aft comes from the precision specifier in
871 -- the format string. For %g, the precision specifier corresponds to
872 -- the number of significant figures desired, whereas the formal Aft
873 -- in Put corresponds to the number of digits after the point.
874 -- Effective_Aft is what will be passed to Put as Aft in order to
875 -- respect the semantics of %g.
876 Effective_Aft
: Text_IO
.Field
;
878 Textual_Rep
: String (Buffer
'Range);
880 Compute_Exponent
(Var
, Valid
, Exponent
);
882 Determine_Notation_And_Aft
883 (Exponent
, Aft
, Nota
, Effective_Aft
);
885 Format_With_Notation
(Var
, Nota
, Effective_Aft
, Textual_Rep
);
887 First_Non_Blank
:= Strings
.Fixed
.Index_Non_Blank
(Textual_Rep
);
891 elsif Effective_Aft
= 0 then
892 -- Special case: it is possible at this point that Effective_Aft
893 -- is zero. But when Put is passed zero through Aft, it still
894 -- outputs one digit after the point. See the reference manual,
897 Remove_Extraneous_Decimal_Digit
(Textual_Rep
, First_Non_Blank
);
900 (Textual_Rep
, First_Non_Blank
);
903 Buffer
:= Textual_Rep
;
904 end Handle_G_Specifier
;
909 Buffer
: String (1 .. 50);
910 S
, E
: Positive := 1;
914 -- Start of processing for P_Flt_Format
917 Next_Format
(Format
, F
, Start
);
919 if F
.Value_Needed
/= Format
.D
.Stored_Value
then
920 Raise_Wrong_Format
(Format
);
922 Format
.D
.Stored_Value
:= 0;
924 if F
.Precision
= Unset
then
931 when Decimal_Float
=>
933 Put
(Buffer
, Var
, Aft
, Exp
=> 0);
934 S
:= Strings
.Fixed
.Index_Non_Blank
(Buffer
);
937 when Decimal_Scientific_Float
938 | Decimal_Scientific_Float_Up
940 Put
(Buffer
, Var
, Aft
, Exp
=> 3);
941 S
:= Strings
.Fixed
.Index_Non_Blank
(Buffer
);
944 if F
.Kind
= Decimal_Scientific_Float
then
946 Characters
.Handling
.To_Lower
(Buffer
(S
.. E
));
952 Handle_G_Specifier
(Buffer
, S
, Aft
);
955 if F
.Kind
= G_Specifier
then
957 Characters
.Handling
.To_Lower
(Buffer
(S
.. E
));
961 Raise_Wrong_Format
(Format
);
964 Append
(Format
.D
.Result
,
965 Get_Formatted
(F
, Buffer
(S
.. E
), Buffer
(S
.. E
)'Length));
974 function P_Int_Format
975 (Format
: Formatted_String
;
976 Var
: Int
) return Formatted_String
978 function Handle_Precision
return Boolean;
979 -- Return True if nothing else to do
982 Buffer
: String (1 .. 50);
983 S
, E
: Positive := 1;
987 ----------------------
988 -- Handle_Precision --
989 ----------------------
991 function Handle_Precision
return Boolean is
993 if F
.Precision
= 0 and then Sign
(Var
) = Zero
then
996 elsif F
.Precision
= Natural'Last then
999 elsif F
.Precision
> E
- S
+ 1 then
1000 Len
:= F
.Precision
- (E
- S
+ 1);
1001 Buffer
(S
- Len
.. S
- 1) := [others => '0'];
1006 end Handle_Precision
;
1008 -- Start of processing for P_Int_Format
1011 Next_Format
(Format
, F
, Start
);
1013 if Format
.D
.Stored_Value
< F
.Value_Needed
then
1014 Format
.D
.Stored_Value
:= Format
.D
.Stored_Value
+ 1;
1015 Format
.D
.Stack
(Format
.D
.Stored_Value
) := To_Integer
(Var
);
1016 Format
.D
.Index
:= Start
;
1019 Format
.D
.Stored_Value
:= 0;
1022 when Unsigned_Octal
=>
1023 if Sign
(Var
) = Neg
then
1024 Raise_Wrong_Format
(Format
);
1027 Put
(Buffer
, Var
, Base
=> 8);
1028 S
:= Strings
.Fixed
.Index
(Buffer
, "8#") + 2;
1029 E
:= Strings
.Fixed
.Index
(Buffer
(S
.. Buffer
'Last), "#") - 1;
1031 if Handle_Precision
then
1037 when C_Style
=> Len
:= 1;
1038 when Ada_Style
=> Len
:= 3;
1041 when Unsigned_Hexadecimal_Int
=>
1042 if Sign
(Var
) = Neg
then
1043 Raise_Wrong_Format
(Format
);
1046 Put
(Buffer
, Var
, Base
=> 16);
1047 S
:= Strings
.Fixed
.Index
(Buffer
, "16#") + 3;
1048 E
:= Strings
.Fixed
.Index
(Buffer
(S
.. Buffer
'Last), "#") - 1;
1049 Buffer
(S
.. E
) := Characters
.Handling
.To_Lower
(Buffer
(S
.. E
));
1051 if Handle_Precision
then
1057 when C_Style
=> Len
:= 2;
1058 when Ada_Style
=> Len
:= 4;
1061 when Unsigned_Hexadecimal_Int_Up
=>
1062 if Sign
(Var
) = Neg
then
1063 Raise_Wrong_Format
(Format
);
1066 Put
(Buffer
, Var
, Base
=> 16);
1067 S
:= Strings
.Fixed
.Index
(Buffer
, "16#") + 3;
1068 E
:= Strings
.Fixed
.Index
(Buffer
(S
.. Buffer
'Last), "#") - 1;
1070 if Handle_Precision
then
1076 when C_Style
=> Len
:= 2;
1077 when Ada_Style
=> Len
:= 4;
1080 when Unsigned_Decimal_Int
=>
1081 if Sign
(Var
) = Neg
then
1082 Raise_Wrong_Format
(Format
);
1085 Put
(Buffer
, Var
, Base
=> 10);
1086 S
:= Strings
.Fixed
.Index_Non_Blank
(Buffer
);
1089 if Handle_Precision
then
1094 Put
(Buffer
, Var
, Base
=> 10);
1095 S
:= Strings
.Fixed
.Index_Non_Blank
(Buffer
);
1098 if Handle_Precision
then
1105 Buffer
(S
) := Character'Val (To_Integer
(Var
));
1107 if Handle_Precision
then
1112 Raise_Wrong_Format
(Format
);
1115 -- Then add base if needed
1118 N
: String := Get_Formatted
(F
, Buffer
(S
.. E
), E
- S
+ 1 + Len
);
1119 P
: constant Positive :=
1122 else Natural'Max (Strings
.Fixed
.Index_Non_Blank
(N
) - 1,
1131 when Unsigned_Octal
=>
1134 when Unsigned_Hexadecimal_Int
=>
1135 if F
.Left_Justify
then
1136 N
(P
.. P
+ 1) := "Ox";
1138 N
(P
- 1 .. P
) := "0x";
1141 when Unsigned_Hexadecimal_Int_Up
=>
1142 if F
.Left_Justify
then
1143 N
(P
.. P
+ 1) := "OX";
1145 N
(P
- 1 .. P
) := "0X";
1154 when Unsigned_Octal
=>
1155 if F
.Left_Justify
then
1156 N
(N
'First + 2 .. N
'Last) := N
(N
'First .. N
'Last - 2);
1158 N
(P
.. N
'Last - 1) := N
(P
+ 1 .. N
'Last);
1161 N
(N
'First .. N
'First + 1) := "8#";
1164 when Unsigned_Hexadecimal_Int
1165 | Unsigned_Hexadecimal_Int_Up
1167 if F
.Left_Justify
then
1168 N
(N
'First + 3 .. N
'Last) := N
(N
'First .. N
'Last - 3);
1170 N
(P
.. N
'Last - 1) := N
(P
+ 1 .. N
'Last);
1173 N
(N
'First .. N
'First + 2) := "16#";
1181 Append
(Format
.D
.Result
, N
);
1187 ------------------------
1188 -- Raise_Wrong_Format --
1189 ------------------------
1191 procedure Raise_Wrong_Format
(Format
: Formatted_String
) is
1193 raise Format_Error
with
1194 "wrong format specified for parameter"
1195 & Positive'Image (Format
.D
.Current
);
1196 end Raise_Wrong_Format
;
1198 -------------------------------------
1199 -- Remove_Extraneous_Decimal_Digit --
1200 -------------------------------------
1202 procedure Remove_Extraneous_Decimal_Digit
1203 (Textual_Rep
: in out String;
1204 First_Non_Blank
: in out Positive)
1206 Point_Position
: constant Positive := Ada
.Strings
.Fixed
.Index
1211 Integral_Part_Needs_Increment
: constant Boolean :=
1212 Textual_Rep
(Point_Position
+ 1) in '5' .. '9';
1214 Ada
.Strings
.Fixed
.Delete
1220 First_Non_Blank
:= First_Non_Blank
+ 2;
1222 if Integral_Part_Needs_Increment
then
1223 Increment_Integral_Part
1226 Last_Digit_Position
=> Point_Position
+ 1);
1228 end Remove_Extraneous_Decimal_Digit
;
1230 --------------------------
1231 -- Trim_Fractional_Part --
1232 --------------------------
1234 procedure Trim_Fractional_Part
1235 (Textual_Rep
: in out String;
1236 First_Non_Blank
: in out Positive)
1238 Cursor
: Positive :=
1239 Ada
.Strings
.Fixed
.Index
(Textual_Rep
, ".", First_Non_Blank
);
1241 First_To_Trim
: Positive;
1242 Fractional_Part_Last
: Positive;
1244 while Cursor
+ 1 <= Textual_Rep
'Last
1245 and then Textual_Rep
(Cursor
+ 1) in '0' .. '9' loop
1246 Cursor
:= Cursor
+ 1;
1249 Fractional_Part_Last
:= Cursor
;
1251 while Textual_Rep
(Cursor
) = '0' loop
1252 Cursor
:= Cursor
- 1;
1255 if Textual_Rep
(Cursor
) = '.' then
1256 Cursor
:= Cursor
- 1;
1259 First_To_Trim
:= Cursor
+ 1;
1261 Ada
.Strings
.Fixed
.Delete
1262 (Textual_Rep
, First_To_Trim
, Fractional_Part_Last
, Ada
.Strings
.Right
);
1265 First_Non_Blank
+ (Fractional_Part_Last
- First_To_Trim
+ 1);
1266 end Trim_Fractional_Part
;
1268 end GNAT
.Formatted_String
;