[AArch64] Improve scheduling model for X-Gene
[official-gcc.git] / gcc / ada / libgnat / a-teioed.adb
blob4260682b69d7f61ed110c6a736cb8035177fe11c
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME 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 -- Copyright (C) 1992-2017, Free Software Foundation, Inc. --
10 -- --
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. --
17 -- --
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. --
21 -- --
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/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 with Ada.Strings.Fixed;
33 package body Ada.Text_IO.Editing is
35 package Strings renames Ada.Strings;
36 package Strings_Fixed renames Ada.Strings.Fixed;
37 package Text_IO renames Ada.Text_IO;
39 ---------------------
40 -- Blank_When_Zero --
41 ---------------------
43 function Blank_When_Zero (Pic : Picture) return Boolean is
44 begin
45 return Pic.Contents.Original_BWZ;
46 end Blank_When_Zero;
48 ------------
49 -- Expand --
50 ------------
52 function Expand (Picture : String) return String is
53 Result : String (1 .. MAX_PICSIZE);
54 Picture_Index : Integer := Picture'First;
55 Result_Index : Integer := Result'First;
56 Count : Natural;
57 Last : Integer;
59 package Int_IO is new Ada.Text_IO.Integer_IO (Integer);
61 begin
62 if Picture'Length < 1 then
63 raise Picture_Error;
64 end if;
66 if Picture (Picture'First) = '(' then
67 raise Picture_Error;
68 end if;
70 loop
71 case Picture (Picture_Index) is
72 when '(' =>
73 Int_IO.Get
74 (Picture (Picture_Index + 1 .. Picture'Last), Count, Last);
76 if Picture (Last + 1) /= ')' then
77 raise Picture_Error;
78 end if;
80 -- In what follows note that one copy of the repeated character
81 -- has already been made, so a count of one is a no-op, and a
82 -- count of zero erases a character.
84 if Result_Index + Count - 2 > Result'Last then
85 raise Picture_Error;
86 end if;
88 for J in 2 .. Count loop
89 Result (Result_Index + J - 2) := Picture (Picture_Index - 1);
90 end loop;
92 Result_Index := Result_Index + Count - 1;
94 -- Last + 1 was a ')' throw it away too
96 Picture_Index := Last + 2;
98 when ')' =>
99 raise Picture_Error;
101 when others =>
102 if Result_Index > Result'Last then
103 raise Picture_Error;
104 end if;
106 Result (Result_Index) := Picture (Picture_Index);
107 Picture_Index := Picture_Index + 1;
108 Result_Index := Result_Index + 1;
109 end case;
111 exit when Picture_Index > Picture'Last;
112 end loop;
114 return Result (1 .. Result_Index - 1);
116 exception
117 when others =>
118 raise Picture_Error;
119 end Expand;
121 -------------------
122 -- Format_Number --
123 -------------------
125 function Format_Number
126 (Pic : Format_Record;
127 Number : String;
128 Currency_Symbol : String;
129 Fill_Character : Character;
130 Separator_Character : Character;
131 Radix_Point : Character) 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;
142 In_Currency : Boolean := False;
144 Dollar : Boolean := False;
145 -- Overridden immediately if necessary
147 Zero : Boolean := True;
148 -- Set to False when a non-zero digit is output
150 begin
152 -- If the picture has fewer decimal places than the number, the image
153 -- must be rounded according to the usual rules.
155 if Attrs.Has_Fraction then
156 declare
157 R : constant Integer :=
158 (Attrs.End_Of_Fraction - Attrs.Start_Of_Fraction + 1)
159 - Pic.Max_Trailing_Digits;
160 R_Pos : Integer;
162 begin
163 if R > 0 then
164 R_Pos := Attrs.End_Of_Fraction - R;
166 if Rounded (R_Pos + 1) > '4' then
168 if Rounded (R_Pos) = '.' then
169 R_Pos := R_Pos - 1;
170 end if;
172 if Rounded (R_Pos) /= '9' then
173 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
174 else
175 Rounded (R_Pos) := '0';
176 R_Pos := R_Pos - 1;
178 while R_Pos > 1 loop
179 if Rounded (R_Pos) = '.' then
180 R_Pos := R_Pos - 1;
181 end if;
183 if Rounded (R_Pos) /= '9' then
184 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
185 exit;
186 else
187 Rounded (R_Pos) := '0';
188 R_Pos := R_Pos - 1;
189 end if;
190 end loop;
192 -- The rounding may add a digit in front. Either the
193 -- leading blank or the sign (already captured) can
194 -- be overwritten.
196 if R_Pos = 1 then
197 Rounded (R_Pos) := '1';
198 Attrs.Start_Of_Int := Attrs.Start_Of_Int - 1;
199 end if;
200 end if;
201 end if;
202 end if;
203 end;
204 end if;
206 if Pic.Start_Currency /= Invalid_Position then
207 Dollar := Answer (Pic.Start_Currency) = '$';
208 end if;
210 -- Fix up "direct inserts" outside the playing field. Set up as one
211 -- loop to do the beginning, one (reverse) loop to do the end.
213 Last := 1;
214 loop
215 exit when Last = Pic.Start_Float;
216 exit when Last = Pic.Radix_Position;
217 exit when Answer (Last) = '9';
219 case Answer (Last) is
220 when '_' =>
221 Answer (Last) := Separator_Character;
223 when 'b' =>
224 Answer (Last) := ' ';
226 when others =>
227 null;
228 end case;
230 exit when Last = Answer'Last;
232 Last := Last + 1;
233 end loop;
235 -- Now for the end...
237 for J in reverse Last .. Answer'Last loop
238 exit when J = Pic.Radix_Position;
240 -- Do this test First, Separator_Character can equal Pic.Floater
242 if Answer (J) = Pic.Floater then
243 exit;
244 end if;
246 case Answer (J) is
247 when '_' =>
248 Answer (J) := Separator_Character;
250 when 'b' =>
251 Answer (J) := ' ';
253 when '9' =>
254 exit;
256 when others =>
257 null;
258 end case;
259 end loop;
261 -- Non-floating sign
263 if Pic.Start_Currency /= -1
264 and then Answer (Pic.Start_Currency) = '#'
265 and then Pic.Floater /= '#'
266 then
267 if Currency_Symbol'Length >
268 Pic.End_Currency - Pic.Start_Currency + 1
269 then
270 raise Picture_Error;
272 elsif Currency_Symbol'Length =
273 Pic.End_Currency - Pic.Start_Currency + 1
274 then
275 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
276 Currency_Symbol;
278 elsif Pic.Radix_Position = Invalid_Position
279 or else Pic.Start_Currency < Pic.Radix_Position
280 then
281 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
282 (others => ' ');
283 Answer (Pic.End_Currency - Currency_Symbol'Length + 1 ..
284 Pic.End_Currency) := Currency_Symbol;
286 else
287 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
288 (others => ' ');
289 Answer (Pic.Start_Currency ..
290 Pic.Start_Currency + Currency_Symbol'Length - 1) :=
291 Currency_Symbol;
292 end if;
293 end if;
295 -- Fill in leading digits
297 if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
298 Pic.Max_Leading_Digits
299 then
300 raise Ada.Text_IO.Layout_Error;
301 end if;
303 Position :=
304 (if Pic.Radix_Position = Invalid_Position
305 then Answer'Last
306 else Pic.Radix_Position - 1);
308 for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop
309 while Answer (Position) /= '9'
310 and then
311 Answer (Position) /= Pic.Floater
312 loop
313 if Answer (Position) = '_' then
314 Answer (Position) := Separator_Character;
316 elsif Answer (Position) = 'b' then
317 Answer (Position) := ' ';
318 end if;
320 Position := Position - 1;
321 end loop;
323 Answer (Position) := Rounded (J);
325 if Rounded (J) /= '0' then
326 Zero := False;
327 end if;
329 Position := Position - 1;
330 end loop;
332 -- Do lead float
334 if Pic.Start_Float = Invalid_Position then
336 -- No leading floats, but need to change '9' to '0', '_' to
337 -- Separator_Character and 'b' to ' '.
339 for J in Last .. Position loop
341 -- Last set when fixing the "uninteresting" leaders above.
342 -- Don't duplicate the work.
344 if Answer (J) = '9' then
345 Answer (J) := '0';
347 elsif Answer (J) = '_' then
348 Answer (J) := Separator_Character;
350 elsif Answer (J) = 'b' then
351 Answer (J) := ' ';
352 end if;
353 end loop;
355 elsif Pic.Floater = '<'
356 or else
357 Pic.Floater = '+'
358 or else
359 Pic.Floater = '-'
360 then
361 for J in Pic.End_Float .. Position loop -- May be null range.
362 if Answer (J) = '9' then
363 Answer (J) := '0';
365 elsif Answer (J) = '_' then
366 Answer (J) := Separator_Character;
368 elsif Answer (J) = 'b' then
369 Answer (J) := ' ';
370 end if;
371 end loop;
373 if Position > Pic.End_Float then
374 Position := Pic.End_Float;
375 end if;
377 for J in Pic.Start_Float .. Position - 1 loop
378 Answer (J) := ' ';
379 end loop;
381 Answer (Position) := Pic.Floater;
382 Sign_Position := Position;
384 elsif Pic.Floater = '$' then
386 for J in Pic.End_Float .. Position loop -- May be null range.
387 if Answer (J) = '9' then
388 Answer (J) := '0';
390 elsif Answer (J) = '_' then
391 Answer (J) := ' '; -- no separators before leftmost digit.
393 elsif Answer (J) = 'b' then
394 Answer (J) := ' ';
395 end if;
396 end loop;
398 if Position > Pic.End_Float then
399 Position := Pic.End_Float;
400 end if;
402 for J in Pic.Start_Float .. Position - 1 loop
403 Answer (J) := ' ';
404 end loop;
406 Answer (Position) := Pic.Floater;
407 Currency_Pos := Position;
409 elsif Pic.Floater = '*' then
411 for J in Pic.End_Float .. Position loop -- May be null range.
412 if Answer (J) = '9' then
413 Answer (J) := '0';
415 elsif Answer (J) = '_' then
416 Answer (J) := Separator_Character;
418 elsif Answer (J) = 'b' then
419 Answer (J) := Fill_Character;
420 end if;
421 end loop;
423 if Position > Pic.End_Float then
424 Position := Pic.End_Float;
425 end if;
427 for J in Pic.Start_Float .. Position loop
428 Answer (J) := Fill_Character;
429 end loop;
431 else
432 if Pic.Floater = '#' then
433 Currency_Pos := Currency_Symbol'Length;
434 In_Currency := True;
435 end if;
437 for J in reverse Pic.Start_Float .. Position loop
438 case Answer (J) is
439 when '*' =>
440 Answer (J) := Fill_Character;
442 when 'b' | '/' =>
443 if In_Currency and then Currency_Pos > 0 then
444 Answer (J) := Currency_Symbol (Currency_Pos);
445 Currency_Pos := Currency_Pos - 1;
446 else
447 Answer (J) := ' ';
448 end if;
450 when 'Z' | '0' =>
451 Answer (J) := ' ';
453 when '9' =>
454 Answer (J) := '0';
456 when '.' | 'V' | 'v' | '<' | '$' | '+' | '-' =>
457 null;
459 when '#' =>
460 if Currency_Pos = 0 then
461 Answer (J) := ' ';
462 else
463 Answer (J) := Currency_Symbol (Currency_Pos);
464 Currency_Pos := Currency_Pos - 1;
465 end if;
467 when '_' =>
468 case Pic.Floater is
469 when '*' =>
470 Answer (J) := Fill_Character;
472 when 'Z' | 'b' =>
473 Answer (J) := ' ';
475 when '#' =>
476 if Currency_Pos = 0 then
477 Answer (J) := ' ';
479 else
480 Answer (J) := Currency_Symbol (Currency_Pos);
481 Currency_Pos := Currency_Pos - 1;
482 end if;
484 when others =>
485 null;
486 end case;
488 when others =>
489 null;
490 end case;
491 end loop;
493 if Pic.Floater = '#' and then Currency_Pos /= 0 then
494 raise Ada.Text_IO.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 Ada.Text_IO.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;
520 end case;
522 else -- positive
524 case Answer (Sign_Position) is
525 when '-' =>
526 Answer (Sign_Position) := ' ';
528 when '<' | 'C' | 'D' =>
529 Answer (Sign_Position) := ' ';
530 Answer (Pic.Second_Sign) := ' ';
532 when '+' =>
533 null;
535 when others =>
536 raise Picture_Error;
537 end case;
538 end if;
539 end if;
541 -- Fill in trailing digits
543 if Pic.Max_Trailing_Digits > 0 then
545 if Attrs.Has_Fraction then
546 Position := Attrs.Start_Of_Fraction;
547 Last := Pic.Radix_Position + 1;
549 for J in Last .. Answer'Last loop
550 if Answer (J) = '9' or else Answer (J) = Pic.Floater then
551 Answer (J) := Rounded (Position);
553 if Rounded (Position) /= '0' then
554 Zero := False;
555 end if;
557 Position := Position + 1;
558 Last := J + 1;
560 -- Used up fraction but remember place in Answer
562 exit when Position > Attrs.End_Of_Fraction;
564 elsif Answer (J) = 'b' then
565 Answer (J) := ' ';
567 elsif Answer (J) = '_' then
568 Answer (J) := Separator_Character;
569 end if;
571 Last := J + 1;
572 end loop;
574 Position := Last;
576 else
577 Position := Pic.Radix_Position + 1;
578 end if;
580 -- Now fill remaining 9's with zeros and _ with separators
582 Last := Answer'Last;
584 for J in Position .. Last loop
585 if Answer (J) = '9' then
586 Answer (J) := '0';
588 elsif Answer (J) = Pic.Floater then
589 Answer (J) := '0';
591 elsif Answer (J) = '_' then
592 Answer (J) := Separator_Character;
594 elsif Answer (J) = 'b' then
595 Answer (J) := ' ';
597 end if;
598 end loop;
600 Position := Last + 1;
602 else
603 if Pic.Floater = '#' and then Currency_Pos /= 0 then
604 raise Ada.Text_IO.Layout_Error;
605 end if;
607 -- No trailing digits, but now J may need to stick in a currency
608 -- symbol or sign.
610 Position :=
611 (if Pic.Start_Currency = Invalid_Position
612 then Answer'Last + 1
613 else Pic.Start_Currency);
614 end if;
616 for J in Position .. Answer'Last loop
617 if Pic.Start_Currency /= Invalid_Position
618 and then Answer (Pic.Start_Currency) = '#'
619 then
620 Currency_Pos := 1;
621 end if;
623 case Answer (J) is
624 when '*' =>
625 Answer (J) := Fill_Character;
627 when 'b' =>
628 if In_Currency then
629 Answer (J) := Currency_Symbol (Currency_Pos);
630 Currency_Pos := Currency_Pos + 1;
632 if Currency_Pos > Currency_Symbol'Length then
633 In_Currency := False;
634 end if;
635 end if;
637 when '#' =>
638 if Currency_Pos > Currency_Symbol'Length then
639 Answer (J) := ' ';
641 else
642 In_Currency := True;
643 Answer (J) := Currency_Symbol (Currency_Pos);
644 Currency_Pos := Currency_Pos + 1;
646 if Currency_Pos > Currency_Symbol'Length then
647 In_Currency := False;
648 end if;
649 end if;
651 when '_' =>
652 Answer (J) := Currency_Symbol (Currency_Pos);
653 Currency_Pos := Currency_Pos + 1;
655 case Pic.Floater is
656 when '*' =>
657 Answer (J) := Fill_Character;
659 when 'Z' | 'z' =>
660 Answer (J) := ' ';
662 when '#' =>
663 if Currency_Pos > Currency_Symbol'Length then
664 Answer (J) := ' ';
665 else
666 Answer (J) := Currency_Symbol (Currency_Pos);
667 Currency_Pos := Currency_Pos + 1;
668 end if;
670 when others =>
671 null;
672 end case;
674 when others =>
675 exit;
676 end case;
677 end loop;
679 -- Now get rid of Blank_when_Zero and complete Star fill
681 if Zero and then Pic.Blank_When_Zero then
683 -- Value is zero, and blank it
685 Last := Answer'Last;
687 if Dollar then
688 Last := Last - 1 + Currency_Symbol'Length;
689 end if;
691 if Pic.Radix_Position /= Invalid_Position
692 and then Answer (Pic.Radix_Position) = 'V'
693 then
694 Last := Last - 1;
695 end if;
697 return String'(1 .. Last => ' ');
699 elsif Zero and then 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 different
739 -- return cases. Not to mention the five above to deal with zeros. Why
740 -- not split things out?
742 -- Processing the radix and sign expansion separately would require
743 -- lots of copying--the string and some of its indexes--without
744 -- 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;
828 end Format_Number;
830 -------------------------
831 -- Parse_Number_String --
832 -------------------------
834 function Parse_Number_String (Str : String) return Number_Attributes is
835 Answer : Number_Attributes;
837 begin
838 for J in Str'Range loop
839 case Str (J) is
840 when ' ' =>
841 null; -- ignore
843 when '1' .. '9' =>
845 -- Decide if this is the start of a number.
846 -- If so, figure out which one...
848 if Answer.Has_Fraction then
849 Answer.End_Of_Fraction := J;
850 else
851 if Answer.Start_Of_Int = Invalid_Position then
852 -- start integer
853 Answer.Start_Of_Int := J;
854 end if;
855 Answer.End_Of_Int := J;
856 end if;
858 when '0' =>
860 -- Only count a zero before the decimal point if it follows a
861 -- non-zero digit. After the decimal point, zeros will be
862 -- counted if followed by a non-zero digit.
864 if not Answer.Has_Fraction then
865 if Answer.Start_Of_Int /= Invalid_Position then
866 Answer.End_Of_Int := J;
867 end if;
868 end if;
870 when '-' =>
872 -- Set negative
874 Answer.Negative := True;
876 when '.' =>
878 -- Close integer, start fraction
880 if Answer.Has_Fraction then
881 raise Picture_Error;
882 end if;
884 -- Two decimal points is a no-no
886 Answer.Has_Fraction := True;
887 Answer.End_Of_Fraction := J;
889 -- Could leave this at Invalid_Position, but this seems the
890 -- right way to indicate a null range...
892 Answer.Start_Of_Fraction := J + 1;
893 Answer.End_Of_Int := J - 1;
895 when others =>
896 raise Picture_Error; -- can this happen? probably not
897 end case;
898 end loop;
900 if Answer.Start_Of_Int = Invalid_Position then
901 Answer.Start_Of_Int := Answer.End_Of_Int + 1;
902 end if;
904 -- No significant (integer) digits needs a null range
906 return Answer;
907 end Parse_Number_String;
909 ----------------
910 -- Pic_String --
911 ----------------
913 -- The following ensures that we return B and not b being careful not
914 -- to break things which expect lower case b for blank. See CXF3A02.
916 function Pic_String (Pic : Picture) return String is
917 Temp : String (1 .. Pic.Contents.Picture.Length) :=
918 Pic.Contents.Picture.Expanded;
919 begin
920 for J in Temp'Range loop
921 if Temp (J) = 'b' then
922 Temp (J) := 'B';
923 end if;
924 end loop;
926 return Temp;
927 end Pic_String;
929 ------------------
930 -- Precalculate --
931 ------------------
933 procedure Precalculate (Pic : in out Format_Record) is
934 Debug : constant Boolean := False;
935 -- Set True to generate debug output
937 Computed_BWZ : Boolean := True;
939 type Legality is (Okay, Reject);
941 State : Legality := Reject;
942 -- Start in reject, which will reject null strings
944 Index : Pic_Index := Pic.Picture.Expanded'First;
946 function At_End return Boolean;
947 pragma Inline (At_End);
949 procedure Set_State (L : Legality);
950 pragma Inline (Set_State);
952 function Look return Character;
953 pragma Inline (Look);
955 function Is_Insert return Boolean;
956 pragma Inline (Is_Insert);
958 procedure Skip;
959 pragma Inline (Skip);
961 procedure Debug_Start (Name : String);
962 pragma Inline (Debug_Start);
964 procedure Debug_Integer (Value : Integer; S : String);
965 pragma Inline (Debug_Integer);
967 procedure Trailing_Currency;
968 procedure Trailing_Bracket;
969 procedure Number_Fraction;
970 procedure Number_Completion;
971 procedure Number_Fraction_Or_Bracket;
972 procedure Number_Fraction_Or_Z_Fill;
973 procedure Zero_Suppression;
974 procedure Floating_Bracket;
975 procedure Number_Fraction_Or_Star_Fill;
976 procedure Star_Suppression;
977 procedure Number_Fraction_Or_Dollar;
978 procedure Leading_Dollar;
979 procedure Number_Fraction_Or_Pound;
980 procedure Leading_Pound;
981 procedure Picture;
982 procedure Floating_Plus;
983 procedure Floating_Minus;
984 procedure Picture_Plus;
985 procedure Picture_Minus;
986 procedure Picture_Bracket;
987 procedure Number;
988 procedure Optional_RHS_Sign;
989 procedure Picture_String;
990 procedure Set_Debug;
992 ------------
993 -- At_End --
994 ------------
996 function At_End return Boolean is
997 begin
998 Debug_Start ("At_End");
999 return Index > Pic.Picture.Length;
1000 end At_End;
1002 --------------
1003 -- Set_Debug--
1004 --------------
1006 -- Needed to have a procedure to pass to pragma Debug
1008 procedure Set_Debug is
1009 begin
1010 -- Uncomment this line and make Debug a variable to enable debug
1012 -- Debug := True;
1014 null;
1015 end Set_Debug;
1017 -------------------
1018 -- Debug_Integer --
1019 -------------------
1021 procedure Debug_Integer (Value : Integer; S : String) is
1023 begin
1024 if Debug and then Value > 0 then
1025 if Ada.Text_IO.Col > 70 - S'Length then
1026 Ada.Text_IO.New_Line;
1027 end if;
1029 Ada.Text_IO.Put (' ' & S & Integer'Image (Value) & ',');
1030 end if;
1031 end Debug_Integer;
1033 -----------------
1034 -- Debug_Start --
1035 -----------------
1037 procedure Debug_Start (Name : String) is
1038 begin
1039 if Debug then
1040 Ada.Text_IO.Put_Line (" In " & Name & '.');
1041 end if;
1042 end Debug_Start;
1044 ----------------------
1045 -- Floating_Bracket --
1046 ----------------------
1048 -- Note that Floating_Bracket is only called with an acceptable
1049 -- prefix. But we don't set Okay, because we must end with a '>'.
1051 procedure Floating_Bracket is
1052 begin
1053 Debug_Start ("Floating_Bracket");
1055 -- Two different floats not allowed
1057 if Pic.Floater /= '!' and then Pic.Floater /= '<' then
1058 raise Picture_Error;
1060 else
1061 Pic.Floater := '<';
1062 end if;
1064 Pic.End_Float := Index;
1065 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1067 -- First bracket wasn't counted...
1069 Skip; -- known '<'
1071 loop
1072 if At_End then
1073 return;
1074 end if;
1076 case Look is
1077 when '_' | '0' | '/' =>
1078 Pic.End_Float := Index;
1079 Skip;
1081 when 'B' | 'b' =>
1082 Pic.End_Float := Index;
1083 Pic.Picture.Expanded (Index) := 'b';
1084 Skip;
1086 when '<' =>
1087 Pic.End_Float := Index;
1088 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1089 Skip;
1091 when '9' =>
1092 Number_Completion;
1094 when '$' =>
1095 Leading_Dollar;
1097 when '#' =>
1098 Leading_Pound;
1100 when 'V' | 'v' | '.' =>
1101 Pic.Radix_Position := Index;
1102 Skip;
1103 Number_Fraction_Or_Bracket;
1104 return;
1106 when others =>
1107 return;
1108 end case;
1109 end loop;
1110 end Floating_Bracket;
1112 --------------------
1113 -- Floating_Minus --
1114 --------------------
1116 procedure Floating_Minus is
1117 begin
1118 Debug_Start ("Floating_Minus");
1120 loop
1121 if At_End then
1122 return;
1123 end if;
1125 case Look is
1126 when '_' | '0' | '/' =>
1127 Pic.End_Float := Index;
1128 Skip;
1130 when 'B' | 'b' =>
1131 Pic.End_Float := Index;
1132 Pic.Picture.Expanded (Index) := 'b';
1133 Skip;
1135 when '-' =>
1136 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1137 Pic.End_Float := Index;
1138 Skip;
1140 when '9' =>
1141 Number_Completion;
1142 return;
1144 when '.' | 'V' | 'v' =>
1145 Pic.Radix_Position := Index;
1146 Skip; -- Radix
1148 while Is_Insert loop
1149 Skip;
1150 end loop;
1152 if At_End then
1153 return;
1154 end if;
1156 if Look = '-' then
1157 loop
1158 if At_End then
1159 return;
1160 end if;
1162 case Look is
1163 when '-' =>
1164 Pic.Max_Trailing_Digits :=
1165 Pic.Max_Trailing_Digits + 1;
1166 Pic.End_Float := Index;
1167 Skip;
1169 when '_' | '0' | '/' =>
1170 Skip;
1172 when 'B' | 'b' =>
1173 Pic.Picture.Expanded (Index) := 'b';
1174 Skip;
1176 when others =>
1177 return;
1178 end case;
1179 end loop;
1181 else
1182 Number_Completion;
1183 end if;
1185 return;
1187 when others =>
1188 return;
1189 end case;
1190 end loop;
1191 end Floating_Minus;
1193 -------------------
1194 -- Floating_Plus --
1195 -------------------
1197 procedure Floating_Plus is
1198 begin
1199 Debug_Start ("Floating_Plus");
1201 loop
1202 if At_End then
1203 return;
1204 end if;
1206 case Look is
1207 when '_' | '0' | '/' =>
1208 Pic.End_Float := Index;
1209 Skip;
1211 when 'B' | 'b' =>
1212 Pic.End_Float := Index;
1213 Pic.Picture.Expanded (Index) := 'b';
1214 Skip;
1216 when '+' =>
1217 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1218 Pic.End_Float := Index;
1219 Skip;
1221 when '9' =>
1222 Number_Completion;
1223 return;
1225 when '.' | 'V' | 'v' =>
1226 Pic.Radix_Position := Index;
1227 Skip; -- Radix
1229 while Is_Insert loop
1230 Skip;
1231 end loop;
1233 if At_End then
1234 return;
1235 end if;
1237 if Look = '+' then
1238 loop
1239 if At_End then
1240 return;
1241 end if;
1243 case Look is
1244 when '+' =>
1245 Pic.Max_Trailing_Digits :=
1246 Pic.Max_Trailing_Digits + 1;
1247 Pic.End_Float := Index;
1248 Skip;
1250 when '_' | '0' | '/' =>
1251 Skip;
1253 when 'B' | 'b' =>
1254 Pic.Picture.Expanded (Index) := 'b';
1255 Skip;
1257 when others =>
1258 return;
1259 end case;
1260 end loop;
1262 else
1263 Number_Completion;
1264 end if;
1266 return;
1268 when others =>
1269 return;
1270 end case;
1271 end loop;
1272 end Floating_Plus;
1274 ---------------
1275 -- Is_Insert --
1276 ---------------
1278 function Is_Insert return Boolean is
1279 begin
1280 if At_End then
1281 return False;
1282 end if;
1284 case Pic.Picture.Expanded (Index) is
1285 when '_' | '0' | '/' =>
1286 return True;
1288 when 'B' | 'b' =>
1289 Pic.Picture.Expanded (Index) := 'b'; -- canonical
1290 return True;
1292 when others =>
1293 return False;
1294 end case;
1295 end Is_Insert;
1297 --------------------
1298 -- Leading_Dollar --
1299 --------------------
1301 -- Note that Leading_Dollar can be called in either State. It will set
1302 -- state to Okay only if a 9 or (second) $ is encountered.
1304 -- Also notice the tricky bit with State and Zero_Suppression.
1305 -- Zero_Suppression is Picture_Error if a '$' or a '9' has been
1306 -- encountered, exactly the cases where State has been set.
1308 procedure Leading_Dollar is
1309 begin
1310 Debug_Start ("Leading_Dollar");
1312 -- Treat as a floating dollar, and unwind otherwise
1314 if Pic.Floater /= '!' and then Pic.Floater /= '$' then
1316 -- Two floats not allowed
1318 raise Picture_Error;
1320 else
1321 Pic.Floater := '$';
1322 end if;
1324 Pic.Start_Currency := Index;
1325 Pic.End_Currency := Index;
1326 Pic.Start_Float := Index;
1327 Pic.End_Float := Index;
1329 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1330 -- currency place.
1332 Skip; -- known '$'
1334 loop
1335 if At_End then
1336 return;
1337 end if;
1339 case Look is
1340 when '_' | '0' | '/' =>
1341 Pic.End_Float := Index;
1342 Skip;
1344 -- A trailing insertion character is not part of the
1345 -- floating currency, so need to look ahead.
1347 if Look /= '$' then
1348 Pic.End_Float := Pic.End_Float - 1;
1349 end if;
1351 when 'B' | 'b' =>
1352 Pic.End_Float := Index;
1353 Pic.Picture.Expanded (Index) := 'b';
1354 Skip;
1356 when 'Z' | 'z' =>
1357 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1359 if State = Okay then
1360 raise Picture_Error;
1361 else
1362 -- Overwrite Floater and Start_Float
1364 Pic.Floater := 'Z';
1365 Pic.Start_Float := Index;
1366 Zero_Suppression;
1367 end if;
1369 when '*' =>
1370 if State = Okay then
1371 raise Picture_Error;
1372 else
1373 -- Overwrite Floater and Start_Float
1375 Pic.Floater := '*';
1376 Pic.Start_Float := Index;
1377 Star_Suppression;
1378 end if;
1380 when '$' =>
1381 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1382 Pic.End_Float := Index;
1383 Pic.End_Currency := Index;
1384 Set_State (Okay); Skip;
1386 when '9' =>
1387 if State /= Okay then
1388 Pic.Floater := '!';
1389 Pic.Start_Float := Invalid_Position;
1390 Pic.End_Float := Invalid_Position;
1391 end if;
1393 -- A single dollar does not a floating make
1395 Number_Completion;
1396 return;
1398 when 'V' | 'v' | '.' =>
1399 if State /= Okay then
1400 Pic.Floater := '!';
1401 Pic.Start_Float := Invalid_Position;
1402 Pic.End_Float := Invalid_Position;
1403 end if;
1405 -- Only one dollar before the sign is okay, but doesn't
1406 -- float.
1408 Pic.Radix_Position := Index;
1409 Skip;
1410 Number_Fraction_Or_Dollar;
1411 return;
1413 when others =>
1414 return;
1415 end case;
1416 end loop;
1417 end Leading_Dollar;
1419 -------------------
1420 -- Leading_Pound --
1421 -------------------
1423 -- This one is complex. A Leading_Pound can be fixed or floating,
1424 -- but in some cases the decision has to be deferred until we leave
1425 -- this procedure. Also note that Leading_Pound can be called in
1426 -- either State.
1428 -- It will set state to Okay only if a 9 or (second) # is encountered
1430 -- One Last note: In ambiguous cases, the currency is treated as
1431 -- floating unless there is only one '#'.
1433 procedure Leading_Pound is
1435 Inserts : Boolean := False;
1436 -- Set to True if a '_', '0', '/', 'B', or 'b' is encountered
1438 Must_Float : Boolean := False;
1439 -- Set to true if a '#' occurs after an insert
1441 begin
1442 Debug_Start ("Leading_Pound");
1444 -- Treat as a floating currency. If it isn't, this will be
1445 -- overwritten later.
1447 if Pic.Floater /= '!' and then Pic.Floater /= '#' then
1449 -- Two floats not allowed
1451 raise Picture_Error;
1453 else
1454 Pic.Floater := '#';
1455 end if;
1457 Pic.Start_Currency := Index;
1458 Pic.End_Currency := Index;
1459 Pic.Start_Float := Index;
1460 Pic.End_Float := Index;
1462 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1463 -- currency place.
1465 Pic.Max_Currency_Digits := 1; -- we've seen one.
1467 Skip; -- known '#'
1469 loop
1470 if At_End then
1471 return;
1472 end if;
1474 case Look is
1475 when '_' | '0' | '/' =>
1476 Pic.End_Float := Index;
1477 Inserts := True;
1478 Skip;
1480 when 'B' | 'b' =>
1481 Pic.Picture.Expanded (Index) := 'b';
1482 Pic.End_Float := Index;
1483 Inserts := True;
1484 Skip;
1486 when 'Z' | 'z' =>
1487 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1489 if Must_Float then
1490 raise Picture_Error;
1491 else
1492 Pic.Max_Leading_Digits := 0;
1494 -- Overwrite Floater and Start_Float
1496 Pic.Floater := 'Z';
1497 Pic.Start_Float := Index;
1498 Zero_Suppression;
1499 end if;
1501 when '*' =>
1502 if Must_Float then
1503 raise Picture_Error;
1504 else
1505 Pic.Max_Leading_Digits := 0;
1507 -- Overwrite Floater and Start_Float
1508 Pic.Floater := '*';
1509 Pic.Start_Float := Index;
1510 Star_Suppression;
1511 end if;
1513 when '#' =>
1514 if Inserts then
1515 Must_Float := True;
1516 end if;
1518 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1519 Pic.End_Float := Index;
1520 Pic.End_Currency := Index;
1521 Set_State (Okay);
1522 Skip;
1524 when '9' =>
1525 if State /= Okay then
1527 -- A single '#' doesn't float
1529 Pic.Floater := '!';
1530 Pic.Start_Float := Invalid_Position;
1531 Pic.End_Float := Invalid_Position;
1532 end if;
1534 Number_Completion;
1535 return;
1537 when 'V' | 'v' | '.' =>
1538 if State /= Okay then
1539 Pic.Floater := '!';
1540 Pic.Start_Float := Invalid_Position;
1541 Pic.End_Float := Invalid_Position;
1542 end if;
1544 -- Only one pound before the sign is okay, but doesn't
1545 -- float.
1547 Pic.Radix_Position := Index;
1548 Skip;
1549 Number_Fraction_Or_Pound;
1550 return;
1552 when others =>
1553 return;
1554 end case;
1555 end loop;
1556 end Leading_Pound;
1558 ----------
1559 -- Look --
1560 ----------
1562 function Look return Character is
1563 begin
1564 if At_End then
1565 raise Picture_Error;
1566 end if;
1568 return Pic.Picture.Expanded (Index);
1569 end Look;
1571 ------------
1572 -- Number --
1573 ------------
1575 procedure Number is
1576 begin
1577 Debug_Start ("Number");
1579 loop
1580 case Look is
1581 when '_' | '0' | '/' =>
1582 Skip;
1584 when 'B' | 'b' =>
1585 Pic.Picture.Expanded (Index) := 'b';
1586 Skip;
1588 when '9' =>
1589 Computed_BWZ := False;
1590 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1591 Set_State (Okay);
1592 Skip;
1594 when '.' | 'V' | 'v' =>
1595 Pic.Radix_Position := Index;
1596 Skip;
1597 Number_Fraction;
1598 return;
1600 when others =>
1601 return;
1602 end case;
1604 if At_End then
1605 return;
1606 end if;
1608 -- Will return in Okay state if a '9' was seen
1610 end loop;
1611 end Number;
1613 -----------------------
1614 -- Number_Completion --
1615 -----------------------
1617 procedure Number_Completion is
1618 begin
1619 Debug_Start ("Number_Completion");
1621 while not At_End loop
1622 case Look is
1623 when '_' | '0' | '/' =>
1624 Skip;
1626 when 'B' | 'b' =>
1627 Pic.Picture.Expanded (Index) := 'b';
1628 Skip;
1630 when '9' =>
1631 Computed_BWZ := False;
1632 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1633 Set_State (Okay);
1634 Skip;
1636 when 'V' | 'v' | '.' =>
1637 Pic.Radix_Position := Index;
1638 Skip;
1639 Number_Fraction;
1640 return;
1642 when others =>
1643 return;
1644 end case;
1645 end loop;
1646 end Number_Completion;
1648 ---------------------
1649 -- Number_Fraction --
1650 ---------------------
1652 procedure Number_Fraction is
1653 begin
1654 -- Note that number fraction can be called in either State.
1655 -- It will set state to Valid only if a 9 is encountered.
1657 Debug_Start ("Number_Fraction");
1659 loop
1660 if At_End then
1661 return;
1662 end if;
1664 case Look is
1665 when '_' | '0' | '/' =>
1666 Skip;
1668 when 'B' | 'b' =>
1669 Pic.Picture.Expanded (Index) := 'b';
1670 Skip;
1672 when '9' =>
1673 Computed_BWZ := False;
1674 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1675 Set_State (Okay); Skip;
1677 when others =>
1678 return;
1679 end case;
1680 end loop;
1681 end Number_Fraction;
1683 --------------------------------
1684 -- Number_Fraction_Or_Bracket --
1685 --------------------------------
1687 procedure Number_Fraction_Or_Bracket is
1688 begin
1689 Debug_Start ("Number_Fraction_Or_Bracket");
1691 loop
1692 if At_End then
1693 return;
1694 end if;
1696 case Look is
1697 when '_' | '0' | '/' =>
1698 Skip;
1700 when 'B' | 'b' =>
1701 Pic.Picture.Expanded (Index) := 'b';
1702 Skip;
1704 when '<' =>
1705 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1706 Pic.End_Float := Index;
1707 Skip;
1709 loop
1710 if At_End then
1711 return;
1712 end if;
1714 case Look is
1715 when '_' | '0' | '/' =>
1716 Skip;
1718 when 'B' | 'b' =>
1719 Pic.Picture.Expanded (Index) := 'b';
1720 Skip;
1722 when '<' =>
1723 Pic.Max_Trailing_Digits :=
1724 Pic.Max_Trailing_Digits + 1;
1725 Pic.End_Float := Index;
1726 Skip;
1728 when others =>
1729 return;
1730 end case;
1731 end loop;
1733 when others =>
1734 Number_Fraction;
1735 return;
1736 end case;
1737 end loop;
1738 end Number_Fraction_Or_Bracket;
1740 -------------------------------
1741 -- Number_Fraction_Or_Dollar --
1742 -------------------------------
1744 procedure Number_Fraction_Or_Dollar is
1745 begin
1746 Debug_Start ("Number_Fraction_Or_Dollar");
1748 loop
1749 if At_End then
1750 return;
1751 end if;
1753 case Look is
1754 when '_' | '0' | '/' =>
1755 Skip;
1757 when 'B' | 'b' =>
1758 Pic.Picture.Expanded (Index) := 'b';
1759 Skip;
1761 when '$' =>
1762 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1763 Pic.End_Float := Index;
1764 Skip;
1766 loop
1767 if At_End then
1768 return;
1769 end if;
1771 case Look is
1772 when '_' | '0' | '/' =>
1773 Skip;
1775 when 'B' | 'b' =>
1776 Pic.Picture.Expanded (Index) := 'b';
1777 Skip;
1779 when '$' =>
1780 Pic.Max_Trailing_Digits :=
1781 Pic.Max_Trailing_Digits + 1;
1782 Pic.End_Float := Index;
1783 Skip;
1785 when others =>
1786 return;
1787 end case;
1788 end loop;
1790 when others =>
1791 Number_Fraction;
1792 return;
1793 end case;
1794 end loop;
1795 end Number_Fraction_Or_Dollar;
1797 ------------------------------
1798 -- Number_Fraction_Or_Pound --
1799 ------------------------------
1801 procedure Number_Fraction_Or_Pound is
1802 begin
1803 loop
1804 if At_End then
1805 return;
1806 end if;
1808 case Look is
1809 when '_' | '0' | '/' =>
1810 Skip;
1812 when 'B' | 'b' =>
1813 Pic.Picture.Expanded (Index) := 'b';
1814 Skip;
1816 when '#' =>
1817 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1818 Pic.End_Float := Index;
1819 Skip;
1821 loop
1822 if At_End then
1823 return;
1824 end if;
1826 case Look is
1827 when '_' | '0' | '/' =>
1828 Skip;
1830 when 'B' | 'b' =>
1831 Pic.Picture.Expanded (Index) := 'b';
1832 Skip;
1834 when '#' =>
1835 Pic.Max_Trailing_Digits :=
1836 Pic.Max_Trailing_Digits + 1;
1837 Pic.End_Float := Index;
1838 Skip;
1840 when others =>
1841 return;
1842 end case;
1843 end loop;
1845 when others =>
1846 Number_Fraction;
1847 return;
1848 end case;
1849 end loop;
1850 end Number_Fraction_Or_Pound;
1852 ----------------------------------
1853 -- Number_Fraction_Or_Star_Fill --
1854 ----------------------------------
1856 procedure Number_Fraction_Or_Star_Fill is
1857 begin
1858 Debug_Start ("Number_Fraction_Or_Star_Fill");
1860 loop
1861 if At_End then
1862 return;
1863 end if;
1865 case Look is
1866 when '_' | '0' | '/' =>
1867 Skip;
1869 when 'B' | 'b' =>
1870 Pic.Picture.Expanded (Index) := 'b';
1871 Skip;
1873 when '*' =>
1874 Pic.Star_Fill := True;
1875 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1876 Pic.End_Float := Index;
1877 Skip;
1879 loop
1880 if At_End then
1881 return;
1882 end if;
1884 case Look is
1885 when '_' | '0' | '/' =>
1886 Skip;
1888 when 'B' | 'b' =>
1889 Pic.Picture.Expanded (Index) := 'b';
1890 Skip;
1892 when '*' =>
1893 Pic.Star_Fill := True;
1894 Pic.Max_Trailing_Digits :=
1895 Pic.Max_Trailing_Digits + 1;
1896 Pic.End_Float := Index;
1897 Skip;
1899 when others =>
1900 return;
1901 end case;
1902 end loop;
1904 when others =>
1905 Number_Fraction;
1906 return;
1907 end case;
1908 end loop;
1909 end Number_Fraction_Or_Star_Fill;
1911 -------------------------------
1912 -- Number_Fraction_Or_Z_Fill --
1913 -------------------------------
1915 procedure Number_Fraction_Or_Z_Fill is
1916 begin
1917 Debug_Start ("Number_Fraction_Or_Z_Fill");
1919 loop
1920 if At_End then
1921 return;
1922 end if;
1924 case Look is
1925 when '_' | '0' | '/' =>
1926 Skip;
1928 when 'B' | 'b' =>
1929 Pic.Picture.Expanded (Index) := 'b';
1930 Skip;
1932 when 'Z' | 'z' =>
1933 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1934 Pic.End_Float := Index;
1935 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1937 Skip;
1939 loop
1940 if At_End then
1941 return;
1942 end if;
1944 case Look is
1945 when '_' | '0' | '/' =>
1946 Skip;
1948 when 'B' | 'b' =>
1949 Pic.Picture.Expanded (Index) := 'b';
1950 Skip;
1952 when 'Z' | 'z' =>
1953 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1955 Pic.Max_Trailing_Digits :=
1956 Pic.Max_Trailing_Digits + 1;
1957 Pic.End_Float := Index;
1958 Skip;
1960 when others =>
1961 return;
1962 end case;
1963 end loop;
1965 when others =>
1966 Number_Fraction;
1967 return;
1968 end case;
1969 end loop;
1970 end Number_Fraction_Or_Z_Fill;
1972 -----------------------
1973 -- Optional_RHS_Sign --
1974 -----------------------
1976 procedure Optional_RHS_Sign is
1977 begin
1978 Debug_Start ("Optional_RHS_Sign");
1980 if At_End then
1981 return;
1982 end if;
1984 case Look is
1985 when '+' | '-' =>
1986 Pic.Sign_Position := Index;
1987 Skip;
1988 return;
1990 when 'C' | 'c' =>
1991 Pic.Sign_Position := Index;
1992 Pic.Picture.Expanded (Index) := 'C';
1993 Skip;
1995 if Look = 'R' or else Look = 'r' then
1996 Pic.Second_Sign := Index;
1997 Pic.Picture.Expanded (Index) := 'R';
1998 Skip;
2000 else
2001 raise Picture_Error;
2002 end if;
2004 return;
2006 when 'D' | 'd' =>
2007 Pic.Sign_Position := Index;
2008 Pic.Picture.Expanded (Index) := 'D';
2009 Skip;
2011 if Look = 'B' or else Look = 'b' then
2012 Pic.Second_Sign := Index;
2013 Pic.Picture.Expanded (Index) := 'B';
2014 Skip;
2016 else
2017 raise Picture_Error;
2018 end if;
2020 return;
2022 when '>' =>
2023 if Pic.Picture.Expanded (Pic.Sign_Position) = '<' then
2024 Pic.Second_Sign := Index;
2025 Skip;
2027 else
2028 raise Picture_Error;
2029 end if;
2031 when others =>
2032 return;
2033 end case;
2034 end Optional_RHS_Sign;
2036 -------------
2037 -- Picture --
2038 -------------
2040 -- Note that Picture can be called in either State
2042 -- It will set state to Valid only if a 9 is encountered or floating
2043 -- currency is called.
2045 procedure Picture is
2046 begin
2047 Debug_Start ("Picture");
2049 loop
2050 if At_End then
2051 return;
2052 end if;
2054 case Look is
2055 when '_' | '0' | '/' =>
2056 Skip;
2058 when 'B' | 'b' =>
2059 Pic.Picture.Expanded (Index) := 'b';
2060 Skip;
2062 when '$' =>
2063 Leading_Dollar;
2064 return;
2066 when '#' =>
2067 Leading_Pound;
2068 return;
2070 when '9' =>
2071 Computed_BWZ := False;
2072 Set_State (Okay);
2073 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2074 Skip;
2076 when 'V' | 'v' | '.' =>
2077 Pic.Radix_Position := Index;
2078 Skip;
2079 Number_Fraction;
2080 Trailing_Currency;
2081 return;
2083 when others =>
2084 return;
2085 end case;
2086 end loop;
2087 end Picture;
2089 ---------------------
2090 -- Picture_Bracket --
2091 ---------------------
2093 procedure Picture_Bracket is
2094 begin
2095 Pic.Sign_Position := Index;
2096 Debug_Start ("Picture_Bracket");
2097 Pic.Sign_Position := Index;
2099 -- Treat as a floating sign, and unwind otherwise
2101 Pic.Floater := '<';
2102 Pic.Start_Float := Index;
2103 Pic.End_Float := Index;
2105 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2106 -- sign place.
2108 Skip; -- Known Bracket
2110 loop
2111 case Look is
2112 when '_' | '0' | '/' =>
2113 Pic.End_Float := Index;
2114 Skip;
2116 when 'B' | 'b' =>
2117 Pic.End_Float := Index;
2118 Pic.Picture.Expanded (Index) := 'b';
2119 Skip;
2121 when '<' =>
2122 Set_State (Okay); -- "<<>" is enough.
2123 Floating_Bracket;
2124 Trailing_Currency;
2125 Trailing_Bracket;
2126 return;
2128 when '$' | '#' | '9' | '*' =>
2129 if State /= Okay then
2130 Pic.Floater := '!';
2131 Pic.Start_Float := Invalid_Position;
2132 Pic.End_Float := Invalid_Position;
2133 end if;
2135 Picture;
2136 Trailing_Bracket;
2137 Set_State (Okay);
2138 return;
2140 when '.' | 'V' | 'v' =>
2141 if State /= Okay then
2142 Pic.Floater := '!';
2143 Pic.Start_Float := Invalid_Position;
2144 Pic.End_Float := Invalid_Position;
2145 end if;
2147 -- Don't assume that state is okay, haven't seen a digit
2149 Picture;
2150 Trailing_Bracket;
2151 return;
2153 when others =>
2154 raise Picture_Error;
2155 end case;
2156 end loop;
2157 end Picture_Bracket;
2159 -------------------
2160 -- Picture_Minus --
2161 -------------------
2163 procedure Picture_Minus is
2164 begin
2165 Debug_Start ("Picture_Minus");
2167 Pic.Sign_Position := Index;
2169 -- Treat as a floating sign, and unwind otherwise
2171 Pic.Floater := '-';
2172 Pic.Start_Float := Index;
2173 Pic.End_Float := Index;
2175 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2176 -- sign place.
2178 Skip; -- Known Minus
2180 loop
2181 case Look is
2182 when '_' | '0' | '/' =>
2183 Pic.End_Float := Index;
2184 Skip;
2186 when 'B' | 'b' =>
2187 Pic.End_Float := Index;
2188 Pic.Picture.Expanded (Index) := 'b';
2189 Skip;
2191 when '-' =>
2192 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2193 Pic.End_Float := Index;
2194 Skip;
2195 Set_State (Okay); -- "-- " is enough.
2196 Floating_Minus;
2197 Trailing_Currency;
2198 return;
2200 when '$' | '#' | '9' | '*' =>
2201 if State /= Okay then
2202 Pic.Floater := '!';
2203 Pic.Start_Float := Invalid_Position;
2204 Pic.End_Float := Invalid_Position;
2205 end if;
2207 Picture;
2208 Set_State (Okay);
2209 return;
2211 when 'Z' | 'z' =>
2213 -- Can't have Z and a floating sign
2215 if State = Okay then
2216 Set_State (Reject);
2217 end if;
2219 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2220 Zero_Suppression;
2221 Trailing_Currency;
2222 Optional_RHS_Sign;
2223 return;
2225 when '.' | 'V' | 'v' =>
2226 if State /= Okay then
2227 Pic.Floater := '!';
2228 Pic.Start_Float := Invalid_Position;
2229 Pic.End_Float := Invalid_Position;
2230 end if;
2232 -- Don't assume that state is okay, haven't seen a digit
2234 Picture;
2235 return;
2237 when others =>
2238 return;
2239 end case;
2240 end loop;
2241 end Picture_Minus;
2243 ------------------
2244 -- Picture_Plus --
2245 ------------------
2247 procedure Picture_Plus is
2248 begin
2249 Debug_Start ("Picture_Plus");
2250 Pic.Sign_Position := Index;
2252 -- Treat as a floating sign, and unwind otherwise
2254 Pic.Floater := '+';
2255 Pic.Start_Float := Index;
2256 Pic.End_Float := Index;
2258 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2259 -- sign place.
2261 Skip; -- Known Plus
2263 loop
2264 case Look is
2265 when '_' | '0' | '/' =>
2266 Pic.End_Float := Index;
2267 Skip;
2269 when 'B' | 'b' =>
2270 Pic.End_Float := Index;
2271 Pic.Picture.Expanded (Index) := 'b';
2272 Skip;
2274 when '+' =>
2275 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2276 Pic.End_Float := Index;
2277 Skip;
2278 Set_State (Okay); -- "++" is enough
2279 Floating_Plus;
2280 Trailing_Currency;
2281 return;
2283 when '$' | '#' | '9' | '*' =>
2284 if State /= Okay then
2285 Pic.Floater := '!';
2286 Pic.Start_Float := Invalid_Position;
2287 Pic.End_Float := Invalid_Position;
2288 end if;
2290 Picture;
2291 Set_State (Okay);
2292 return;
2294 when 'Z' | 'z' =>
2295 if State = Okay then
2296 Set_State (Reject);
2297 end if;
2299 -- Can't have Z and a floating sign
2301 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2303 -- '+Z' is acceptable
2305 Set_State (Okay);
2307 -- Overwrite Floater and Start_Float
2309 Pic.Floater := 'Z';
2310 Pic.Start_Float := Index;
2312 Zero_Suppression;
2313 Trailing_Currency;
2314 Optional_RHS_Sign;
2315 return;
2317 when '.' | 'V' | 'v' =>
2318 if State /= Okay then
2319 Pic.Floater := '!';
2320 Pic.Start_Float := Invalid_Position;
2321 Pic.End_Float := Invalid_Position;
2322 end if;
2324 -- Don't assume that state is okay, haven't seen a digit
2326 Picture;
2327 return;
2329 when others =>
2330 return;
2331 end case;
2332 end loop;
2333 end Picture_Plus;
2335 --------------------
2336 -- Picture_String --
2337 --------------------
2339 procedure Picture_String is
2340 begin
2341 Debug_Start ("Picture_String");
2343 while Is_Insert loop
2344 Skip;
2345 end loop;
2347 case Look is
2348 when '$' | '#' =>
2349 Picture;
2350 Optional_RHS_Sign;
2352 when '+' =>
2353 Picture_Plus;
2355 when '-' =>
2356 Picture_Minus;
2358 when '<' =>
2359 Picture_Bracket;
2361 when 'Z' | 'z' =>
2362 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2363 Zero_Suppression;
2364 Trailing_Currency;
2365 Optional_RHS_Sign;
2367 when '*' =>
2368 Star_Suppression;
2369 Trailing_Currency;
2370 Optional_RHS_Sign;
2372 when '9' | '.' | 'V' | 'v' =>
2373 Number;
2374 Trailing_Currency;
2375 Optional_RHS_Sign;
2377 when others =>
2378 raise Picture_Error;
2379 end case;
2381 -- Blank when zero either if the PIC does not contain a '9' or if
2382 -- requested by the user and no '*'.
2384 Pic.Blank_When_Zero :=
2385 (Computed_BWZ or else Pic.Blank_When_Zero)
2386 and then not Pic.Star_Fill;
2388 -- Star fill if '*' and no '9'
2390 Pic.Star_Fill := Pic.Star_Fill and then Computed_BWZ;
2392 if not At_End then
2393 Set_State (Reject);
2394 end if;
2395 end Picture_String;
2397 ---------------
2398 -- Set_State --
2399 ---------------
2401 procedure Set_State (L : Legality) is
2402 begin
2403 if Debug then
2404 Ada.Text_IO.Put_Line
2405 (" Set state from " & Legality'Image (State)
2406 & " to " & Legality'Image (L));
2407 end if;
2409 State := L;
2410 end Set_State;
2412 ----------
2413 -- Skip --
2414 ----------
2416 procedure Skip is
2417 begin
2418 if Debug then
2419 Ada.Text_IO.Put_Line (" Skip " & Pic.Picture.Expanded (Index));
2420 end if;
2422 Index := Index + 1;
2423 end Skip;
2425 ----------------------
2426 -- Star_Suppression --
2427 ----------------------
2429 procedure Star_Suppression is
2430 begin
2431 Debug_Start ("Star_Suppression");
2433 if Pic.Floater /= '!' and then Pic.Floater /= '*' then
2435 -- Two floats not allowed
2437 raise Picture_Error;
2439 else
2440 Pic.Floater := '*';
2441 end if;
2443 Pic.Start_Float := Index;
2444 Pic.End_Float := Index;
2445 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2446 Set_State (Okay);
2448 -- Even a single * is a valid picture
2450 Pic.Star_Fill := True;
2451 Skip; -- Known *
2453 loop
2454 if At_End then
2455 return;
2456 end if;
2458 case Look is
2459 when '_' | '0' | '/' =>
2460 Pic.End_Float := Index;
2461 Skip;
2463 when 'B' | 'b' =>
2464 Pic.End_Float := Index;
2465 Pic.Picture.Expanded (Index) := 'b';
2466 Skip;
2468 when '*' =>
2469 Pic.End_Float := Index;
2470 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2471 Set_State (Okay); Skip;
2473 when '9' =>
2474 Set_State (Okay);
2475 Number_Completion;
2476 return;
2478 when '.' | 'V' | 'v' =>
2479 Pic.Radix_Position := Index;
2480 Skip;
2481 Number_Fraction_Or_Star_Fill;
2482 return;
2484 when '#' | '$' =>
2485 if Pic.Max_Currency_Digits > 0 then
2486 raise Picture_Error;
2487 end if;
2489 -- Cannot have leading and trailing currency
2491 Trailing_Currency;
2492 Set_State (Okay);
2493 return;
2495 when others =>
2496 raise Picture_Error;
2497 end case;
2498 end loop;
2499 end Star_Suppression;
2501 ----------------------
2502 -- Trailing_Bracket --
2503 ----------------------
2505 procedure Trailing_Bracket is
2506 begin
2507 Debug_Start ("Trailing_Bracket");
2509 if Look = '>' then
2510 Pic.Second_Sign := Index;
2511 Skip;
2512 else
2513 raise Picture_Error;
2514 end if;
2515 end Trailing_Bracket;
2517 -----------------------
2518 -- Trailing_Currency --
2519 -----------------------
2521 procedure Trailing_Currency is
2522 begin
2523 Debug_Start ("Trailing_Currency");
2525 if At_End then
2526 return;
2527 end if;
2529 if Look = '$' then
2530 Pic.Start_Currency := Index;
2531 Pic.End_Currency := Index;
2532 Skip;
2534 else
2535 while not At_End and then Look = '#' loop
2536 if Pic.Start_Currency = Invalid_Position then
2537 Pic.Start_Currency := Index;
2538 end if;
2540 Pic.End_Currency := Index;
2541 Skip;
2542 end loop;
2543 end if;
2545 loop
2546 if At_End then
2547 return;
2548 end if;
2550 case Look is
2551 when '_' | '0' | '/' =>
2552 Skip;
2554 when 'B' | 'b' =>
2555 Pic.Picture.Expanded (Index) := 'b';
2556 Skip;
2558 when others =>
2559 return;
2560 end case;
2561 end loop;
2562 end Trailing_Currency;
2564 ----------------------
2565 -- Zero_Suppression --
2566 ----------------------
2568 procedure Zero_Suppression is
2569 begin
2570 Debug_Start ("Zero_Suppression");
2572 Pic.Floater := 'Z';
2573 Pic.Start_Float := Index;
2574 Pic.End_Float := Index;
2575 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2576 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2578 Skip; -- Known Z
2580 loop
2581 -- Even a single Z is a valid picture
2583 if At_End then
2584 Set_State (Okay);
2585 return;
2586 end if;
2588 case Look is
2589 when '_' | '0' | '/' =>
2590 Pic.End_Float := Index;
2591 Skip;
2593 when 'B' | 'b' =>
2594 Pic.End_Float := Index;
2595 Pic.Picture.Expanded (Index) := 'b';
2596 Skip;
2598 when 'Z' | 'z' =>
2599 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2601 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2602 Pic.End_Float := Index;
2603 Set_State (Okay);
2604 Skip;
2606 when '9' =>
2607 Set_State (Okay);
2608 Number_Completion;
2609 return;
2611 when '.' | 'V' | 'v' =>
2612 Pic.Radix_Position := Index;
2613 Skip;
2614 Number_Fraction_Or_Z_Fill;
2615 return;
2617 when '#' | '$' =>
2618 Trailing_Currency;
2619 Set_State (Okay);
2620 return;
2622 when others =>
2623 return;
2624 end case;
2625 end loop;
2626 end Zero_Suppression;
2628 -- Start of processing for Precalculate
2630 begin
2631 pragma Debug (Set_Debug);
2633 Picture_String;
2635 if Debug then
2636 Ada.Text_IO.New_Line;
2637 Ada.Text_IO.Put (" Picture : """ &
2638 Pic.Picture.Expanded (1 .. Pic.Picture.Length) & """,");
2639 Ada.Text_IO.Put (" Floater : '" & Pic.Floater & "',");
2640 end if;
2642 if State = Reject then
2643 raise Picture_Error;
2644 end if;
2646 Debug_Integer (Pic.Radix_Position, "Radix Positon : ");
2647 Debug_Integer (Pic.Sign_Position, "Sign Positon : ");
2648 Debug_Integer (Pic.Second_Sign, "Second Sign : ");
2649 Debug_Integer (Pic.Start_Float, "Start Float : ");
2650 Debug_Integer (Pic.End_Float, "End Float : ");
2651 Debug_Integer (Pic.Start_Currency, "Start Currency : ");
2652 Debug_Integer (Pic.End_Currency, "End Currency : ");
2653 Debug_Integer (Pic.Max_Leading_Digits, "Max Leading Digits : ");
2654 Debug_Integer (Pic.Max_Trailing_Digits, "Max Trailing Digits : ");
2656 if Debug then
2657 Ada.Text_IO.New_Line;
2658 end if;
2660 exception
2662 when Constraint_Error =>
2664 -- To deal with special cases like null strings
2666 raise Picture_Error;
2667 end Precalculate;
2669 ----------------
2670 -- To_Picture --
2671 ----------------
2673 function To_Picture
2674 (Pic_String : String;
2675 Blank_When_Zero : Boolean := False) return Picture
2677 Result : Picture;
2679 begin
2680 declare
2681 Item : constant String := Expand (Pic_String);
2683 begin
2684 Result.Contents.Picture := (Item'Length, Item);
2685 Result.Contents.Original_BWZ := Blank_When_Zero;
2686 Result.Contents.Blank_When_Zero := Blank_When_Zero;
2687 Precalculate (Result.Contents);
2688 return Result;
2689 end;
2691 exception
2692 when others =>
2693 raise Picture_Error;
2694 end To_Picture;
2696 -----------
2697 -- Valid --
2698 -----------
2700 function Valid
2701 (Pic_String : String;
2702 Blank_When_Zero : Boolean := False) return Boolean
2704 begin
2705 declare
2706 Expanded_Pic : constant String := Expand (Pic_String);
2707 -- Raises Picture_Error if Item not well-formed
2709 Format_Rec : Format_Record;
2711 begin
2712 Format_Rec.Picture := (Expanded_Pic'Length, Expanded_Pic);
2713 Format_Rec.Blank_When_Zero := Blank_When_Zero;
2714 Format_Rec.Original_BWZ := Blank_When_Zero;
2715 Precalculate (Format_Rec);
2717 -- False only if Blank_When_Zero is True but the pic string has a '*'
2719 return not Blank_When_Zero
2720 or else Strings_Fixed.Index (Expanded_Pic, "*") = 0;
2721 end;
2723 exception
2724 when others => return False;
2725 end Valid;
2727 --------------------
2728 -- Decimal_Output --
2729 --------------------
2731 package body Decimal_Output is
2733 -----------
2734 -- Image --
2735 -----------
2737 function Image
2738 (Item : Num;
2739 Pic : Picture;
2740 Currency : String := Default_Currency;
2741 Fill : Character := Default_Fill;
2742 Separator : Character := Default_Separator;
2743 Radix_Mark : Character := Default_Radix_Mark) return String
2745 begin
2746 return Format_Number
2747 (Pic.Contents, Num'Image (Item),
2748 Currency, Fill, Separator, Radix_Mark);
2749 end Image;
2751 ------------
2752 -- Length --
2753 ------------
2755 function Length
2756 (Pic : Picture;
2757 Currency : String := Default_Currency) return Natural
2759 Picstr : constant String := Pic_String (Pic);
2760 V_Adjust : Integer := 0;
2761 Cur_Adjust : Integer := 0;
2763 begin
2764 -- Check if Picstr has 'V' or '$'
2766 -- If 'V', then length is 1 less than otherwise
2768 -- If '$', then length is Currency'Length-1 more than otherwise
2770 -- This should use the string handling package ???
2772 for J in Picstr'Range loop
2773 if Picstr (J) = 'V' then
2774 V_Adjust := -1;
2776 elsif Picstr (J) = '$' then
2777 Cur_Adjust := Currency'Length - 1;
2778 end if;
2779 end loop;
2781 return Picstr'Length - V_Adjust + Cur_Adjust;
2782 end Length;
2784 ---------
2785 -- Put --
2786 ---------
2788 procedure Put
2789 (File : Text_IO.File_Type;
2790 Item : Num;
2791 Pic : Picture;
2792 Currency : String := Default_Currency;
2793 Fill : Character := Default_Fill;
2794 Separator : Character := Default_Separator;
2795 Radix_Mark : Character := Default_Radix_Mark)
2797 begin
2798 Text_IO.Put (File, Image (Item, Pic,
2799 Currency, Fill, Separator, Radix_Mark));
2800 end Put;
2802 procedure Put
2803 (Item : Num;
2804 Pic : Picture;
2805 Currency : String := Default_Currency;
2806 Fill : Character := Default_Fill;
2807 Separator : Character := Default_Separator;
2808 Radix_Mark : Character := Default_Radix_Mark)
2810 begin
2811 Text_IO.Put (Image (Item, Pic,
2812 Currency, Fill, Separator, Radix_Mark));
2813 end Put;
2815 procedure Put
2816 (To : out String;
2817 Item : Num;
2818 Pic : Picture;
2819 Currency : String := Default_Currency;
2820 Fill : Character := Default_Fill;
2821 Separator : Character := Default_Separator;
2822 Radix_Mark : Character := Default_Radix_Mark)
2824 Result : constant String :=
2825 Image (Item, Pic, Currency, Fill, Separator, Radix_Mark);
2827 begin
2828 if Result'Length > To'Length then
2829 raise Ada.Text_IO.Layout_Error;
2830 else
2831 Strings_Fixed.Move (Source => Result, Target => To,
2832 Justify => Strings.Right);
2833 end if;
2834 end Put;
2836 -----------
2837 -- Valid --
2838 -----------
2840 function Valid
2841 (Item : Num;
2842 Pic : Picture;
2843 Currency : String := Default_Currency) return Boolean
2845 begin
2846 declare
2847 Temp : constant String := Image (Item, Pic, Currency);
2848 pragma Warnings (Off, Temp);
2849 begin
2850 return True;
2851 end;
2853 exception
2854 when Ada.Text_IO.Layout_Error => return False;
2856 end Valid;
2857 end Decimal_Output;
2859 end Ada.Text_IO.Editing;