2002-02-06 Aldy Hernandez <aldyh@redhat.com>
[official-gcc.git] / gcc / ada / a-teioed.adb
blobb67fe5fbc08c3b27de413af7d7b8adf3f1153dde
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUNTIME COMPONENTS --
4 -- --
5 -- A D A . T E X T _ I O . E D I T I N G --
6 -- --
7 -- B o d y --
8 -- --
9 -- $Revision: 1.1 $
10 -- --
11 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
12 -- --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
23 -- --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
30 -- --
31 -- GNAT was originally developed by the GNAT team at New York University. --
32 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
33 -- --
34 ------------------------------------------------------------------------------
36 with Ada.Strings.Fixed;
37 package body Ada.Text_IO.Editing is
39 package Strings renames Ada.Strings;
40 package Strings_Fixed renames Ada.Strings.Fixed;
41 package Text_IO renames Ada.Text_IO;
43 ---------------------
44 -- Blank_When_Zero --
45 ---------------------
47 function Blank_When_Zero (Pic : in Picture) return Boolean is
48 begin
49 return Pic.Contents.Original_BWZ;
50 end Blank_When_Zero;
52 ------------
53 -- Expand --
54 ------------
56 function Expand (Picture : in String) return String is
57 Result : String (1 .. MAX_PICSIZE);
58 Picture_Index : Integer := Picture'First;
59 Result_Index : Integer := Result'First;
60 Count : Natural;
61 Last : Integer;
63 package Int_IO is new Ada.Text_IO.Integer_IO (Integer);
65 begin
66 if Picture'Length < 1 then
67 raise Picture_Error;
68 end if;
70 if Picture (Picture'First) = '(' then
71 raise Picture_Error;
72 end if;
74 loop
75 case Picture (Picture_Index) is
77 when '(' =>
78 Int_IO.Get (Picture (Picture_Index + 1 .. Picture'Last),
79 Count, Last);
81 if Picture (Last + 1) /= ')' then
82 raise Picture_Error;
83 end if;
85 -- In what follows note that one copy of the repeated
86 -- character has already been made, so a count of one is a
87 -- no-op, and a count of zero erases a character.
89 for J in 2 .. Count loop
90 Result (Result_Index + J - 2) := Picture (Picture_Index - 1);
91 end loop;
93 Result_Index := Result_Index + Count - 1;
95 -- Last + 1 was a ')' throw it away too.
97 Picture_Index := Last + 2;
99 when ')' =>
100 raise Picture_Error;
102 when others =>
103 Result (Result_Index) := Picture (Picture_Index);
104 Picture_Index := Picture_Index + 1;
105 Result_Index := Result_Index + 1;
107 end case;
109 exit when Picture_Index > Picture'Last;
110 end loop;
112 return Result (1 .. Result_Index - 1);
114 exception
115 when others =>
116 raise Picture_Error;
118 end Expand;
120 -------------------
121 -- Format_Number --
122 -------------------
124 function Format_Number
125 (Pic : Format_Record;
126 Number : String;
127 Currency_Symbol : String;
128 Fill_Character : Character;
129 Separator_Character : Character;
130 Radix_Point : Character)
131 return String
133 Attrs : Number_Attributes := Parse_Number_String (Number);
134 Position : Integer;
135 Rounded : String := Number;
137 Sign_Position : Integer := Pic.Sign_Position; -- may float.
139 Answer : String (1 .. Pic.Picture.Length) := Pic.Picture.Expanded;
140 Last : Integer;
141 Currency_Pos : Integer := Pic.Start_Currency;
143 Dollar : Boolean := False;
144 -- Overridden immediately if necessary.
146 Zero : Boolean := True;
147 -- Set to False when a non-zero digit is output.
149 begin
151 -- If the picture has fewer decimal places than the number, the image
152 -- must be rounded according to the usual rules.
154 if Attrs.Has_Fraction then
155 declare
156 R : constant Integer :=
157 (Attrs.End_Of_Fraction - Attrs.Start_Of_Fraction + 1)
158 - Pic.Max_Trailing_Digits;
159 R_Pos : Integer;
161 begin
162 if R > 0 then
163 R_Pos := Attrs.End_Of_Fraction - R;
165 if Rounded (R_Pos + 1) > '4' then
167 if Rounded (R_Pos) = '.' then
168 R_Pos := R_Pos - 1;
169 end if;
171 if Rounded (R_Pos) /= '9' then
172 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
173 else
174 Rounded (R_Pos) := '0';
175 R_Pos := R_Pos - 1;
177 while R_Pos > 1 loop
178 if Rounded (R_Pos) = '.' then
179 R_Pos := R_Pos - 1;
180 end if;
182 if Rounded (R_Pos) /= '9' then
183 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
184 exit;
185 else
186 Rounded (R_Pos) := '0';
187 R_Pos := R_Pos - 1;
188 end if;
189 end loop;
191 -- The rounding may add a digit in front. Either the
192 -- leading blank or the sign (already captured) can
193 -- be overwritten.
195 if R_Pos = 1 then
196 Rounded (R_Pos) := '1';
197 Attrs.Start_Of_Int := Attrs.Start_Of_Int - 1;
198 end if;
199 end if;
200 end if;
201 end if;
202 end;
203 end if;
205 if Pic.Start_Currency /= Invalid_Position then
206 Dollar := Answer (Pic.Start_Currency) = '$';
207 end if;
209 -- Fix up "direct inserts" outside the playing field. Set up as one
210 -- loop to do the beginning, one (reverse) loop to do the end.
212 Last := 1;
213 loop
214 exit when Last = Pic.Start_Float;
215 exit when Last = Pic.Radix_Position;
216 exit when Answer (Last) = '9';
218 case Answer (Last) is
220 when '_' =>
221 Answer (Last) := Separator_Character;
223 when 'b' =>
224 Answer (Last) := ' ';
226 when others =>
227 null;
229 end case;
231 exit when Last = Answer'Last;
233 Last := Last + 1;
234 end loop;
236 -- Now for the end...
238 for J in reverse Last .. Answer'Last loop
239 exit when J = Pic.Radix_Position;
241 -- Do this test First, Separator_Character can equal Pic.Floater.
243 if Answer (J) = Pic.Floater then
244 exit;
245 end if;
247 case Answer (J) is
249 when '_' =>
250 Answer (J) := Separator_Character;
252 when 'b' =>
253 Answer (J) := ' ';
255 when '9' =>
256 exit;
258 when others =>
259 null;
261 end case;
262 end loop;
264 -- Non-floating sign
266 if Pic.Start_Currency /= -1
267 and then Answer (Pic.Start_Currency) = '#'
268 and then Pic.Floater /= '#'
269 then
270 if Currency_Symbol'Length >
271 Pic.End_Currency - Pic.Start_Currency + 1
272 then
273 raise Picture_Error;
275 elsif Currency_Symbol'Length =
276 Pic.End_Currency - Pic.Start_Currency + 1
277 then
278 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
279 Currency_Symbol;
281 elsif Pic.Radix_Position = Invalid_Position
282 or else Pic.Start_Currency < Pic.Radix_Position
283 then
284 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
285 (others => ' ');
286 Answer (Pic.End_Currency - Currency_Symbol'Length + 1 ..
287 Pic.End_Currency) := Currency_Symbol;
289 else
290 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
291 (others => ' ');
292 Answer (Pic.Start_Currency ..
293 Pic.Start_Currency + Currency_Symbol'Length - 1) :=
294 Currency_Symbol;
295 end if;
296 end if;
298 -- Fill in leading digits
300 if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
301 Pic.Max_Leading_Digits
302 then
303 raise Layout_Error;
304 end if;
306 if Pic.Radix_Position = Invalid_Position then
307 Position := Answer'Last;
308 else
309 Position := Pic.Radix_Position - 1;
310 end if;
312 for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop
314 while Answer (Position) /= '9'
315 and Answer (Position) /= Pic.Floater
316 loop
317 if Answer (Position) = '_' then
318 Answer (Position) := Separator_Character;
320 elsif Answer (Position) = 'b' then
321 Answer (Position) := ' ';
322 end if;
324 Position := Position - 1;
325 end loop;
327 Answer (Position) := Rounded (J);
329 if Rounded (J) /= '0' then
330 Zero := False;
331 end if;
333 Position := Position - 1;
334 end loop;
336 -- Do lead float
338 if Pic.Start_Float = Invalid_Position then
340 -- No leading floats, but need to change '9' to '0', '_' to
341 -- Separator_Character and 'b' to ' '.
343 for J in Last .. Position loop
345 -- Last set when fixing the "uninteresting" leaders above.
346 -- Don't duplicate the work.
348 if Answer (J) = '9' then
349 Answer (J) := '0';
351 elsif Answer (J) = '_' then
352 Answer (J) := Separator_Character;
354 elsif Answer (J) = 'b' then
355 Answer (J) := ' ';
356 end if;
357 end loop;
359 elsif Pic.Floater = '<'
360 or else
361 Pic.Floater = '+'
362 or else
363 Pic.Floater = '-'
364 then
365 for J in Pic.End_Float .. Position loop -- May be null range.
366 if Answer (J) = '9' then
367 Answer (J) := '0';
369 elsif Answer (J) = '_' then
370 Answer (J) := Separator_Character;
372 elsif Answer (J) = 'b' then
373 Answer (J) := ' ';
374 end if;
375 end loop;
377 if Position > Pic.End_Float then
378 Position := Pic.End_Float;
379 end if;
381 for J in Pic.Start_Float .. Position - 1 loop
382 Answer (J) := ' ';
383 end loop;
385 Answer (Position) := Pic.Floater;
386 Sign_Position := Position;
388 elsif Pic.Floater = '$' then
390 for J in Pic.End_Float .. Position loop -- May be null range.
391 if Answer (J) = '9' then
392 Answer (J) := '0';
394 elsif Answer (J) = '_' then
395 Answer (J) := ' '; -- no separators before leftmost digit.
397 elsif Answer (J) = 'b' then
398 Answer (J) := ' ';
399 end if;
400 end loop;
402 if Position > Pic.End_Float then
403 Position := Pic.End_Float;
404 end if;
406 for J in Pic.Start_Float .. Position - 1 loop
407 Answer (J) := ' ';
408 end loop;
410 Answer (Position) := Pic.Floater;
411 Currency_Pos := Position;
413 elsif Pic.Floater = '*' then
415 for J in Pic.End_Float .. Position loop -- May be null range.
416 if Answer (J) = '9' then
417 Answer (J) := '0';
419 elsif Answer (J) = '_' then
420 Answer (J) := Separator_Character;
422 elsif Answer (J) = 'b' then
423 Answer (J) := '*';
424 end if;
425 end loop;
427 if Position > Pic.End_Float then
428 Position := Pic.End_Float;
429 end if;
431 for J in Pic.Start_Float .. Position loop
432 Answer (J) := '*';
433 end loop;
435 else
436 if Pic.Floater = '#' then
437 Currency_Pos := Currency_Symbol'Length;
438 end if;
440 for J in reverse Pic.Start_Float .. Position loop
441 case Answer (J) is
443 when '*' =>
444 Answer (J) := Fill_Character;
446 when 'Z' | 'b' | '/' | '0' =>
447 Answer (J) := ' ';
449 when '9' =>
450 Answer (J) := '0';
452 when '.' | 'V' | 'v' | '<' | '$' | '+' | '-' =>
453 null;
455 when '#' =>
456 if Currency_Pos = 0 then
457 Answer (J) := ' ';
458 else
459 Answer (J) := Currency_Symbol (Currency_Pos);
460 Currency_Pos := Currency_Pos - 1;
461 end if;
463 when '_' =>
465 case Pic.Floater is
467 when '*' =>
468 Answer (J) := Fill_Character;
470 when 'Z' | 'b' =>
471 Answer (J) := ' ';
473 when '#' =>
474 if Currency_Pos = 0 then
475 Answer (J) := ' ';
477 else
478 Answer (J) := Currency_Symbol (Currency_Pos);
479 Currency_Pos := Currency_Pos - 1;
480 end if;
482 when others =>
483 null;
485 end case;
487 when others =>
488 null;
490 end case;
491 end loop;
493 if Pic.Floater = '#' and then Currency_Pos /= 0 then
494 raise Layout_Error;
495 end if;
496 end if;
498 -- Do sign
500 if Sign_Position = Invalid_Position then
501 if Attrs.Negative then
502 raise Layout_Error;
503 end if;
505 else
506 if Attrs.Negative then
507 case Answer (Sign_Position) is
508 when 'C' | 'D' | '-' =>
509 null;
511 when '+' =>
512 Answer (Sign_Position) := '-';
514 when '<' =>
515 Answer (Sign_Position) := '(';
516 Answer (Pic.Second_Sign) := ')';
518 when others =>
519 raise Picture_Error;
521 end case;
523 else -- positive
525 case Answer (Sign_Position) is
527 when '-' =>
528 Answer (Sign_Position) := ' ';
530 when '<' | 'C' | 'D' =>
531 Answer (Sign_Position) := ' ';
532 Answer (Pic.Second_Sign) := ' ';
534 when '+' =>
535 null;
537 when others =>
538 raise Picture_Error;
540 end case;
541 end if;
542 end if;
544 -- Fill in trailing digits
546 if Pic.Max_Trailing_Digits > 0 then
548 if Attrs.Has_Fraction then
549 Position := Attrs.Start_Of_Fraction;
550 Last := Pic.Radix_Position + 1;
552 for J in Last .. Answer'Last loop
554 if Answer (J) = '9' or Answer (J) = Pic.Floater then
555 Answer (J) := Rounded (Position);
557 if Rounded (Position) /= '0' then
558 Zero := False;
559 end if;
561 Position := Position + 1;
562 Last := J + 1;
564 -- Used up fraction but remember place in Answer
566 exit when Position > Attrs.End_Of_Fraction;
568 elsif Answer (J) = 'b' then
569 Answer (J) := ' ';
571 elsif Answer (J) = '_' then
572 Answer (J) := Separator_Character;
574 end if;
576 Last := J + 1;
577 end loop;
579 Position := Last;
581 else
582 Position := Pic.Radix_Position + 1;
583 end if;
585 -- Now fill remaining 9's with zeros and _ with separators
587 Last := Answer'Last;
589 for J in Position .. Last loop
590 if Answer (J) = '9' then
591 Answer (J) := '0';
593 elsif Answer (J) = Pic.Floater then
594 Answer (J) := '0';
596 elsif Answer (J) = '_' then
597 Answer (J) := Separator_Character;
599 elsif Answer (J) = 'b' then
600 Answer (J) := ' ';
602 end if;
603 end loop;
605 Position := Last + 1;
607 else
608 if Pic.Floater = '#' and then Currency_Pos /= 0 then
609 raise Layout_Error;
610 end if;
612 -- No trailing digits, but now J may need to stick in a currency
613 -- symbol or sign.
615 if Pic.Start_Currency = Invalid_Position then
616 Position := Answer'Last + 1;
617 else
618 Position := Pic.Start_Currency;
619 end if;
620 end if;
622 for J in Position .. Answer'Last loop
624 if Pic.Start_Currency /= Invalid_Position and then
625 Answer (Pic.Start_Currency) = '#' then
626 Currency_Pos := 1;
627 end if;
629 -- Note: There are some weird cases J can imagine with 'b' or '#'
630 -- in currency strings where the following code will cause
631 -- glitches. The trick is to tell when the character in the
632 -- answer should be checked, and when to look at the original
633 -- string. Some other time. RIE 11/26/96 ???
635 case Answer (J) is
636 when '*' =>
637 Answer (J) := Fill_Character;
639 when 'b' =>
640 Answer (J) := ' ';
642 when '#' =>
643 if Currency_Pos > Currency_Symbol'Length then
644 Answer (J) := ' ';
646 else
647 Answer (J) := Currency_Symbol (Currency_Pos);
648 Currency_Pos := Currency_Pos + 1;
649 end if;
651 when '_' =>
653 case Pic.Floater is
655 when '*' =>
656 Answer (J) := Fill_Character;
658 when 'Z' | 'z' =>
659 Answer (J) := ' ';
661 when '#' =>
662 if Currency_Pos > Currency_Symbol'Length then
663 Answer (J) := ' ';
664 else
665 Answer (J) := Currency_Symbol (Currency_Pos);
666 Currency_Pos := Currency_Pos + 1;
667 end if;
669 when others =>
670 null;
672 end case;
674 when others =>
675 exit;
677 end case;
678 end loop;
680 -- Now get rid of Blank_when_Zero and complete Star fill.
682 if Zero and Pic.Blank_When_Zero then
684 -- Value is zero, and blank it.
686 Last := Answer'Last;
688 if Dollar then
689 Last := Last - 1 + Currency_Symbol'Length;
690 end if;
692 if Pic.Radix_Position /= Invalid_Position and then
693 Answer (Pic.Radix_Position) = 'V' then
694 Last := Last - 1;
695 end if;
697 return String' (1 .. Last => ' ');
699 elsif Zero and Pic.Star_Fill then
700 Last := Answer'Last;
702 if Dollar then
703 Last := Last - 1 + Currency_Symbol'Length;
704 end if;
706 if Pic.Radix_Position /= Invalid_Position then
708 if Answer (Pic.Radix_Position) = 'V' then
709 Last := Last - 1;
711 elsif Dollar then
712 if Pic.Radix_Position > Pic.Start_Currency then
713 return String' (1 .. Pic.Radix_Position - 1 => '*') &
714 Radix_Point &
715 String' (Pic.Radix_Position + 1 .. Last => '*');
717 else
718 return
719 String'
720 (1 ..
721 Pic.Radix_Position + Currency_Symbol'Length - 2 =>
722 '*') & Radix_Point &
723 String'
724 (Pic.Radix_Position + Currency_Symbol'Length .. Last
725 => '*');
726 end if;
728 else
729 return String' (1 .. Pic.Radix_Position - 1 => '*') &
730 Radix_Point &
731 String' (Pic.Radix_Position + 1 .. Last => '*');
732 end if;
733 end if;
735 return String' (1 .. Last => '*');
736 end if;
738 -- This was once a simple return statement, now there are nine
739 -- different return cases. Not to mention the five above to deal
740 -- with zeros. Why not split things out?
742 -- Processing the radix and sign expansion separately
743 -- would require lots of copying--the string and some of its
744 -- indices--without really simplifying the logic. The cases are:
746 -- 1) Expand $, replace '.' with Radix_Point
747 -- 2) No currency expansion, replace '.' with Radix_Point
748 -- 3) Expand $, radix blanked
749 -- 4) No currency expansion, radix blanked
750 -- 5) Elide V
751 -- 6) Expand $, Elide V
752 -- 7) Elide V, Expand $ (Two cases depending on order.)
753 -- 8) No radix, expand $
754 -- 9) No radix, no currency expansion
756 if Pic.Radix_Position /= Invalid_Position then
758 if Answer (Pic.Radix_Position) = '.' then
759 Answer (Pic.Radix_Position) := Radix_Point;
761 if Dollar then
763 -- 1) Expand $, replace '.' with Radix_Point
765 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
766 Answer (Currency_Pos + 1 .. Answer'Last);
768 else
769 -- 2) No currency expansion, replace '.' with Radix_Point
771 return Answer;
772 end if;
774 elsif Answer (Pic.Radix_Position) = ' ' then -- blanked radix.
775 if Dollar then
777 -- 3) Expand $, radix blanked
779 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
780 Answer (Currency_Pos + 1 .. Answer'Last);
782 else
783 -- 4) No expansion, radix blanked
785 return Answer;
786 end if;
788 -- V cases
790 else
791 if not Dollar then
793 -- 5) Elide V
795 return Answer (1 .. Pic.Radix_Position - 1) &
796 Answer (Pic.Radix_Position + 1 .. Answer'Last);
798 elsif Currency_Pos < Pic.Radix_Position then
800 -- 6) Expand $, Elide V
802 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
803 Answer (Currency_Pos + 1 .. Pic.Radix_Position - 1) &
804 Answer (Pic.Radix_Position + 1 .. Answer'Last);
806 else
807 -- 7) Elide V, Expand $
809 return Answer (1 .. Pic.Radix_Position - 1) &
810 Answer (Pic.Radix_Position + 1 .. Currency_Pos - 1) &
811 Currency_Symbol &
812 Answer (Currency_Pos + 1 .. Answer'Last);
813 end if;
814 end if;
816 elsif Dollar then
818 -- 8) No radix, expand $
820 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
821 Answer (Currency_Pos + 1 .. Answer'Last);
823 else
824 -- 9) No radix, no currency expansion
826 return Answer;
827 end if;
829 end Format_Number;
831 -------------------------
832 -- Parse_Number_String --
833 -------------------------
835 function Parse_Number_String (Str : String) return Number_Attributes is
836 Answer : Number_Attributes;
838 begin
839 for J in Str'Range loop
840 case Str (J) is
842 when ' ' =>
843 null; -- ignore
845 when '1' .. '9' =>
847 -- Decide if this is the start of a number.
848 -- If so, figure out which one...
850 if Answer.Has_Fraction then
851 Answer.End_Of_Fraction := J;
852 else
853 if Answer.Start_Of_Int = Invalid_Position then
854 -- start integer
855 Answer.Start_Of_Int := J;
856 end if;
857 Answer.End_Of_Int := J;
858 end if;
860 when '0' =>
862 -- Only count a zero before the decimal point if it follows a
863 -- non-zero digit. After the decimal point, zeros will be
864 -- counted if followed by a non-zero digit.
866 if not Answer.Has_Fraction then
867 if Answer.Start_Of_Int /= Invalid_Position then
868 Answer.End_Of_Int := J;
869 end if;
870 end if;
872 when '-' =>
874 -- Set negative
876 Answer.Negative := True;
878 when '.' =>
880 -- Close integer, start fraction
882 if Answer.Has_Fraction then
883 raise Picture_Error;
884 end if;
886 -- Two decimal points is a no-no.
888 Answer.Has_Fraction := True;
889 Answer.End_Of_Fraction := J;
891 -- Could leave this at Invalid_Position, but this seems the
892 -- right way to indicate a null range...
894 Answer.Start_Of_Fraction := J + 1;
895 Answer.End_Of_Int := J - 1;
897 when others =>
898 raise Picture_Error; -- can this happen? probably not!
899 end case;
900 end loop;
902 if Answer.Start_Of_Int = Invalid_Position then
903 Answer.Start_Of_Int := Answer.End_Of_Int + 1;
904 end if;
906 -- No significant (intger) digits needs a null range.
908 return Answer;
910 end Parse_Number_String;
912 ----------------
913 -- Pic_String --
914 ----------------
916 -- The following ensures that we return B and not b being careful not
917 -- to break things which expect lower case b for blank. See CXF3A02.
919 function Pic_String (Pic : in Picture) return String is
920 Temp : String (1 .. Pic.Contents.Picture.Length) :=
921 Pic.Contents.Picture.Expanded;
922 begin
923 for J in Temp'Range loop
924 if Temp (J) = 'b' then Temp (J) := 'B'; end if;
925 end loop;
927 return Temp;
928 end Pic_String;
930 ------------------
931 -- Precalculate --
932 ------------------
934 procedure Precalculate (Pic : in out Format_Record) is
936 Computed_BWZ : Boolean := True;
937 Debug : Boolean := False;
939 type Legality is (Okay, Reject);
940 State : Legality := Reject;
941 -- Start in reject, which will reject null strings.
943 Index : Pic_Index := Pic.Picture.Expanded'First;
945 function At_End return Boolean;
946 pragma Inline (At_End);
948 procedure Set_State (L : Legality);
949 pragma Inline (Set_State);
951 function Look return Character;
952 pragma Inline (Look);
954 function Is_Insert return Boolean;
955 pragma Inline (Is_Insert);
957 procedure Skip;
958 pragma Inline (Skip);
960 procedure Debug_Start (Name : String);
961 pragma Inline (Debug_Start);
963 procedure Debug_Integer (Value : in Integer; S : String);
964 pragma Inline (Debug_Integer);
966 procedure Trailing_Currency;
967 procedure Trailing_Bracket;
968 procedure Number_Fraction;
969 procedure Number_Completion;
970 procedure Number_Fraction_Or_Bracket;
971 procedure Number_Fraction_Or_Z_Fill;
972 procedure Zero_Suppression;
973 procedure Floating_Bracket;
974 procedure Number_Fraction_Or_Star_Fill;
975 procedure Star_Suppression;
976 procedure Number_Fraction_Or_Dollar;
977 procedure Leading_Dollar;
978 procedure Number_Fraction_Or_Pound;
979 procedure Leading_Pound;
980 procedure Picture;
981 procedure Floating_Plus;
982 procedure Floating_Minus;
983 procedure Picture_Plus;
984 procedure Picture_Minus;
985 procedure Picture_Bracket;
986 procedure Number;
987 procedure Optional_RHS_Sign;
988 procedure Picture_String;
990 ------------
991 -- At_End --
992 ------------
994 function At_End return Boolean is
995 begin
996 return Index > Pic.Picture.Length;
997 end At_End;
999 -------------------
1000 -- Debug_Integer --
1001 -------------------
1003 procedure Debug_Integer (Value : in Integer; S : String) is
1004 use Ada.Text_IO; -- needed for >
1006 begin
1007 if Debug and then Value > 0 then
1008 if Ada.Text_IO.Col > 70 - S'Length then
1009 Ada.Text_IO.New_Line;
1010 end if;
1012 Ada.Text_IO.Put (' ' & S & Integer'Image (Value) & ',');
1013 end if;
1014 end Debug_Integer;
1016 -----------------
1017 -- Debug_Start --
1018 -----------------
1020 procedure Debug_Start (Name : String) is
1021 begin
1022 if Debug then
1023 Ada.Text_IO.Put_Line (" In " & Name & '.');
1024 end if;
1025 end Debug_Start;
1027 ----------------------
1028 -- Floating_Bracket --
1029 ----------------------
1031 -- Note that Floating_Bracket is only called with an acceptable
1032 -- prefix. But we don't set Okay, because we must end with a '>'.
1034 procedure Floating_Bracket is
1035 begin
1036 Debug_Start ("Floating_Bracket");
1037 Pic.Floater := '<';
1038 Pic.End_Float := Index;
1039 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1041 -- First bracket wasn't counted...
1043 Skip; -- known '<'
1045 loop
1046 if At_End then
1047 return;
1048 end if;
1050 case Look is
1052 when '_' | '0' | '/' =>
1053 Pic.End_Float := Index;
1054 Skip;
1056 when 'B' | 'b' =>
1057 Pic.End_Float := Index;
1058 Pic.Picture.Expanded (Index) := 'b';
1059 Skip;
1061 when '<' =>
1062 Pic.End_Float := Index;
1063 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1064 Skip;
1066 when '9' =>
1067 Number_Completion;
1069 when '$' =>
1070 Leading_Dollar;
1072 when '#' =>
1073 Leading_Pound;
1075 when 'V' | 'v' | '.' =>
1076 Pic.Radix_Position := Index;
1077 Skip;
1078 Number_Fraction_Or_Bracket;
1079 return;
1081 when others =>
1082 return;
1083 end case;
1084 end loop;
1085 end Floating_Bracket;
1088 --------------------
1089 -- Floating_Minus --
1090 --------------------
1092 procedure Floating_Minus is
1093 begin
1094 Debug_Start ("Floating_Minus");
1096 loop
1097 if At_End then
1098 return;
1099 end if;
1101 case Look is
1102 when '_' | '0' | '/' =>
1103 Pic.End_Float := Index;
1104 Skip;
1106 when 'B' | 'b' =>
1107 Pic.End_Float := Index;
1108 Pic.Picture.Expanded (Index) := 'b';
1109 Skip;
1111 when '-' =>
1112 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1113 Pic.End_Float := Index;
1114 Skip;
1116 when '9' =>
1117 Number_Completion;
1118 return;
1120 when '.' | 'V' | 'v' =>
1121 Pic.Radix_Position := Index;
1122 Skip; -- Radix
1124 while Is_Insert loop
1125 Skip;
1126 end loop;
1128 if At_End then
1129 return;
1130 end if;
1132 if Look = '-' then
1133 loop
1134 if At_End then
1135 return;
1136 end if;
1138 case Look is
1140 when '-' =>
1141 Pic.Max_Trailing_Digits :=
1142 Pic.Max_Trailing_Digits + 1;
1143 Pic.End_Float := Index;
1144 Skip;
1146 when '_' | '0' | '/' =>
1147 Skip;
1149 when 'B' | 'b' =>
1150 Pic.Picture.Expanded (Index) := 'b';
1151 Skip;
1153 when others =>
1154 return;
1156 end case;
1157 end loop;
1159 else
1160 Number_Completion;
1161 end if;
1163 return;
1165 when others =>
1166 return;
1167 end case;
1168 end loop;
1169 end Floating_Minus;
1171 -------------------
1172 -- Floating_Plus --
1173 -------------------
1175 procedure Floating_Plus is
1176 begin
1177 Debug_Start ("Floating_Plus");
1179 loop
1180 if At_End then
1181 return;
1182 end if;
1184 case Look is
1185 when '_' | '0' | '/' =>
1186 Pic.End_Float := Index;
1187 Skip;
1189 when 'B' | 'b' =>
1190 Pic.End_Float := Index;
1191 Pic.Picture.Expanded (Index) := 'b';
1192 Skip;
1194 when '+' =>
1195 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1196 Pic.End_Float := Index;
1197 Skip;
1199 when '9' =>
1200 Number_Completion;
1201 return;
1203 when '.' | 'V' | 'v' =>
1204 Pic.Radix_Position := Index;
1205 Skip; -- Radix
1207 while Is_Insert loop
1208 Skip;
1209 end loop;
1211 if At_End then
1212 return;
1213 end if;
1215 if Look = '+' then
1216 loop
1217 if At_End then
1218 return;
1219 end if;
1221 case Look is
1223 when '+' =>
1224 Pic.Max_Trailing_Digits :=
1225 Pic.Max_Trailing_Digits + 1;
1226 Pic.End_Float := Index;
1227 Skip;
1229 when '_' | '0' | '/' =>
1230 Skip;
1232 when 'B' | 'b' =>
1233 Pic.Picture.Expanded (Index) := 'b';
1234 Skip;
1236 when others =>
1237 return;
1239 end case;
1240 end loop;
1242 else
1243 Number_Completion;
1244 end if;
1246 return;
1248 when others =>
1249 return;
1251 end case;
1252 end loop;
1253 end Floating_Plus;
1255 ---------------
1256 -- Is_Insert --
1257 ---------------
1259 function Is_Insert return Boolean is
1260 begin
1261 if At_End then
1262 return False;
1263 end if;
1265 case Pic.Picture.Expanded (Index) is
1267 when '_' | '0' | '/' => return True;
1269 when 'B' | 'b' =>
1270 Pic.Picture.Expanded (Index) := 'b'; -- canonical
1271 return True;
1273 when others => return False;
1274 end case;
1275 end Is_Insert;
1277 --------------------
1278 -- Leading_Dollar --
1279 --------------------
1281 -- Note that Leading_Dollar can be called in either State.
1282 -- It will set state to Okay only if a 9 or (second) $
1283 -- is encountered.
1285 -- Also notice the tricky bit with State and Zero_Suppression.
1286 -- Zero_Suppression is Picture_Error if a '$' or a '9' has been
1287 -- encountered, exactly the cases where State has been set.
1289 procedure Leading_Dollar is
1290 begin
1291 Debug_Start ("Leading_Dollar");
1293 -- Treat as a floating dollar, and unwind otherwise.
1295 Pic.Floater := '$';
1296 Pic.Start_Currency := Index;
1297 Pic.End_Currency := Index;
1298 Pic.Start_Float := Index;
1299 Pic.End_Float := Index;
1301 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1302 -- currency place.
1304 Skip; -- known '$'
1306 loop
1307 if At_End then
1308 return;
1309 end if;
1311 case Look is
1313 when '_' | '0' | '/' =>
1314 Pic.End_Float := Index;
1315 Skip;
1317 -- A trailing insertion character is not part of the
1318 -- floating currency, so need to look ahead.
1320 if Look /= '$' then
1321 Pic.End_Float := Pic.End_Float - 1;
1322 end if;
1324 when 'B' | 'b' =>
1325 Pic.End_Float := Index;
1326 Pic.Picture.Expanded (Index) := 'b';
1327 Skip;
1329 when 'Z' | 'z' =>
1330 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1332 if State = Okay then
1333 raise Picture_Error;
1334 else
1335 -- Will overwrite Floater and Start_Float
1337 Zero_Suppression;
1338 end if;
1340 when '*' =>
1341 if State = Okay then
1342 raise Picture_Error;
1343 else
1344 -- Will overwrite Floater and Start_Float
1346 Star_Suppression;
1347 end if;
1349 when '$' =>
1350 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1351 Pic.End_Float := Index;
1352 Pic.End_Currency := Index;
1353 Set_State (Okay); Skip;
1355 when '9' =>
1356 if State /= Okay then
1357 Pic.Floater := '!';
1358 Pic.Start_Float := Invalid_Position;
1359 Pic.End_Float := Invalid_Position;
1360 end if;
1362 -- A single dollar does not a floating make.
1364 Number_Completion;
1365 return;
1367 when 'V' | 'v' | '.' =>
1368 if State /= Okay then
1369 Pic.Floater := '!';
1370 Pic.Start_Float := Invalid_Position;
1371 Pic.End_Float := Invalid_Position;
1372 end if;
1374 -- Only one dollar before the sign is okay,
1375 -- but doesn't float.
1377 Pic.Radix_Position := Index;
1378 Skip;
1379 Number_Fraction_Or_Dollar;
1380 return;
1382 when others =>
1383 return;
1385 end case;
1386 end loop;
1387 end Leading_Dollar;
1389 -------------------
1390 -- Leading_Pound --
1391 -------------------
1393 -- This one is complex! A Leading_Pound can be fixed or floating,
1394 -- but in some cases the decision has to be deferred until we leave
1395 -- this procedure. Also note that Leading_Pound can be called in
1396 -- either State.
1398 -- It will set state to Okay only if a 9 or (second) # is
1399 -- encountered.
1401 -- One Last note: In ambiguous cases, the currency is treated as
1402 -- floating unless there is only one '#'.
1404 procedure Leading_Pound is
1406 Inserts : Boolean := False;
1407 -- Set to True if a '_', '0', '/', 'B', or 'b' is encountered
1409 Must_Float : Boolean := False;
1410 -- Set to true if a '#' occurs after an insert.
1412 begin
1413 Debug_Start ("Leading_Pound");
1415 -- Treat as a floating currency. If it isn't, this will be
1416 -- overwritten later.
1418 Pic.Floater := '#';
1420 Pic.Start_Currency := Index;
1421 Pic.End_Currency := Index;
1422 Pic.Start_Float := Index;
1423 Pic.End_Float := Index;
1425 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1426 -- currency place.
1428 Pic.Max_Currency_Digits := 1; -- we've seen one.
1430 Skip; -- known '#'
1432 loop
1433 if At_End then
1434 return;
1435 end if;
1437 case Look is
1439 when '_' | '0' | '/' =>
1440 Pic.End_Float := Index;
1441 Inserts := True;
1442 Skip;
1444 when 'B' | 'b' =>
1445 Pic.Picture.Expanded (Index) := 'b';
1446 Pic.End_Float := Index;
1447 Inserts := True;
1448 Skip;
1450 when 'Z' | 'z' =>
1451 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1453 if Must_Float then
1454 raise Picture_Error;
1455 else
1456 Pic.Max_Leading_Digits := 0;
1458 -- Will overwrite Floater and Start_Float
1460 Zero_Suppression;
1461 end if;
1463 when '*' =>
1464 if Must_Float then
1465 raise Picture_Error;
1466 else
1467 Pic.Max_Leading_Digits := 0;
1469 -- Will overwrite Floater and Start_Float
1471 Star_Suppression;
1472 end if;
1474 when '#' =>
1475 if Inserts then
1476 Must_Float := True;
1477 end if;
1479 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1480 Pic.End_Float := Index;
1481 Pic.End_Currency := Index;
1482 Set_State (Okay);
1483 Skip;
1485 when '9' =>
1486 if State /= Okay then
1488 -- A single '#' doesn't float.
1490 Pic.Floater := '!';
1491 Pic.Start_Float := Invalid_Position;
1492 Pic.End_Float := Invalid_Position;
1493 end if;
1495 Number_Completion;
1496 return;
1498 when 'V' | 'v' | '.' =>
1499 if State /= Okay then
1500 Pic.Floater := '!';
1501 Pic.Start_Float := Invalid_Position;
1502 Pic.End_Float := Invalid_Position;
1503 end if;
1505 -- Only one pound before the sign is okay,
1506 -- but doesn't float.
1508 Pic.Radix_Position := Index;
1509 Skip;
1510 Number_Fraction_Or_Pound;
1511 return;
1513 when others =>
1514 return;
1515 end case;
1516 end loop;
1517 end Leading_Pound;
1519 ----------
1520 -- Look --
1521 ----------
1523 function Look return Character is
1524 begin
1525 if At_End then
1526 raise Picture_Error;
1527 end if;
1529 return Pic.Picture.Expanded (Index);
1530 end Look;
1532 ------------
1533 -- Number --
1534 ------------
1536 procedure Number is
1537 begin
1538 Debug_Start ("Number");
1540 loop
1542 case Look is
1543 when '_' | '0' | '/' =>
1544 Skip;
1546 when 'B' | 'b' =>
1547 Pic.Picture.Expanded (Index) := 'b';
1548 Skip;
1550 when '9' =>
1551 Computed_BWZ := False;
1552 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1553 Set_State (Okay);
1554 Skip;
1556 when '.' | 'V' | 'v' =>
1557 Pic.Radix_Position := Index;
1558 Skip;
1559 Number_Fraction;
1560 return;
1562 when others =>
1563 return;
1565 end case;
1567 if At_End then
1568 return;
1569 end if;
1571 -- Will return in Okay state if a '9' was seen.
1573 end loop;
1574 end Number;
1576 -----------------------
1577 -- Number_Completion --
1578 -----------------------
1580 procedure Number_Completion is
1581 begin
1582 Debug_Start ("Number_Completion");
1584 while not At_End loop
1585 case Look is
1587 when '_' | '0' | '/' =>
1588 Skip;
1590 when 'B' | 'b' =>
1591 Pic.Picture.Expanded (Index) := 'b';
1592 Skip;
1594 when '9' =>
1595 Computed_BWZ := False;
1596 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1597 Set_State (Okay);
1598 Skip;
1600 when 'V' | 'v' | '.' =>
1601 Pic.Radix_Position := Index;
1602 Skip;
1603 Number_Fraction;
1604 return;
1606 when others =>
1607 return;
1608 end case;
1609 end loop;
1610 end Number_Completion;
1612 ---------------------
1613 -- Number_Fraction --
1614 ---------------------
1616 procedure Number_Fraction is
1617 begin
1618 -- Note that number fraction can be called in either State.
1619 -- It will set state to Valid only if a 9 is encountered.
1621 Debug_Start ("Number_Fraction");
1623 loop
1624 if At_End then
1625 return;
1626 end if;
1628 case Look is
1629 when '_' | '0' | '/' =>
1630 Skip;
1632 when 'B' | 'b' =>
1633 Pic.Picture.Expanded (Index) := 'b';
1634 Skip;
1636 when '9' =>
1637 Computed_BWZ := False;
1638 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1639 Set_State (Okay); Skip;
1641 when others =>
1642 return;
1643 end case;
1644 end loop;
1645 end Number_Fraction;
1647 --------------------------------
1648 -- Number_Fraction_Or_Bracket --
1649 --------------------------------
1651 procedure Number_Fraction_Or_Bracket is
1652 begin
1653 Debug_Start ("Number_Fraction_Or_Bracket");
1655 loop
1656 if At_End then
1657 return;
1658 end if;
1660 case Look is
1662 when '_' | '0' | '/' => Skip;
1664 when 'B' | 'b' =>
1665 Pic.Picture.Expanded (Index) := 'b';
1666 Skip;
1668 when '<' =>
1669 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1670 Pic.End_Float := Index;
1671 Skip;
1673 loop
1674 if At_End then
1675 return;
1676 end if;
1678 case Look is
1679 when '_' | '0' | '/' =>
1680 Skip;
1682 when 'B' | 'b' =>
1683 Pic.Picture.Expanded (Index) := 'b';
1684 Skip;
1686 when '<' =>
1687 Pic.Max_Trailing_Digits :=
1688 Pic.Max_Trailing_Digits + 1;
1689 Pic.End_Float := Index;
1690 Skip;
1692 when others =>
1693 return;
1694 end case;
1695 end loop;
1697 when others =>
1698 Number_Fraction;
1699 return;
1700 end case;
1701 end loop;
1702 end Number_Fraction_Or_Bracket;
1704 -------------------------------
1705 -- Number_Fraction_Or_Dollar --
1706 -------------------------------
1708 procedure Number_Fraction_Or_Dollar is
1709 begin
1710 Debug_Start ("Number_Fraction_Or_Dollar");
1712 loop
1713 if At_End then
1714 return;
1715 end if;
1717 case Look is
1718 when '_' | '0' | '/' =>
1719 Skip;
1721 when 'B' | 'b' =>
1722 Pic.Picture.Expanded (Index) := 'b';
1723 Skip;
1725 when '$' =>
1726 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1727 Pic.End_Float := Index;
1728 Skip;
1730 loop
1731 if At_End then
1732 return;
1733 end if;
1735 case Look is
1736 when '_' | '0' | '/' =>
1737 Skip;
1739 when 'B' | 'b' =>
1740 Pic.Picture.Expanded (Index) := 'b';
1741 Skip;
1743 when '$' =>
1744 Pic.Max_Trailing_Digits :=
1745 Pic.Max_Trailing_Digits + 1;
1746 Pic.End_Float := Index;
1747 Skip;
1749 when others =>
1750 return;
1751 end case;
1752 end loop;
1754 when others =>
1755 Number_Fraction;
1756 return;
1757 end case;
1758 end loop;
1759 end Number_Fraction_Or_Dollar;
1761 ------------------------------
1762 -- Number_Fraction_Or_Pound --
1763 ------------------------------
1765 procedure Number_Fraction_Or_Pound is
1766 begin
1767 loop
1768 if At_End then
1769 return;
1770 end if;
1772 case Look is
1774 when '_' | '0' | '/' =>
1775 Skip;
1777 when 'B' | 'b' =>
1778 Pic.Picture.Expanded (Index) := 'b';
1779 Skip;
1781 when '#' =>
1782 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1783 Pic.End_Float := Index;
1784 Skip;
1786 loop
1787 if At_End then
1788 return;
1789 end if;
1791 case Look is
1793 when '_' | '0' | '/' =>
1794 Skip;
1796 when 'B' | 'b' =>
1797 Pic.Picture.Expanded (Index) := 'b';
1798 Skip;
1800 when '#' =>
1801 Pic.Max_Trailing_Digits :=
1802 Pic.Max_Trailing_Digits + 1;
1803 Pic.End_Float := Index;
1804 Skip;
1806 when others =>
1807 return;
1809 end case;
1810 end loop;
1812 when others =>
1813 Number_Fraction;
1814 return;
1816 end case;
1817 end loop;
1818 end Number_Fraction_Or_Pound;
1820 ----------------------------------
1821 -- Number_Fraction_Or_Star_Fill --
1822 ----------------------------------
1824 procedure Number_Fraction_Or_Star_Fill is
1825 begin
1826 Debug_Start ("Number_Fraction_Or_Star_Fill");
1828 loop
1829 if At_End then
1830 return;
1831 end if;
1833 case Look is
1835 when '_' | '0' | '/' =>
1836 Skip;
1838 when 'B' | 'b' =>
1839 Pic.Picture.Expanded (Index) := 'b';
1840 Skip;
1842 when '*' =>
1843 Pic.Star_Fill := True;
1844 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1845 Pic.End_Float := Index;
1846 Skip;
1848 loop
1849 if At_End then
1850 return;
1851 end if;
1853 case Look is
1855 when '_' | '0' | '/' =>
1856 Skip;
1858 when 'B' | 'b' =>
1859 Pic.Picture.Expanded (Index) := 'b';
1860 Skip;
1862 when '*' =>
1863 Pic.Star_Fill := True;
1864 Pic.Max_Trailing_Digits :=
1865 Pic.Max_Trailing_Digits + 1;
1866 Pic.End_Float := Index;
1867 Skip;
1869 when others =>
1870 return;
1871 end case;
1872 end loop;
1874 when others =>
1875 Number_Fraction;
1876 return;
1878 end case;
1879 end loop;
1880 end Number_Fraction_Or_Star_Fill;
1882 -------------------------------
1883 -- Number_Fraction_Or_Z_Fill --
1884 -------------------------------
1886 procedure Number_Fraction_Or_Z_Fill is
1887 begin
1888 Debug_Start ("Number_Fraction_Or_Z_Fill");
1890 loop
1891 if At_End then
1892 return;
1893 end if;
1895 case Look is
1897 when '_' | '0' | '/' =>
1898 Skip;
1900 when 'B' | 'b' =>
1901 Pic.Picture.Expanded (Index) := 'b';
1902 Skip;
1904 when 'Z' | 'z' =>
1905 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1906 Pic.End_Float := Index;
1907 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1909 Skip;
1911 loop
1912 if At_End then
1913 return;
1914 end if;
1916 case Look is
1918 when '_' | '0' | '/' =>
1919 Skip;
1921 when 'B' | 'b' =>
1922 Pic.Picture.Expanded (Index) := 'b';
1923 Skip;
1925 when 'Z' | 'z' =>
1926 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1928 Pic.Max_Trailing_Digits :=
1929 Pic.Max_Trailing_Digits + 1;
1930 Pic.End_Float := Index;
1931 Skip;
1933 when others =>
1934 return;
1935 end case;
1936 end loop;
1938 when others =>
1939 Number_Fraction;
1940 return;
1941 end case;
1942 end loop;
1943 end Number_Fraction_Or_Z_Fill;
1945 -----------------------
1946 -- Optional_RHS_Sign --
1947 -----------------------
1949 procedure Optional_RHS_Sign is
1950 begin
1951 Debug_Start ("Optional_RHS_Sign");
1953 if At_End then
1954 return;
1955 end if;
1957 case Look is
1959 when '+' | '-' =>
1960 Pic.Sign_Position := Index;
1961 Skip;
1962 return;
1964 when 'C' | 'c' =>
1965 Pic.Sign_Position := Index;
1966 Pic.Picture.Expanded (Index) := 'C';
1967 Skip;
1969 if Look = 'R' or Look = 'r' then
1970 Pic.Second_Sign := Index;
1971 Pic.Picture.Expanded (Index) := 'R';
1972 Skip;
1974 else
1975 raise Picture_Error;
1976 end if;
1978 return;
1980 when 'D' | 'd' =>
1981 Pic.Sign_Position := Index;
1982 Pic.Picture.Expanded (Index) := 'D';
1983 Skip;
1985 if Look = 'B' or Look = 'b' then
1986 Pic.Second_Sign := Index;
1987 Pic.Picture.Expanded (Index) := 'B';
1988 Skip;
1990 else
1991 raise Picture_Error;
1992 end if;
1994 return;
1996 when '>' =>
1997 if Pic.Picture.Expanded (Pic.Sign_Position) = '<' then
1998 Pic.Second_Sign := Index;
1999 Skip;
2001 else
2002 raise Picture_Error;
2003 end if;
2005 when others =>
2006 return;
2008 end case;
2009 end Optional_RHS_Sign;
2011 -------------
2012 -- Picture --
2013 -------------
2015 -- Note that Picture can be called in either State.
2017 -- It will set state to Valid only if a 9 is encountered or floating
2018 -- currency is called.
2020 procedure Picture is
2021 begin
2022 Debug_Start ("Picture");
2024 loop
2025 if At_End then
2026 return;
2027 end if;
2029 case Look is
2031 when '_' | '0' | '/' =>
2032 Skip;
2034 when 'B' | 'b' =>
2035 Pic.Picture.Expanded (Index) := 'b';
2036 Skip;
2038 when '$' =>
2039 Leading_Dollar;
2040 return;
2042 when '#' =>
2043 Leading_Pound;
2044 return;
2046 when '9' =>
2047 Computed_BWZ := False;
2048 Set_State (Okay);
2049 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2050 Skip;
2052 when 'V' | 'v' | '.' =>
2053 Pic.Radix_Position := Index;
2054 Skip;
2055 Number_Fraction;
2056 Trailing_Currency;
2057 return;
2059 when others =>
2060 return;
2062 end case;
2063 end loop;
2064 end Picture;
2066 ---------------------
2067 -- Picture_Bracket --
2068 ---------------------
2070 procedure Picture_Bracket is
2071 begin
2072 Pic.Sign_Position := Index;
2073 Debug_Start ("Picture_Bracket");
2074 Pic.Sign_Position := Index;
2076 -- Treat as a floating sign, and unwind otherwise.
2078 Pic.Floater := '<';
2079 Pic.Start_Float := Index;
2080 Pic.End_Float := Index;
2082 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2083 -- sign place.
2085 Skip; -- Known Bracket
2087 loop
2088 case Look is
2090 when '_' | '0' | '/' =>
2091 Pic.End_Float := Index;
2092 Skip;
2094 when 'B' | 'b' =>
2095 Pic.End_Float := Index;
2096 Pic.Picture.Expanded (Index) := 'b';
2097 Skip;
2099 when '<' =>
2100 Set_State (Okay); -- "<<>" is enough.
2101 Floating_Bracket;
2102 Trailing_Currency;
2103 Trailing_Bracket;
2104 return;
2106 when '$' | '#' | '9' | '*' =>
2107 if State /= Okay then
2108 Pic.Floater := '!';
2109 Pic.Start_Float := Invalid_Position;
2110 Pic.End_Float := Invalid_Position;
2111 end if;
2113 Picture;
2114 Trailing_Bracket;
2115 Set_State (Okay);
2116 return;
2118 when '.' | 'V' | 'v' =>
2119 if State /= Okay then
2120 Pic.Floater := '!';
2121 Pic.Start_Float := Invalid_Position;
2122 Pic.End_Float := Invalid_Position;
2123 end if;
2125 -- Don't assume that state is okay, haven't seen a digit
2127 Picture;
2128 Trailing_Bracket;
2129 return;
2131 when others =>
2132 raise Picture_Error;
2134 end case;
2135 end loop;
2136 end Picture_Bracket;
2138 -------------------
2139 -- Picture_Minus --
2140 -------------------
2142 procedure Picture_Minus is
2143 begin
2144 Debug_Start ("Picture_Minus");
2146 Pic.Sign_Position := Index;
2148 -- Treat as a floating sign, and unwind otherwise.
2150 Pic.Floater := '-';
2151 Pic.Start_Float := Index;
2152 Pic.End_Float := Index;
2154 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2155 -- sign place.
2157 Skip; -- Known Minus
2159 loop
2160 case Look is
2162 when '_' | '0' | '/' =>
2163 Pic.End_Float := Index;
2164 Skip;
2166 when 'B' | 'b' =>
2167 Pic.End_Float := Index;
2168 Pic.Picture.Expanded (Index) := 'b';
2169 Skip;
2171 when '-' =>
2172 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2173 Pic.End_Float := Index;
2174 Skip;
2175 Set_State (Okay); -- "-- " is enough.
2176 Floating_Minus;
2177 Trailing_Currency;
2178 return;
2180 when '$' | '#' | '9' | '*' =>
2181 if State /= Okay then
2182 Pic.Floater := '!';
2183 Pic.Start_Float := Invalid_Position;
2184 Pic.End_Float := Invalid_Position;
2185 end if;
2187 Picture;
2188 Set_State (Okay);
2189 return;
2191 when 'Z' | 'z' =>
2193 -- Can't have Z and a floating sign.
2195 if State = Okay then
2196 Set_State (Reject);
2197 end if;
2199 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2200 Zero_Suppression;
2201 Trailing_Currency;
2202 Optional_RHS_Sign;
2203 return;
2205 when '.' | 'V' | 'v' =>
2206 if State /= Okay then
2207 Pic.Floater := '!';
2208 Pic.Start_Float := Invalid_Position;
2209 Pic.End_Float := Invalid_Position;
2210 end if;
2212 -- Don't assume that state is okay, haven't seen a digit.
2214 Picture;
2215 return;
2217 when others =>
2218 return;
2220 end case;
2221 end loop;
2222 end Picture_Minus;
2224 ------------------
2225 -- Picture_Plus --
2226 ------------------
2228 procedure Picture_Plus is
2229 begin
2230 Debug_Start ("Picture_Plus");
2231 Pic.Sign_Position := Index;
2233 -- Treat as a floating sign, and unwind otherwise.
2235 Pic.Floater := '+';
2236 Pic.Start_Float := Index;
2237 Pic.End_Float := Index;
2239 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2240 -- sign place.
2242 Skip; -- Known Plus
2244 loop
2245 case Look is
2247 when '_' | '0' | '/' =>
2248 Pic.End_Float := Index;
2249 Skip;
2251 when 'B' | 'b' =>
2252 Pic.End_Float := Index;
2253 Pic.Picture.Expanded (Index) := 'b';
2254 Skip;
2256 when '+' =>
2257 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2258 Pic.End_Float := Index;
2259 Skip;
2260 Set_State (Okay); -- "++" is enough.
2261 Floating_Plus;
2262 Trailing_Currency;
2263 return;
2265 when '$' | '#' | '9' | '*' =>
2266 if State /= Okay then
2267 Pic.Floater := '!';
2268 Pic.Start_Float := Invalid_Position;
2269 Pic.End_Float := Invalid_Position;
2270 end if;
2272 Picture;
2273 Set_State (Okay);
2274 return;
2276 when 'Z' | 'z' =>
2277 if State = Okay then
2278 Set_State (Reject);
2279 end if;
2281 -- Can't have Z and a floating sign.
2283 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2285 -- '+Z' is acceptable
2287 Set_State (Okay);
2289 Zero_Suppression;
2290 Trailing_Currency;
2291 Optional_RHS_Sign;
2292 return;
2294 when '.' | 'V' | 'v' =>
2295 if State /= Okay then
2296 Pic.Floater := '!';
2297 Pic.Start_Float := Invalid_Position;
2298 Pic.End_Float := Invalid_Position;
2299 end if;
2301 -- Don't assume that state is okay, haven't seen a digit.
2303 Picture;
2304 return;
2306 when others =>
2307 return;
2309 end case;
2310 end loop;
2311 end Picture_Plus;
2313 --------------------
2314 -- Picture_String --
2315 --------------------
2317 procedure Picture_String is
2318 begin
2319 Debug_Start ("Picture_String");
2321 while Is_Insert loop
2322 Skip;
2323 end loop;
2325 case Look is
2327 when '$' | '#' =>
2328 Picture;
2329 Optional_RHS_Sign;
2331 when '+' =>
2332 Picture_Plus;
2334 when '-' =>
2335 Picture_Minus;
2337 when '<' =>
2338 Picture_Bracket;
2340 when 'Z' | 'z' =>
2341 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2342 Zero_Suppression;
2343 Trailing_Currency;
2344 Optional_RHS_Sign;
2346 when '*' =>
2347 Star_Suppression;
2348 Trailing_Currency;
2349 Optional_RHS_Sign;
2351 when '9' | '.' | 'V' | 'v' =>
2352 Number;
2353 Trailing_Currency;
2354 Optional_RHS_Sign;
2356 when others =>
2357 raise Picture_Error;
2359 end case;
2361 -- Blank when zero either if the PIC does not contain a '9' or if
2362 -- requested by the user and no '*'
2364 Pic.Blank_When_Zero :=
2365 (Computed_BWZ or Pic.Blank_When_Zero) and not Pic.Star_Fill;
2367 -- Star fill if '*' and no '9'.
2369 Pic.Star_Fill := Pic.Star_Fill and Computed_BWZ;
2371 if not At_End then
2372 Set_State (Reject);
2373 end if;
2375 end Picture_String;
2377 ---------------
2378 -- Set_State --
2379 ---------------
2381 procedure Set_State (L : Legality) is
2382 begin
2383 if Debug then Ada.Text_IO.Put_Line
2384 (" Set state from " & Legality'Image (State) &
2385 " to " & Legality'Image (L));
2386 end if;
2388 State := L;
2389 end Set_State;
2391 ----------
2392 -- Skip --
2393 ----------
2395 procedure Skip is
2396 begin
2397 if Debug then Ada.Text_IO.Put_Line
2398 (" Skip " & Pic.Picture.Expanded (Index));
2399 end if;
2401 Index := Index + 1;
2402 end Skip;
2404 ----------------------
2405 -- Star_Suppression --
2406 ----------------------
2408 procedure Star_Suppression is
2409 begin
2410 Debug_Start ("Star_Suppression");
2411 Pic.Floater := '*';
2412 Pic.Start_Float := Index;
2413 Pic.End_Float := Index;
2414 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2415 Set_State (Okay);
2417 -- Even a single * is a valid picture
2419 Pic.Star_Fill := True;
2420 Skip; -- Known *
2422 loop
2423 if At_End then
2424 return;
2425 end if;
2427 case Look is
2429 when '_' | '0' | '/' =>
2430 Pic.End_Float := Index;
2431 Skip;
2433 when 'B' | 'b' =>
2434 Pic.End_Float := Index;
2435 Pic.Picture.Expanded (Index) := 'b';
2436 Skip;
2438 when '*' =>
2439 Pic.End_Float := Index;
2440 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2441 Set_State (Okay); Skip;
2443 when '9' =>
2444 Set_State (Okay);
2445 Number_Completion;
2446 return;
2448 when '.' | 'V' | 'v' =>
2449 Pic.Radix_Position := Index;
2450 Skip;
2451 Number_Fraction_Or_Star_Fill;
2452 return;
2454 when '#' | '$' =>
2455 Trailing_Currency;
2456 Set_State (Okay);
2457 return;
2459 when others => raise Picture_Error;
2460 end case;
2461 end loop;
2462 end Star_Suppression;
2464 ----------------------
2465 -- Trailing_Bracket --
2466 ----------------------
2468 procedure Trailing_Bracket is
2469 begin
2470 Debug_Start ("Trailing_Bracket");
2472 if Look = '>' then
2473 Pic.Second_Sign := Index;
2474 Skip;
2475 else
2476 raise Picture_Error;
2477 end if;
2478 end Trailing_Bracket;
2480 -----------------------
2481 -- Trailing_Currency --
2482 -----------------------
2484 procedure Trailing_Currency is
2485 begin
2486 Debug_Start ("Trailing_Currency");
2488 if At_End then
2489 return;
2490 end if;
2492 if Look = '$' then
2493 Pic.Start_Currency := Index;
2494 Pic.End_Currency := Index;
2495 Skip;
2497 else
2498 while not At_End and then Look = '#' loop
2499 if Pic.Start_Currency = Invalid_Position then
2500 Pic.Start_Currency := Index;
2501 end if;
2503 Pic.End_Currency := Index;
2504 Skip;
2505 end loop;
2506 end if;
2508 loop
2509 if At_End then
2510 return;
2511 end if;
2513 case Look is
2514 when '_' | '0' | '/' => Skip;
2516 when 'B' | 'b' =>
2517 Pic.Picture.Expanded (Index) := 'b';
2518 Skip;
2520 when others => return;
2521 end case;
2522 end loop;
2523 end Trailing_Currency;
2525 ----------------------
2526 -- Zero_Suppression --
2527 ----------------------
2529 procedure Zero_Suppression is
2530 begin
2531 Debug_Start ("Zero_Suppression");
2533 Pic.Floater := 'Z';
2534 Pic.Start_Float := Index;
2535 Pic.End_Float := Index;
2536 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2537 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2539 Skip; -- Known Z
2541 loop
2542 -- Even a single Z is a valid picture
2544 if At_End then
2545 Set_State (Okay);
2546 return;
2547 end if;
2549 case Look is
2550 when '_' | '0' | '/' =>
2551 Pic.End_Float := Index;
2552 Skip;
2554 when 'B' | 'b' =>
2555 Pic.End_Float := Index;
2556 Pic.Picture.Expanded (Index) := 'b';
2557 Skip;
2559 when 'Z' | 'z' =>
2560 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2562 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2563 Pic.End_Float := Index;
2564 Set_State (Okay);
2565 Skip;
2567 when '9' =>
2568 Set_State (Okay);
2569 Number_Completion;
2570 return;
2572 when '.' | 'V' | 'v' =>
2573 Pic.Radix_Position := Index;
2574 Skip;
2575 Number_Fraction_Or_Z_Fill;
2576 return;
2578 when '#' | '$' =>
2579 Trailing_Currency;
2580 Set_State (Okay);
2581 return;
2583 when others =>
2584 return;
2585 end case;
2586 end loop;
2587 end Zero_Suppression;
2589 -- Start of processing for Precalculate
2591 begin
2592 Picture_String;
2594 if Debug then
2595 Ada.Text_IO.New_Line;
2596 Ada.Text_IO.Put (" Picture : """ &
2597 Pic.Picture.Expanded (1 .. Pic.Picture.Length) & """,");
2598 Ada.Text_IO.Put (" Floater : '" & Pic.Floater & "',");
2599 end if;
2601 if State = Reject then
2602 raise Picture_Error;
2603 end if;
2605 Debug_Integer (Pic.Radix_Position, "Radix Positon : ");
2606 Debug_Integer (Pic.Sign_Position, "Sign Positon : ");
2607 Debug_Integer (Pic.Second_Sign, "Second Sign : ");
2608 Debug_Integer (Pic.Start_Float, "Start Float : ");
2609 Debug_Integer (Pic.End_Float, "End Float : ");
2610 Debug_Integer (Pic.Start_Currency, "Start Currency : ");
2611 Debug_Integer (Pic.End_Currency, "End Currency : ");
2612 Debug_Integer (Pic.Max_Leading_Digits, "Max Leading Digits : ");
2613 Debug_Integer (Pic.Max_Trailing_Digits, "Max Trailing Digits : ");
2615 if Debug then
2616 Ada.Text_IO.New_Line;
2617 end if;
2619 exception
2621 when Constraint_Error =>
2623 -- To deal with special cases like null strings.
2625 raise Picture_Error;
2627 end Precalculate;
2629 ----------------
2630 -- To_Picture --
2631 ----------------
2633 function To_Picture
2634 (Pic_String : in String;
2635 Blank_When_Zero : in Boolean := False)
2636 return Picture
2638 Result : Picture;
2640 begin
2641 declare
2642 Item : constant String := Expand (Pic_String);
2644 begin
2645 Result.Contents.Picture := (Item'Length, Item);
2646 Result.Contents.Original_BWZ := Blank_When_Zero;
2647 Result.Contents.Blank_When_Zero := Blank_When_Zero;
2648 Precalculate (Result.Contents);
2649 return Result;
2650 end;
2652 exception
2653 when others =>
2654 raise Picture_Error;
2656 end To_Picture;
2658 -----------
2659 -- Valid --
2660 -----------
2662 function Valid
2663 (Pic_String : in String;
2664 Blank_When_Zero : in Boolean := False)
2665 return Boolean
2667 begin
2668 declare
2669 Expanded_Pic : constant String := Expand (Pic_String);
2670 -- Raises Picture_Error if Item not well-formed
2672 Format_Rec : Format_Record;
2674 begin
2675 Format_Rec.Picture := (Expanded_Pic'Length, Expanded_Pic);
2676 Format_Rec.Blank_When_Zero := Blank_When_Zero;
2677 Format_Rec.Original_BWZ := Blank_When_Zero;
2678 Precalculate (Format_Rec);
2680 -- False only if Blank_When_0 is True but the pic string has a '*'
2682 return not Blank_When_Zero or
2683 Strings_Fixed.Index (Expanded_Pic, "*") = 0;
2684 end;
2686 exception
2687 when others => return False;
2689 end Valid;
2691 --------------------
2692 -- Decimal_Output --
2693 --------------------
2695 package body Decimal_Output is
2697 -----------
2698 -- Image --
2699 -----------
2701 function Image
2702 (Item : in Num;
2703 Pic : in Picture;
2704 Currency : in String := Default_Currency;
2705 Fill : in Character := Default_Fill;
2706 Separator : in Character := Default_Separator;
2707 Radix_Mark : in Character := Default_Radix_Mark)
2708 return String
2710 begin
2711 return Format_Number
2712 (Pic.Contents, Num'Image (Item),
2713 Currency, Fill, Separator, Radix_Mark);
2714 end Image;
2716 ------------
2717 -- Length --
2718 ------------
2720 function Length
2721 (Pic : in Picture;
2722 Currency : in String := Default_Currency)
2723 return Natural
2725 Picstr : constant String := Pic_String (Pic);
2726 V_Adjust : Integer := 0;
2727 Cur_Adjust : Integer := 0;
2729 begin
2730 -- Check if Picstr has 'V' or '$'
2732 -- If 'V', then length is 1 less than otherwise
2734 -- If '$', then length is Currency'Length-1 more than otherwise
2736 -- This should use the string handling package ???
2738 for J in Picstr'Range loop
2739 if Picstr (J) = 'V' then
2740 V_Adjust := -1;
2742 elsif Picstr (J) = '$' then
2743 Cur_Adjust := Currency'Length - 1;
2744 end if;
2745 end loop;
2747 return Picstr'Length - V_Adjust + Cur_Adjust;
2748 end Length;
2750 ---------
2751 -- Put --
2752 ---------
2754 procedure Put
2755 (File : in Text_IO.File_Type;
2756 Item : in Num;
2757 Pic : in Picture;
2758 Currency : in String := Default_Currency;
2759 Fill : in Character := Default_Fill;
2760 Separator : in Character := Default_Separator;
2761 Radix_Mark : in Character := Default_Radix_Mark)
2763 begin
2764 Text_IO.Put (File, Image (Item, Pic,
2765 Currency, Fill, Separator, Radix_Mark));
2766 end Put;
2768 procedure Put
2769 (Item : in Num;
2770 Pic : in Picture;
2771 Currency : in String := Default_Currency;
2772 Fill : in Character := Default_Fill;
2773 Separator : in Character := Default_Separator;
2774 Radix_Mark : in Character := Default_Radix_Mark)
2776 begin
2777 Text_IO.Put (Image (Item, Pic,
2778 Currency, Fill, Separator, Radix_Mark));
2779 end Put;
2781 procedure Put
2782 (To : out String;
2783 Item : in Num;
2784 Pic : in Picture;
2785 Currency : in String := Default_Currency;
2786 Fill : in Character := Default_Fill;
2787 Separator : in Character := Default_Separator;
2788 Radix_Mark : in Character := Default_Radix_Mark)
2790 Result : constant String :=
2791 Image (Item, Pic, Currency, Fill, Separator, Radix_Mark);
2793 begin
2794 if Result'Length > To'Length then
2795 raise Text_IO.Layout_Error;
2796 else
2797 Strings_Fixed.Move (Source => Result, Target => To,
2798 Justify => Strings.Right);
2799 end if;
2800 end Put;
2802 -----------
2803 -- Valid --
2804 -----------
2806 function Valid
2807 (Item : Num;
2808 Pic : in Picture;
2809 Currency : in String := Default_Currency)
2810 return Boolean
2812 begin
2813 declare
2814 Temp : constant String := Image (Item, Pic, Currency);
2815 pragma Warnings (Off, Temp);
2816 begin
2817 return True;
2818 end;
2820 exception
2821 when Layout_Error => return False;
2823 end Valid;
2825 end Decimal_Output;
2827 end Ada.Text_IO.Editing;