* config/xtensa/linux.h (TARGET_OS_CPP_BUILTINS): Remove definition of
[official-gcc.git] / gcc / ada / a-teioed.adb
blobf273a246b677dc8bb10ca20415563196dfad1ab7
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 -- Copyright (C) 1992-2001 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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
21 -- --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
28 -- --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
31 -- --
32 ------------------------------------------------------------------------------
34 with Ada.Strings.Fixed;
35 package body Ada.Text_IO.Editing is
37 package Strings renames Ada.Strings;
38 package Strings_Fixed renames Ada.Strings.Fixed;
39 package Text_IO renames Ada.Text_IO;
41 ---------------------
42 -- Blank_When_Zero --
43 ---------------------
45 function Blank_When_Zero (Pic : in Picture) return Boolean is
46 begin
47 return Pic.Contents.Original_BWZ;
48 end Blank_When_Zero;
50 ------------
51 -- Expand --
52 ------------
54 function Expand (Picture : in String) return String is
55 Result : String (1 .. MAX_PICSIZE);
56 Picture_Index : Integer := Picture'First;
57 Result_Index : Integer := Result'First;
58 Count : Natural;
59 Last : Integer;
61 package Int_IO is new Ada.Text_IO.Integer_IO (Integer);
63 begin
64 if Picture'Length < 1 then
65 raise Picture_Error;
66 end if;
68 if Picture (Picture'First) = '(' then
69 raise Picture_Error;
70 end if;
72 loop
73 case Picture (Picture_Index) is
75 when '(' =>
76 Int_IO.Get (Picture (Picture_Index + 1 .. Picture'Last),
77 Count, Last);
79 if Picture (Last + 1) /= ')' then
80 raise Picture_Error;
81 end if;
83 -- In what follows note that one copy of the repeated
84 -- character has already been made, so a count of one is a
85 -- no-op, and a count of zero erases a character.
87 for J in 2 .. Count loop
88 Result (Result_Index + J - 2) := Picture (Picture_Index - 1);
89 end loop;
91 Result_Index := Result_Index + Count - 1;
93 -- Last + 1 was a ')' throw it away too.
95 Picture_Index := Last + 2;
97 when ')' =>
98 raise Picture_Error;
100 when others =>
101 Result (Result_Index) := Picture (Picture_Index);
102 Picture_Index := Picture_Index + 1;
103 Result_Index := Result_Index + 1;
105 end case;
107 exit when Picture_Index > Picture'Last;
108 end loop;
110 return Result (1 .. Result_Index - 1);
112 exception
113 when others =>
114 raise Picture_Error;
116 end Expand;
118 -------------------
119 -- Format_Number --
120 -------------------
122 function Format_Number
123 (Pic : Format_Record;
124 Number : String;
125 Currency_Symbol : String;
126 Fill_Character : Character;
127 Separator_Character : Character;
128 Radix_Point : Character)
129 return String
131 Attrs : Number_Attributes := Parse_Number_String (Number);
132 Position : Integer;
133 Rounded : String := Number;
135 Sign_Position : Integer := Pic.Sign_Position; -- may float.
137 Answer : String (1 .. Pic.Picture.Length) := Pic.Picture.Expanded;
138 Last : Integer;
139 Currency_Pos : Integer := Pic.Start_Currency;
141 Dollar : Boolean := False;
142 -- Overridden immediately if necessary.
144 Zero : Boolean := True;
145 -- Set to False when a non-zero digit is output.
147 begin
149 -- If the picture has fewer decimal places than the number, the image
150 -- must be rounded according to the usual rules.
152 if Attrs.Has_Fraction then
153 declare
154 R : constant Integer :=
155 (Attrs.End_Of_Fraction - Attrs.Start_Of_Fraction + 1)
156 - Pic.Max_Trailing_Digits;
157 R_Pos : Integer;
159 begin
160 if R > 0 then
161 R_Pos := Attrs.End_Of_Fraction - R;
163 if Rounded (R_Pos + 1) > '4' then
165 if Rounded (R_Pos) = '.' then
166 R_Pos := R_Pos - 1;
167 end if;
169 if Rounded (R_Pos) /= '9' then
170 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
171 else
172 Rounded (R_Pos) := '0';
173 R_Pos := R_Pos - 1;
175 while R_Pos > 1 loop
176 if Rounded (R_Pos) = '.' then
177 R_Pos := R_Pos - 1;
178 end if;
180 if Rounded (R_Pos) /= '9' then
181 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
182 exit;
183 else
184 Rounded (R_Pos) := '0';
185 R_Pos := R_Pos - 1;
186 end if;
187 end loop;
189 -- The rounding may add a digit in front. Either the
190 -- leading blank or the sign (already captured) can
191 -- be overwritten.
193 if R_Pos = 1 then
194 Rounded (R_Pos) := '1';
195 Attrs.Start_Of_Int := Attrs.Start_Of_Int - 1;
196 end if;
197 end if;
198 end if;
199 end if;
200 end;
201 end if;
203 if Pic.Start_Currency /= Invalid_Position then
204 Dollar := Answer (Pic.Start_Currency) = '$';
205 end if;
207 -- Fix up "direct inserts" outside the playing field. Set up as one
208 -- loop to do the beginning, one (reverse) loop to do the end.
210 Last := 1;
211 loop
212 exit when Last = Pic.Start_Float;
213 exit when Last = Pic.Radix_Position;
214 exit when Answer (Last) = '9';
216 case Answer (Last) is
218 when '_' =>
219 Answer (Last) := Separator_Character;
221 when 'b' =>
222 Answer (Last) := ' ';
224 when others =>
225 null;
227 end case;
229 exit when Last = Answer'Last;
231 Last := Last + 1;
232 end loop;
234 -- Now for the end...
236 for J in reverse Last .. Answer'Last loop
237 exit when J = Pic.Radix_Position;
239 -- Do this test First, Separator_Character can equal Pic.Floater.
241 if Answer (J) = Pic.Floater then
242 exit;
243 end if;
245 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;
259 end case;
260 end loop;
262 -- Non-floating sign
264 if Pic.Start_Currency /= -1
265 and then Answer (Pic.Start_Currency) = '#'
266 and then Pic.Floater /= '#'
267 then
268 if Currency_Symbol'Length >
269 Pic.End_Currency - Pic.Start_Currency + 1
270 then
271 raise Picture_Error;
273 elsif Currency_Symbol'Length =
274 Pic.End_Currency - Pic.Start_Currency + 1
275 then
276 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
277 Currency_Symbol;
279 elsif Pic.Radix_Position = Invalid_Position
280 or else Pic.Start_Currency < Pic.Radix_Position
281 then
282 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
283 (others => ' ');
284 Answer (Pic.End_Currency - Currency_Symbol'Length + 1 ..
285 Pic.End_Currency) := Currency_Symbol;
287 else
288 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
289 (others => ' ');
290 Answer (Pic.Start_Currency ..
291 Pic.Start_Currency + Currency_Symbol'Length - 1) :=
292 Currency_Symbol;
293 end if;
294 end if;
296 -- Fill in leading digits
298 if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
299 Pic.Max_Leading_Digits
300 then
301 raise Layout_Error;
302 end if;
304 if Pic.Radix_Position = Invalid_Position then
305 Position := Answer'Last;
306 else
307 Position := Pic.Radix_Position - 1;
308 end if;
310 for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop
312 while Answer (Position) /= '9'
313 and Answer (Position) /= Pic.Floater
314 loop
315 if Answer (Position) = '_' then
316 Answer (Position) := Separator_Character;
318 elsif Answer (Position) = 'b' then
319 Answer (Position) := ' ';
320 end if;
322 Position := Position - 1;
323 end loop;
325 Answer (Position) := Rounded (J);
327 if Rounded (J) /= '0' then
328 Zero := False;
329 end if;
331 Position := Position - 1;
332 end loop;
334 -- Do lead float
336 if Pic.Start_Float = Invalid_Position then
338 -- No leading floats, but need to change '9' to '0', '_' to
339 -- Separator_Character and 'b' to ' '.
341 for J in Last .. Position loop
343 -- Last set when fixing the "uninteresting" leaders above.
344 -- Don't duplicate the work.
346 if Answer (J) = '9' then
347 Answer (J) := '0';
349 elsif Answer (J) = '_' then
350 Answer (J) := Separator_Character;
352 elsif Answer (J) = 'b' then
353 Answer (J) := ' ';
354 end if;
355 end loop;
357 elsif Pic.Floater = '<'
358 or else
359 Pic.Floater = '+'
360 or else
361 Pic.Floater = '-'
362 then
363 for J in Pic.End_Float .. Position loop -- May be null range.
364 if Answer (J) = '9' then
365 Answer (J) := '0';
367 elsif Answer (J) = '_' then
368 Answer (J) := Separator_Character;
370 elsif Answer (J) = 'b' then
371 Answer (J) := ' ';
372 end if;
373 end loop;
375 if Position > Pic.End_Float then
376 Position := Pic.End_Float;
377 end if;
379 for J in Pic.Start_Float .. Position - 1 loop
380 Answer (J) := ' ';
381 end loop;
383 Answer (Position) := Pic.Floater;
384 Sign_Position := Position;
386 elsif Pic.Floater = '$' then
388 for J in Pic.End_Float .. Position loop -- May be null range.
389 if Answer (J) = '9' then
390 Answer (J) := '0';
392 elsif Answer (J) = '_' then
393 Answer (J) := ' '; -- no separators before leftmost digit.
395 elsif Answer (J) = 'b' then
396 Answer (J) := ' ';
397 end if;
398 end loop;
400 if Position > Pic.End_Float then
401 Position := Pic.End_Float;
402 end if;
404 for J in Pic.Start_Float .. Position - 1 loop
405 Answer (J) := ' ';
406 end loop;
408 Answer (Position) := Pic.Floater;
409 Currency_Pos := Position;
411 elsif Pic.Floater = '*' then
413 for J in Pic.End_Float .. Position loop -- May be null range.
414 if Answer (J) = '9' then
415 Answer (J) := '0';
417 elsif Answer (J) = '_' then
418 Answer (J) := Separator_Character;
420 elsif Answer (J) = 'b' then
421 Answer (J) := '*';
422 end if;
423 end loop;
425 if Position > Pic.End_Float then
426 Position := Pic.End_Float;
427 end if;
429 for J in Pic.Start_Float .. Position loop
430 Answer (J) := '*';
431 end loop;
433 else
434 if Pic.Floater = '#' then
435 Currency_Pos := Currency_Symbol'Length;
436 end if;
438 for J in reverse Pic.Start_Float .. Position loop
439 case Answer (J) is
441 when '*' =>
442 Answer (J) := Fill_Character;
444 when 'Z' | 'b' | '/' | '0' =>
445 Answer (J) := ' ';
447 when '9' =>
448 Answer (J) := '0';
450 when '.' | 'V' | 'v' | '<' | '$' | '+' | '-' =>
451 null;
453 when '#' =>
454 if Currency_Pos = 0 then
455 Answer (J) := ' ';
456 else
457 Answer (J) := Currency_Symbol (Currency_Pos);
458 Currency_Pos := Currency_Pos - 1;
459 end if;
461 when '_' =>
463 case Pic.Floater is
465 when '*' =>
466 Answer (J) := Fill_Character;
468 when 'Z' | 'b' =>
469 Answer (J) := ' ';
471 when '#' =>
472 if Currency_Pos = 0 then
473 Answer (J) := ' ';
475 else
476 Answer (J) := Currency_Symbol (Currency_Pos);
477 Currency_Pos := Currency_Pos - 1;
478 end if;
480 when others =>
481 null;
483 end case;
485 when others =>
486 null;
488 end case;
489 end loop;
491 if Pic.Floater = '#' and then Currency_Pos /= 0 then
492 raise Layout_Error;
493 end if;
494 end if;
496 -- Do sign
498 if Sign_Position = Invalid_Position then
499 if Attrs.Negative then
500 raise Layout_Error;
501 end if;
503 else
504 if Attrs.Negative then
505 case Answer (Sign_Position) is
506 when 'C' | 'D' | '-' =>
507 null;
509 when '+' =>
510 Answer (Sign_Position) := '-';
512 when '<' =>
513 Answer (Sign_Position) := '(';
514 Answer (Pic.Second_Sign) := ')';
516 when others =>
517 raise Picture_Error;
519 end case;
521 else -- positive
523 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;
538 end case;
539 end if;
540 end if;
542 -- Fill in trailing digits
544 if Pic.Max_Trailing_Digits > 0 then
546 if Attrs.Has_Fraction then
547 Position := Attrs.Start_Of_Fraction;
548 Last := Pic.Radix_Position + 1;
550 for J in Last .. Answer'Last loop
552 if Answer (J) = '9' or Answer (J) = Pic.Floater then
553 Answer (J) := Rounded (Position);
555 if Rounded (Position) /= '0' then
556 Zero := False;
557 end if;
559 Position := Position + 1;
560 Last := J + 1;
562 -- Used up fraction but remember place in Answer
564 exit when Position > Attrs.End_Of_Fraction;
566 elsif Answer (J) = 'b' then
567 Answer (J) := ' ';
569 elsif Answer (J) = '_' then
570 Answer (J) := Separator_Character;
572 end if;
574 Last := J + 1;
575 end loop;
577 Position := Last;
579 else
580 Position := Pic.Radix_Position + 1;
581 end if;
583 -- Now fill remaining 9's with zeros and _ with separators
585 Last := Answer'Last;
587 for J in Position .. Last loop
588 if Answer (J) = '9' then
589 Answer (J) := '0';
591 elsif Answer (J) = Pic.Floater then
592 Answer (J) := '0';
594 elsif Answer (J) = '_' then
595 Answer (J) := Separator_Character;
597 elsif Answer (J) = 'b' then
598 Answer (J) := ' ';
600 end if;
601 end loop;
603 Position := Last + 1;
605 else
606 if Pic.Floater = '#' and then Currency_Pos /= 0 then
607 raise Layout_Error;
608 end if;
610 -- No trailing digits, but now J may need to stick in a currency
611 -- symbol or sign.
613 if Pic.Start_Currency = Invalid_Position then
614 Position := Answer'Last + 1;
615 else
616 Position := Pic.Start_Currency;
617 end if;
618 end if;
620 for J in Position .. Answer'Last loop
622 if Pic.Start_Currency /= Invalid_Position and then
623 Answer (Pic.Start_Currency) = '#' then
624 Currency_Pos := 1;
625 end if;
627 -- Note: There are some weird cases J can imagine with 'b' or '#'
628 -- in currency strings where the following code will cause
629 -- glitches. The trick is to tell when the character in the
630 -- answer should be checked, and when to look at the original
631 -- string. Some other time. RIE 11/26/96 ???
633 case Answer (J) is
634 when '*' =>
635 Answer (J) := Fill_Character;
637 when 'b' =>
638 Answer (J) := ' ';
640 when '#' =>
641 if Currency_Pos > Currency_Symbol'Length then
642 Answer (J) := ' ';
644 else
645 Answer (J) := Currency_Symbol (Currency_Pos);
646 Currency_Pos := Currency_Pos + 1;
647 end if;
649 when '_' =>
651 case Pic.Floater is
653 when '*' =>
654 Answer (J) := Fill_Character;
656 when 'Z' | 'z' =>
657 Answer (J) := ' ';
659 when '#' =>
660 if Currency_Pos > Currency_Symbol'Length then
661 Answer (J) := ' ';
662 else
663 Answer (J) := Currency_Symbol (Currency_Pos);
664 Currency_Pos := Currency_Pos + 1;
665 end if;
667 when others =>
668 null;
670 end case;
672 when others =>
673 exit;
675 end case;
676 end loop;
678 -- Now get rid of Blank_when_Zero and complete Star fill.
680 if Zero and Pic.Blank_When_Zero then
682 -- Value is zero, and blank it.
684 Last := Answer'Last;
686 if Dollar then
687 Last := Last - 1 + Currency_Symbol'Length;
688 end if;
690 if Pic.Radix_Position /= Invalid_Position and then
691 Answer (Pic.Radix_Position) = 'V' then
692 Last := Last - 1;
693 end if;
695 return String' (1 .. Last => ' ');
697 elsif Zero and Pic.Star_Fill then
698 Last := Answer'Last;
700 if Dollar then
701 Last := Last - 1 + Currency_Symbol'Length;
702 end if;
704 if Pic.Radix_Position /= Invalid_Position then
706 if Answer (Pic.Radix_Position) = 'V' then
707 Last := Last - 1;
709 elsif Dollar then
710 if Pic.Radix_Position > Pic.Start_Currency then
711 return String' (1 .. Pic.Radix_Position - 1 => '*') &
712 Radix_Point &
713 String' (Pic.Radix_Position + 1 .. Last => '*');
715 else
716 return
717 String'
718 (1 ..
719 Pic.Radix_Position + Currency_Symbol'Length - 2 =>
720 '*') & Radix_Point &
721 String'
722 (Pic.Radix_Position + Currency_Symbol'Length .. Last
723 => '*');
724 end if;
726 else
727 return String' (1 .. Pic.Radix_Position - 1 => '*') &
728 Radix_Point &
729 String' (Pic.Radix_Position + 1 .. Last => '*');
730 end if;
731 end if;
733 return String' (1 .. Last => '*');
734 end if;
736 -- This was once a simple return statement, now there are nine
737 -- different return cases. Not to mention the five above to deal
738 -- with zeros. Why not split things out?
740 -- Processing the radix and sign expansion separately
741 -- would require lots of copying--the string and some of its
742 -- indices--without really simplifying the logic. The cases are:
744 -- 1) Expand $, replace '.' with Radix_Point
745 -- 2) No currency expansion, replace '.' with Radix_Point
746 -- 3) Expand $, radix blanked
747 -- 4) No currency expansion, radix blanked
748 -- 5) Elide V
749 -- 6) Expand $, Elide V
750 -- 7) Elide V, Expand $ (Two cases depending on order.)
751 -- 8) No radix, expand $
752 -- 9) No radix, no currency expansion
754 if Pic.Radix_Position /= Invalid_Position then
756 if Answer (Pic.Radix_Position) = '.' then
757 Answer (Pic.Radix_Position) := Radix_Point;
759 if Dollar then
761 -- 1) Expand $, replace '.' with Radix_Point
763 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
764 Answer (Currency_Pos + 1 .. Answer'Last);
766 else
767 -- 2) No currency expansion, replace '.' with Radix_Point
769 return Answer;
770 end if;
772 elsif Answer (Pic.Radix_Position) = ' ' then -- blanked radix.
773 if Dollar then
775 -- 3) Expand $, radix blanked
777 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
778 Answer (Currency_Pos + 1 .. Answer'Last);
780 else
781 -- 4) No expansion, radix blanked
783 return Answer;
784 end if;
786 -- V cases
788 else
789 if not Dollar then
791 -- 5) Elide V
793 return Answer (1 .. Pic.Radix_Position - 1) &
794 Answer (Pic.Radix_Position + 1 .. Answer'Last);
796 elsif Currency_Pos < Pic.Radix_Position then
798 -- 6) Expand $, Elide V
800 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
801 Answer (Currency_Pos + 1 .. Pic.Radix_Position - 1) &
802 Answer (Pic.Radix_Position + 1 .. Answer'Last);
804 else
805 -- 7) Elide V, Expand $
807 return Answer (1 .. Pic.Radix_Position - 1) &
808 Answer (Pic.Radix_Position + 1 .. Currency_Pos - 1) &
809 Currency_Symbol &
810 Answer (Currency_Pos + 1 .. Answer'Last);
811 end if;
812 end if;
814 elsif Dollar then
816 -- 8) No radix, expand $
818 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
819 Answer (Currency_Pos + 1 .. Answer'Last);
821 else
822 -- 9) No radix, no currency expansion
824 return Answer;
825 end if;
827 end Format_Number;
829 -------------------------
830 -- Parse_Number_String --
831 -------------------------
833 function Parse_Number_String (Str : String) return Number_Attributes is
834 Answer : Number_Attributes;
836 begin
837 for J in Str'Range loop
838 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 (intger) digits needs a null range.
906 return Answer;
908 end Parse_Number_String;
910 ----------------
911 -- Pic_String --
912 ----------------
914 -- The following ensures that we return B and not b being careful not
915 -- to break things which expect lower case b for blank. See CXF3A02.
917 function Pic_String (Pic : in Picture) return String is
918 Temp : String (1 .. Pic.Contents.Picture.Length) :=
919 Pic.Contents.Picture.Expanded;
920 begin
921 for J in Temp'Range loop
922 if Temp (J) = 'b' then Temp (J) := 'B'; end if;
923 end loop;
925 return Temp;
926 end Pic_String;
928 ------------------
929 -- Precalculate --
930 ------------------
932 procedure Precalculate (Pic : in out Format_Record) is
934 Computed_BWZ : Boolean := True;
935 Debug : Boolean := False;
937 type Legality is (Okay, Reject);
938 State : Legality := Reject;
939 -- Start in reject, which will reject null strings.
941 Index : Pic_Index := Pic.Picture.Expanded'First;
943 function At_End return Boolean;
944 pragma Inline (At_End);
946 procedure Set_State (L : Legality);
947 pragma Inline (Set_State);
949 function Look return Character;
950 pragma Inline (Look);
952 function Is_Insert return Boolean;
953 pragma Inline (Is_Insert);
955 procedure Skip;
956 pragma Inline (Skip);
958 procedure Debug_Start (Name : String);
959 pragma Inline (Debug_Start);
961 procedure Debug_Integer (Value : in Integer; S : String);
962 pragma Inline (Debug_Integer);
964 procedure Trailing_Currency;
965 procedure Trailing_Bracket;
966 procedure Number_Fraction;
967 procedure Number_Completion;
968 procedure Number_Fraction_Or_Bracket;
969 procedure Number_Fraction_Or_Z_Fill;
970 procedure Zero_Suppression;
971 procedure Floating_Bracket;
972 procedure Number_Fraction_Or_Star_Fill;
973 procedure Star_Suppression;
974 procedure Number_Fraction_Or_Dollar;
975 procedure Leading_Dollar;
976 procedure Number_Fraction_Or_Pound;
977 procedure Leading_Pound;
978 procedure Picture;
979 procedure Floating_Plus;
980 procedure Floating_Minus;
981 procedure Picture_Plus;
982 procedure Picture_Minus;
983 procedure Picture_Bracket;
984 procedure Number;
985 procedure Optional_RHS_Sign;
986 procedure Picture_String;
988 ------------
989 -- At_End --
990 ------------
992 function At_End return Boolean is
993 begin
994 return Index > Pic.Picture.Length;
995 end At_End;
997 -------------------
998 -- Debug_Integer --
999 -------------------
1001 procedure Debug_Integer (Value : in Integer; S : String) is
1002 use Ada.Text_IO; -- needed for >
1004 begin
1005 if Debug and then Value > 0 then
1006 if Ada.Text_IO.Col > 70 - S'Length then
1007 Ada.Text_IO.New_Line;
1008 end if;
1010 Ada.Text_IO.Put (' ' & S & Integer'Image (Value) & ',');
1011 end if;
1012 end Debug_Integer;
1014 -----------------
1015 -- Debug_Start --
1016 -----------------
1018 procedure Debug_Start (Name : String) is
1019 begin
1020 if Debug then
1021 Ada.Text_IO.Put_Line (" In " & Name & '.');
1022 end if;
1023 end Debug_Start;
1025 ----------------------
1026 -- Floating_Bracket --
1027 ----------------------
1029 -- Note that Floating_Bracket is only called with an acceptable
1030 -- prefix. But we don't set Okay, because we must end with a '>'.
1032 procedure Floating_Bracket is
1033 begin
1034 Debug_Start ("Floating_Bracket");
1035 Pic.Floater := '<';
1036 Pic.End_Float := Index;
1037 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1039 -- First bracket wasn't counted...
1041 Skip; -- known '<'
1043 loop
1044 if At_End then
1045 return;
1046 end if;
1048 case Look is
1050 when '_' | '0' | '/' =>
1051 Pic.End_Float := Index;
1052 Skip;
1054 when 'B' | 'b' =>
1055 Pic.End_Float := Index;
1056 Pic.Picture.Expanded (Index) := 'b';
1057 Skip;
1059 when '<' =>
1060 Pic.End_Float := Index;
1061 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1062 Skip;
1064 when '9' =>
1065 Number_Completion;
1067 when '$' =>
1068 Leading_Dollar;
1070 when '#' =>
1071 Leading_Pound;
1073 when 'V' | 'v' | '.' =>
1074 Pic.Radix_Position := Index;
1075 Skip;
1076 Number_Fraction_Or_Bracket;
1077 return;
1079 when others =>
1080 return;
1081 end case;
1082 end loop;
1083 end Floating_Bracket;
1086 --------------------
1087 -- Floating_Minus --
1088 --------------------
1090 procedure Floating_Minus is
1091 begin
1092 Debug_Start ("Floating_Minus");
1094 loop
1095 if At_End then
1096 return;
1097 end if;
1099 case Look is
1100 when '_' | '0' | '/' =>
1101 Pic.End_Float := Index;
1102 Skip;
1104 when 'B' | 'b' =>
1105 Pic.End_Float := Index;
1106 Pic.Picture.Expanded (Index) := 'b';
1107 Skip;
1109 when '-' =>
1110 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1111 Pic.End_Float := Index;
1112 Skip;
1114 when '9' =>
1115 Number_Completion;
1116 return;
1118 when '.' | 'V' | 'v' =>
1119 Pic.Radix_Position := Index;
1120 Skip; -- Radix
1122 while Is_Insert loop
1123 Skip;
1124 end loop;
1126 if At_End then
1127 return;
1128 end if;
1130 if Look = '-' then
1131 loop
1132 if At_End then
1133 return;
1134 end if;
1136 case Look is
1138 when '-' =>
1139 Pic.Max_Trailing_Digits :=
1140 Pic.Max_Trailing_Digits + 1;
1141 Pic.End_Float := Index;
1142 Skip;
1144 when '_' | '0' | '/' =>
1145 Skip;
1147 when 'B' | 'b' =>
1148 Pic.Picture.Expanded (Index) := 'b';
1149 Skip;
1151 when others =>
1152 return;
1154 end case;
1155 end loop;
1157 else
1158 Number_Completion;
1159 end if;
1161 return;
1163 when others =>
1164 return;
1165 end case;
1166 end loop;
1167 end Floating_Minus;
1169 -------------------
1170 -- Floating_Plus --
1171 -------------------
1173 procedure Floating_Plus is
1174 begin
1175 Debug_Start ("Floating_Plus");
1177 loop
1178 if At_End then
1179 return;
1180 end if;
1182 case Look is
1183 when '_' | '0' | '/' =>
1184 Pic.End_Float := Index;
1185 Skip;
1187 when 'B' | 'b' =>
1188 Pic.End_Float := Index;
1189 Pic.Picture.Expanded (Index) := 'b';
1190 Skip;
1192 when '+' =>
1193 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1194 Pic.End_Float := Index;
1195 Skip;
1197 when '9' =>
1198 Number_Completion;
1199 return;
1201 when '.' | 'V' | 'v' =>
1202 Pic.Radix_Position := Index;
1203 Skip; -- Radix
1205 while Is_Insert loop
1206 Skip;
1207 end loop;
1209 if At_End then
1210 return;
1211 end if;
1213 if Look = '+' then
1214 loop
1215 if At_End then
1216 return;
1217 end if;
1219 case Look is
1221 when '+' =>
1222 Pic.Max_Trailing_Digits :=
1223 Pic.Max_Trailing_Digits + 1;
1224 Pic.End_Float := Index;
1225 Skip;
1227 when '_' | '0' | '/' =>
1228 Skip;
1230 when 'B' | 'b' =>
1231 Pic.Picture.Expanded (Index) := 'b';
1232 Skip;
1234 when others =>
1235 return;
1237 end case;
1238 end loop;
1240 else
1241 Number_Completion;
1242 end if;
1244 return;
1246 when others =>
1247 return;
1249 end case;
1250 end loop;
1251 end Floating_Plus;
1253 ---------------
1254 -- Is_Insert --
1255 ---------------
1257 function Is_Insert return Boolean is
1258 begin
1259 if At_End then
1260 return False;
1261 end if;
1263 case Pic.Picture.Expanded (Index) is
1265 when '_' | '0' | '/' => return True;
1267 when 'B' | 'b' =>
1268 Pic.Picture.Expanded (Index) := 'b'; -- canonical
1269 return True;
1271 when others => return False;
1272 end case;
1273 end Is_Insert;
1275 --------------------
1276 -- Leading_Dollar --
1277 --------------------
1279 -- Note that Leading_Dollar can be called in either State.
1280 -- It will set state to Okay only if a 9 or (second) $
1281 -- is encountered.
1283 -- Also notice the tricky bit with State and Zero_Suppression.
1284 -- Zero_Suppression is Picture_Error if a '$' or a '9' has been
1285 -- encountered, exactly the cases where State has been set.
1287 procedure Leading_Dollar is
1288 begin
1289 Debug_Start ("Leading_Dollar");
1291 -- Treat as a floating dollar, and unwind otherwise.
1293 Pic.Floater := '$';
1294 Pic.Start_Currency := Index;
1295 Pic.End_Currency := Index;
1296 Pic.Start_Float := Index;
1297 Pic.End_Float := Index;
1299 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1300 -- currency place.
1302 Skip; -- known '$'
1304 loop
1305 if At_End then
1306 return;
1307 end if;
1309 case Look is
1311 when '_' | '0' | '/' =>
1312 Pic.End_Float := Index;
1313 Skip;
1315 -- A trailing insertion character is not part of the
1316 -- floating currency, so need to look ahead.
1318 if Look /= '$' then
1319 Pic.End_Float := Pic.End_Float - 1;
1320 end if;
1322 when 'B' | 'b' =>
1323 Pic.End_Float := Index;
1324 Pic.Picture.Expanded (Index) := 'b';
1325 Skip;
1327 when 'Z' | 'z' =>
1328 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1330 if State = Okay then
1331 raise Picture_Error;
1332 else
1333 -- Will overwrite Floater and Start_Float
1335 Zero_Suppression;
1336 end if;
1338 when '*' =>
1339 if State = Okay then
1340 raise Picture_Error;
1341 else
1342 -- Will overwrite Floater and Start_Float
1344 Star_Suppression;
1345 end if;
1347 when '$' =>
1348 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1349 Pic.End_Float := Index;
1350 Pic.End_Currency := Index;
1351 Set_State (Okay); Skip;
1353 when '9' =>
1354 if State /= Okay then
1355 Pic.Floater := '!';
1356 Pic.Start_Float := Invalid_Position;
1357 Pic.End_Float := Invalid_Position;
1358 end if;
1360 -- A single dollar does not a floating make.
1362 Number_Completion;
1363 return;
1365 when 'V' | 'v' | '.' =>
1366 if State /= Okay then
1367 Pic.Floater := '!';
1368 Pic.Start_Float := Invalid_Position;
1369 Pic.End_Float := Invalid_Position;
1370 end if;
1372 -- Only one dollar before the sign is okay,
1373 -- but doesn't float.
1375 Pic.Radix_Position := Index;
1376 Skip;
1377 Number_Fraction_Or_Dollar;
1378 return;
1380 when others =>
1381 return;
1383 end case;
1384 end loop;
1385 end Leading_Dollar;
1387 -------------------
1388 -- Leading_Pound --
1389 -------------------
1391 -- This one is complex! A Leading_Pound can be fixed or floating,
1392 -- but in some cases the decision has to be deferred until we leave
1393 -- this procedure. Also note that Leading_Pound can be called in
1394 -- either State.
1396 -- It will set state to Okay only if a 9 or (second) # is
1397 -- encountered.
1399 -- One Last note: In ambiguous cases, the currency is treated as
1400 -- floating unless there is only one '#'.
1402 procedure Leading_Pound is
1404 Inserts : Boolean := False;
1405 -- Set to True if a '_', '0', '/', 'B', or 'b' is encountered
1407 Must_Float : Boolean := False;
1408 -- Set to true if a '#' occurs after an insert.
1410 begin
1411 Debug_Start ("Leading_Pound");
1413 -- Treat as a floating currency. If it isn't, this will be
1414 -- overwritten later.
1416 Pic.Floater := '#';
1418 Pic.Start_Currency := Index;
1419 Pic.End_Currency := Index;
1420 Pic.Start_Float := Index;
1421 Pic.End_Float := Index;
1423 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1424 -- currency place.
1426 Pic.Max_Currency_Digits := 1; -- we've seen one.
1428 Skip; -- known '#'
1430 loop
1431 if At_End then
1432 return;
1433 end if;
1435 case Look is
1437 when '_' | '0' | '/' =>
1438 Pic.End_Float := Index;
1439 Inserts := True;
1440 Skip;
1442 when 'B' | 'b' =>
1443 Pic.Picture.Expanded (Index) := 'b';
1444 Pic.End_Float := Index;
1445 Inserts := True;
1446 Skip;
1448 when 'Z' | 'z' =>
1449 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1451 if Must_Float then
1452 raise Picture_Error;
1453 else
1454 Pic.Max_Leading_Digits := 0;
1456 -- Will overwrite Floater and Start_Float
1458 Zero_Suppression;
1459 end if;
1461 when '*' =>
1462 if Must_Float then
1463 raise Picture_Error;
1464 else
1465 Pic.Max_Leading_Digits := 0;
1467 -- Will overwrite Floater and Start_Float
1469 Star_Suppression;
1470 end if;
1472 when '#' =>
1473 if Inserts then
1474 Must_Float := True;
1475 end if;
1477 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1478 Pic.End_Float := Index;
1479 Pic.End_Currency := Index;
1480 Set_State (Okay);
1481 Skip;
1483 when '9' =>
1484 if State /= Okay then
1486 -- A single '#' doesn't float.
1488 Pic.Floater := '!';
1489 Pic.Start_Float := Invalid_Position;
1490 Pic.End_Float := Invalid_Position;
1491 end if;
1493 Number_Completion;
1494 return;
1496 when 'V' | 'v' | '.' =>
1497 if State /= Okay then
1498 Pic.Floater := '!';
1499 Pic.Start_Float := Invalid_Position;
1500 Pic.End_Float := Invalid_Position;
1501 end if;
1503 -- Only one pound before the sign is okay,
1504 -- but doesn't float.
1506 Pic.Radix_Position := Index;
1507 Skip;
1508 Number_Fraction_Or_Pound;
1509 return;
1511 when others =>
1512 return;
1513 end case;
1514 end loop;
1515 end Leading_Pound;
1517 ----------
1518 -- Look --
1519 ----------
1521 function Look return Character is
1522 begin
1523 if At_End then
1524 raise Picture_Error;
1525 end if;
1527 return Pic.Picture.Expanded (Index);
1528 end Look;
1530 ------------
1531 -- Number --
1532 ------------
1534 procedure Number is
1535 begin
1536 Debug_Start ("Number");
1538 loop
1540 case Look is
1541 when '_' | '0' | '/' =>
1542 Skip;
1544 when 'B' | 'b' =>
1545 Pic.Picture.Expanded (Index) := 'b';
1546 Skip;
1548 when '9' =>
1549 Computed_BWZ := False;
1550 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1551 Set_State (Okay);
1552 Skip;
1554 when '.' | 'V' | 'v' =>
1555 Pic.Radix_Position := Index;
1556 Skip;
1557 Number_Fraction;
1558 return;
1560 when others =>
1561 return;
1563 end case;
1565 if At_End then
1566 return;
1567 end if;
1569 -- Will return in Okay state if a '9' was seen.
1571 end loop;
1572 end Number;
1574 -----------------------
1575 -- Number_Completion --
1576 -----------------------
1578 procedure Number_Completion is
1579 begin
1580 Debug_Start ("Number_Completion");
1582 while not At_End loop
1583 case Look is
1585 when '_' | '0' | '/' =>
1586 Skip;
1588 when 'B' | 'b' =>
1589 Pic.Picture.Expanded (Index) := 'b';
1590 Skip;
1592 when '9' =>
1593 Computed_BWZ := False;
1594 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1595 Set_State (Okay);
1596 Skip;
1598 when 'V' | 'v' | '.' =>
1599 Pic.Radix_Position := Index;
1600 Skip;
1601 Number_Fraction;
1602 return;
1604 when others =>
1605 return;
1606 end case;
1607 end loop;
1608 end Number_Completion;
1610 ---------------------
1611 -- Number_Fraction --
1612 ---------------------
1614 procedure Number_Fraction is
1615 begin
1616 -- Note that number fraction can be called in either State.
1617 -- It will set state to Valid only if a 9 is encountered.
1619 Debug_Start ("Number_Fraction");
1621 loop
1622 if At_End then
1623 return;
1624 end if;
1626 case Look is
1627 when '_' | '0' | '/' =>
1628 Skip;
1630 when 'B' | 'b' =>
1631 Pic.Picture.Expanded (Index) := 'b';
1632 Skip;
1634 when '9' =>
1635 Computed_BWZ := False;
1636 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1637 Set_State (Okay); Skip;
1639 when others =>
1640 return;
1641 end case;
1642 end loop;
1643 end Number_Fraction;
1645 --------------------------------
1646 -- Number_Fraction_Or_Bracket --
1647 --------------------------------
1649 procedure Number_Fraction_Or_Bracket is
1650 begin
1651 Debug_Start ("Number_Fraction_Or_Bracket");
1653 loop
1654 if At_End then
1655 return;
1656 end if;
1658 case Look is
1660 when '_' | '0' | '/' => Skip;
1662 when 'B' | 'b' =>
1663 Pic.Picture.Expanded (Index) := 'b';
1664 Skip;
1666 when '<' =>
1667 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1668 Pic.End_Float := Index;
1669 Skip;
1671 loop
1672 if At_End then
1673 return;
1674 end if;
1676 case Look is
1677 when '_' | '0' | '/' =>
1678 Skip;
1680 when 'B' | 'b' =>
1681 Pic.Picture.Expanded (Index) := 'b';
1682 Skip;
1684 when '<' =>
1685 Pic.Max_Trailing_Digits :=
1686 Pic.Max_Trailing_Digits + 1;
1687 Pic.End_Float := Index;
1688 Skip;
1690 when others =>
1691 return;
1692 end case;
1693 end loop;
1695 when others =>
1696 Number_Fraction;
1697 return;
1698 end case;
1699 end loop;
1700 end Number_Fraction_Or_Bracket;
1702 -------------------------------
1703 -- Number_Fraction_Or_Dollar --
1704 -------------------------------
1706 procedure Number_Fraction_Or_Dollar is
1707 begin
1708 Debug_Start ("Number_Fraction_Or_Dollar");
1710 loop
1711 if At_End then
1712 return;
1713 end if;
1715 case Look is
1716 when '_' | '0' | '/' =>
1717 Skip;
1719 when 'B' | 'b' =>
1720 Pic.Picture.Expanded (Index) := 'b';
1721 Skip;
1723 when '$' =>
1724 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1725 Pic.End_Float := Index;
1726 Skip;
1728 loop
1729 if At_End then
1730 return;
1731 end if;
1733 case Look is
1734 when '_' | '0' | '/' =>
1735 Skip;
1737 when 'B' | 'b' =>
1738 Pic.Picture.Expanded (Index) := 'b';
1739 Skip;
1741 when '$' =>
1742 Pic.Max_Trailing_Digits :=
1743 Pic.Max_Trailing_Digits + 1;
1744 Pic.End_Float := Index;
1745 Skip;
1747 when others =>
1748 return;
1749 end case;
1750 end loop;
1752 when others =>
1753 Number_Fraction;
1754 return;
1755 end case;
1756 end loop;
1757 end Number_Fraction_Or_Dollar;
1759 ------------------------------
1760 -- Number_Fraction_Or_Pound --
1761 ------------------------------
1763 procedure Number_Fraction_Or_Pound is
1764 begin
1765 loop
1766 if At_End then
1767 return;
1768 end if;
1770 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 := Pic.Max_Trailing_Digits + 1;
1781 Pic.End_Float := Index;
1782 Skip;
1784 loop
1785 if At_End then
1786 return;
1787 end if;
1789 case Look is
1791 when '_' | '0' | '/' =>
1792 Skip;
1794 when 'B' | 'b' =>
1795 Pic.Picture.Expanded (Index) := 'b';
1796 Skip;
1798 when '#' =>
1799 Pic.Max_Trailing_Digits :=
1800 Pic.Max_Trailing_Digits + 1;
1801 Pic.End_Float := Index;
1802 Skip;
1804 when others =>
1805 return;
1807 end case;
1808 end loop;
1810 when others =>
1811 Number_Fraction;
1812 return;
1814 end case;
1815 end loop;
1816 end Number_Fraction_Or_Pound;
1818 ----------------------------------
1819 -- Number_Fraction_Or_Star_Fill --
1820 ----------------------------------
1822 procedure Number_Fraction_Or_Star_Fill is
1823 begin
1824 Debug_Start ("Number_Fraction_Or_Star_Fill");
1826 loop
1827 if At_End then
1828 return;
1829 end if;
1831 case Look is
1833 when '_' | '0' | '/' =>
1834 Skip;
1836 when 'B' | 'b' =>
1837 Pic.Picture.Expanded (Index) := 'b';
1838 Skip;
1840 when '*' =>
1841 Pic.Star_Fill := True;
1842 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1843 Pic.End_Float := Index;
1844 Skip;
1846 loop
1847 if At_End then
1848 return;
1849 end if;
1851 case Look is
1853 when '_' | '0' | '/' =>
1854 Skip;
1856 when 'B' | 'b' =>
1857 Pic.Picture.Expanded (Index) := 'b';
1858 Skip;
1860 when '*' =>
1861 Pic.Star_Fill := True;
1862 Pic.Max_Trailing_Digits :=
1863 Pic.Max_Trailing_Digits + 1;
1864 Pic.End_Float := Index;
1865 Skip;
1867 when others =>
1868 return;
1869 end case;
1870 end loop;
1872 when others =>
1873 Number_Fraction;
1874 return;
1876 end case;
1877 end loop;
1878 end Number_Fraction_Or_Star_Fill;
1880 -------------------------------
1881 -- Number_Fraction_Or_Z_Fill --
1882 -------------------------------
1884 procedure Number_Fraction_Or_Z_Fill is
1885 begin
1886 Debug_Start ("Number_Fraction_Or_Z_Fill");
1888 loop
1889 if At_End then
1890 return;
1891 end if;
1893 case Look is
1895 when '_' | '0' | '/' =>
1896 Skip;
1898 when 'B' | 'b' =>
1899 Pic.Picture.Expanded (Index) := 'b';
1900 Skip;
1902 when 'Z' | 'z' =>
1903 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1904 Pic.End_Float := Index;
1905 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1907 Skip;
1909 loop
1910 if At_End then
1911 return;
1912 end if;
1914 case Look is
1916 when '_' | '0' | '/' =>
1917 Skip;
1919 when 'B' | 'b' =>
1920 Pic.Picture.Expanded (Index) := 'b';
1921 Skip;
1923 when 'Z' | 'z' =>
1924 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1926 Pic.Max_Trailing_Digits :=
1927 Pic.Max_Trailing_Digits + 1;
1928 Pic.End_Float := Index;
1929 Skip;
1931 when others =>
1932 return;
1933 end case;
1934 end loop;
1936 when others =>
1937 Number_Fraction;
1938 return;
1939 end case;
1940 end loop;
1941 end Number_Fraction_Or_Z_Fill;
1943 -----------------------
1944 -- Optional_RHS_Sign --
1945 -----------------------
1947 procedure Optional_RHS_Sign is
1948 begin
1949 Debug_Start ("Optional_RHS_Sign");
1951 if At_End then
1952 return;
1953 end if;
1955 case Look is
1957 when '+' | '-' =>
1958 Pic.Sign_Position := Index;
1959 Skip;
1960 return;
1962 when 'C' | 'c' =>
1963 Pic.Sign_Position := Index;
1964 Pic.Picture.Expanded (Index) := 'C';
1965 Skip;
1967 if Look = 'R' or Look = 'r' then
1968 Pic.Second_Sign := Index;
1969 Pic.Picture.Expanded (Index) := 'R';
1970 Skip;
1972 else
1973 raise Picture_Error;
1974 end if;
1976 return;
1978 when 'D' | 'd' =>
1979 Pic.Sign_Position := Index;
1980 Pic.Picture.Expanded (Index) := 'D';
1981 Skip;
1983 if Look = 'B' or Look = 'b' then
1984 Pic.Second_Sign := Index;
1985 Pic.Picture.Expanded (Index) := 'B';
1986 Skip;
1988 else
1989 raise Picture_Error;
1990 end if;
1992 return;
1994 when '>' =>
1995 if Pic.Picture.Expanded (Pic.Sign_Position) = '<' then
1996 Pic.Second_Sign := Index;
1997 Skip;
1999 else
2000 raise Picture_Error;
2001 end if;
2003 when others =>
2004 return;
2006 end case;
2007 end Optional_RHS_Sign;
2009 -------------
2010 -- Picture --
2011 -------------
2013 -- Note that Picture can be called in either State.
2015 -- It will set state to Valid only if a 9 is encountered or floating
2016 -- currency is called.
2018 procedure Picture is
2019 begin
2020 Debug_Start ("Picture");
2022 loop
2023 if At_End then
2024 return;
2025 end if;
2027 case Look is
2029 when '_' | '0' | '/' =>
2030 Skip;
2032 when 'B' | 'b' =>
2033 Pic.Picture.Expanded (Index) := 'b';
2034 Skip;
2036 when '$' =>
2037 Leading_Dollar;
2038 return;
2040 when '#' =>
2041 Leading_Pound;
2042 return;
2044 when '9' =>
2045 Computed_BWZ := False;
2046 Set_State (Okay);
2047 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2048 Skip;
2050 when 'V' | 'v' | '.' =>
2051 Pic.Radix_Position := Index;
2052 Skip;
2053 Number_Fraction;
2054 Trailing_Currency;
2055 return;
2057 when others =>
2058 return;
2060 end case;
2061 end loop;
2062 end Picture;
2064 ---------------------
2065 -- Picture_Bracket --
2066 ---------------------
2068 procedure Picture_Bracket is
2069 begin
2070 Pic.Sign_Position := Index;
2071 Debug_Start ("Picture_Bracket");
2072 Pic.Sign_Position := Index;
2074 -- Treat as a floating sign, and unwind otherwise.
2076 Pic.Floater := '<';
2077 Pic.Start_Float := Index;
2078 Pic.End_Float := Index;
2080 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2081 -- sign place.
2083 Skip; -- Known Bracket
2085 loop
2086 case Look is
2088 when '_' | '0' | '/' =>
2089 Pic.End_Float := Index;
2090 Skip;
2092 when 'B' | 'b' =>
2093 Pic.End_Float := Index;
2094 Pic.Picture.Expanded (Index) := 'b';
2095 Skip;
2097 when '<' =>
2098 Set_State (Okay); -- "<<>" is enough.
2099 Floating_Bracket;
2100 Trailing_Currency;
2101 Trailing_Bracket;
2102 return;
2104 when '$' | '#' | '9' | '*' =>
2105 if State /= Okay then
2106 Pic.Floater := '!';
2107 Pic.Start_Float := Invalid_Position;
2108 Pic.End_Float := Invalid_Position;
2109 end if;
2111 Picture;
2112 Trailing_Bracket;
2113 Set_State (Okay);
2114 return;
2116 when '.' | 'V' | 'v' =>
2117 if State /= Okay then
2118 Pic.Floater := '!';
2119 Pic.Start_Float := Invalid_Position;
2120 Pic.End_Float := Invalid_Position;
2121 end if;
2123 -- Don't assume that state is okay, haven't seen a digit
2125 Picture;
2126 Trailing_Bracket;
2127 return;
2129 when others =>
2130 raise Picture_Error;
2132 end case;
2133 end loop;
2134 end Picture_Bracket;
2136 -------------------
2137 -- Picture_Minus --
2138 -------------------
2140 procedure Picture_Minus is
2141 begin
2142 Debug_Start ("Picture_Minus");
2144 Pic.Sign_Position := Index;
2146 -- Treat as a floating sign, and unwind otherwise.
2148 Pic.Floater := '-';
2149 Pic.Start_Float := Index;
2150 Pic.End_Float := Index;
2152 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2153 -- sign place.
2155 Skip; -- Known Minus
2157 loop
2158 case Look is
2160 when '_' | '0' | '/' =>
2161 Pic.End_Float := Index;
2162 Skip;
2164 when 'B' | 'b' =>
2165 Pic.End_Float := Index;
2166 Pic.Picture.Expanded (Index) := 'b';
2167 Skip;
2169 when '-' =>
2170 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2171 Pic.End_Float := Index;
2172 Skip;
2173 Set_State (Okay); -- "-- " is enough.
2174 Floating_Minus;
2175 Trailing_Currency;
2176 return;
2178 when '$' | '#' | '9' | '*' =>
2179 if State /= Okay then
2180 Pic.Floater := '!';
2181 Pic.Start_Float := Invalid_Position;
2182 Pic.End_Float := Invalid_Position;
2183 end if;
2185 Picture;
2186 Set_State (Okay);
2187 return;
2189 when 'Z' | 'z' =>
2191 -- Can't have Z and a floating sign.
2193 if State = Okay then
2194 Set_State (Reject);
2195 end if;
2197 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2198 Zero_Suppression;
2199 Trailing_Currency;
2200 Optional_RHS_Sign;
2201 return;
2203 when '.' | 'V' | 'v' =>
2204 if State /= Okay then
2205 Pic.Floater := '!';
2206 Pic.Start_Float := Invalid_Position;
2207 Pic.End_Float := Invalid_Position;
2208 end if;
2210 -- Don't assume that state is okay, haven't seen a digit.
2212 Picture;
2213 return;
2215 when others =>
2216 return;
2218 end case;
2219 end loop;
2220 end Picture_Minus;
2222 ------------------
2223 -- Picture_Plus --
2224 ------------------
2226 procedure Picture_Plus is
2227 begin
2228 Debug_Start ("Picture_Plus");
2229 Pic.Sign_Position := Index;
2231 -- Treat as a floating sign, and unwind otherwise.
2233 Pic.Floater := '+';
2234 Pic.Start_Float := Index;
2235 Pic.End_Float := Index;
2237 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2238 -- sign place.
2240 Skip; -- Known Plus
2242 loop
2243 case Look is
2245 when '_' | '0' | '/' =>
2246 Pic.End_Float := Index;
2247 Skip;
2249 when 'B' | 'b' =>
2250 Pic.End_Float := Index;
2251 Pic.Picture.Expanded (Index) := 'b';
2252 Skip;
2254 when '+' =>
2255 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2256 Pic.End_Float := Index;
2257 Skip;
2258 Set_State (Okay); -- "++" is enough.
2259 Floating_Plus;
2260 Trailing_Currency;
2261 return;
2263 when '$' | '#' | '9' | '*' =>
2264 if State /= Okay then
2265 Pic.Floater := '!';
2266 Pic.Start_Float := Invalid_Position;
2267 Pic.End_Float := Invalid_Position;
2268 end if;
2270 Picture;
2271 Set_State (Okay);
2272 return;
2274 when 'Z' | 'z' =>
2275 if State = Okay then
2276 Set_State (Reject);
2277 end if;
2279 -- Can't have Z and a floating sign.
2281 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2283 -- '+Z' is acceptable
2285 Set_State (Okay);
2287 Zero_Suppression;
2288 Trailing_Currency;
2289 Optional_RHS_Sign;
2290 return;
2292 when '.' | 'V' | 'v' =>
2293 if State /= Okay then
2294 Pic.Floater := '!';
2295 Pic.Start_Float := Invalid_Position;
2296 Pic.End_Float := Invalid_Position;
2297 end if;
2299 -- Don't assume that state is okay, haven't seen a digit.
2301 Picture;
2302 return;
2304 when others =>
2305 return;
2307 end case;
2308 end loop;
2309 end Picture_Plus;
2311 --------------------
2312 -- Picture_String --
2313 --------------------
2315 procedure Picture_String is
2316 begin
2317 Debug_Start ("Picture_String");
2319 while Is_Insert loop
2320 Skip;
2321 end loop;
2323 case Look is
2325 when '$' | '#' =>
2326 Picture;
2327 Optional_RHS_Sign;
2329 when '+' =>
2330 Picture_Plus;
2332 when '-' =>
2333 Picture_Minus;
2335 when '<' =>
2336 Picture_Bracket;
2338 when 'Z' | 'z' =>
2339 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2340 Zero_Suppression;
2341 Trailing_Currency;
2342 Optional_RHS_Sign;
2344 when '*' =>
2345 Star_Suppression;
2346 Trailing_Currency;
2347 Optional_RHS_Sign;
2349 when '9' | '.' | 'V' | 'v' =>
2350 Number;
2351 Trailing_Currency;
2352 Optional_RHS_Sign;
2354 when others =>
2355 raise Picture_Error;
2357 end case;
2359 -- Blank when zero either if the PIC does not contain a '9' or if
2360 -- requested by the user and no '*'
2362 Pic.Blank_When_Zero :=
2363 (Computed_BWZ or Pic.Blank_When_Zero) and not Pic.Star_Fill;
2365 -- Star fill if '*' and no '9'.
2367 Pic.Star_Fill := Pic.Star_Fill and Computed_BWZ;
2369 if not At_End then
2370 Set_State (Reject);
2371 end if;
2373 end Picture_String;
2375 ---------------
2376 -- Set_State --
2377 ---------------
2379 procedure Set_State (L : Legality) is
2380 begin
2381 if Debug then Ada.Text_IO.Put_Line
2382 (" Set state from " & Legality'Image (State) &
2383 " to " & Legality'Image (L));
2384 end if;
2386 State := L;
2387 end Set_State;
2389 ----------
2390 -- Skip --
2391 ----------
2393 procedure Skip is
2394 begin
2395 if Debug then Ada.Text_IO.Put_Line
2396 (" Skip " & Pic.Picture.Expanded (Index));
2397 end if;
2399 Index := Index + 1;
2400 end Skip;
2402 ----------------------
2403 -- Star_Suppression --
2404 ----------------------
2406 procedure Star_Suppression is
2407 begin
2408 Debug_Start ("Star_Suppression");
2409 Pic.Floater := '*';
2410 Pic.Start_Float := Index;
2411 Pic.End_Float := Index;
2412 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2413 Set_State (Okay);
2415 -- Even a single * is a valid picture
2417 Pic.Star_Fill := True;
2418 Skip; -- Known *
2420 loop
2421 if At_End then
2422 return;
2423 end if;
2425 case Look is
2427 when '_' | '0' | '/' =>
2428 Pic.End_Float := Index;
2429 Skip;
2431 when 'B' | 'b' =>
2432 Pic.End_Float := Index;
2433 Pic.Picture.Expanded (Index) := 'b';
2434 Skip;
2436 when '*' =>
2437 Pic.End_Float := Index;
2438 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2439 Set_State (Okay); Skip;
2441 when '9' =>
2442 Set_State (Okay);
2443 Number_Completion;
2444 return;
2446 when '.' | 'V' | 'v' =>
2447 Pic.Radix_Position := Index;
2448 Skip;
2449 Number_Fraction_Or_Star_Fill;
2450 return;
2452 when '#' | '$' =>
2453 Trailing_Currency;
2454 Set_State (Okay);
2455 return;
2457 when others => raise Picture_Error;
2458 end case;
2459 end loop;
2460 end Star_Suppression;
2462 ----------------------
2463 -- Trailing_Bracket --
2464 ----------------------
2466 procedure Trailing_Bracket is
2467 begin
2468 Debug_Start ("Trailing_Bracket");
2470 if Look = '>' then
2471 Pic.Second_Sign := Index;
2472 Skip;
2473 else
2474 raise Picture_Error;
2475 end if;
2476 end Trailing_Bracket;
2478 -----------------------
2479 -- Trailing_Currency --
2480 -----------------------
2482 procedure Trailing_Currency is
2483 begin
2484 Debug_Start ("Trailing_Currency");
2486 if At_End then
2487 return;
2488 end if;
2490 if Look = '$' then
2491 Pic.Start_Currency := Index;
2492 Pic.End_Currency := Index;
2493 Skip;
2495 else
2496 while not At_End and then Look = '#' loop
2497 if Pic.Start_Currency = Invalid_Position then
2498 Pic.Start_Currency := Index;
2499 end if;
2501 Pic.End_Currency := Index;
2502 Skip;
2503 end loop;
2504 end if;
2506 loop
2507 if At_End then
2508 return;
2509 end if;
2511 case Look is
2512 when '_' | '0' | '/' => Skip;
2514 when 'B' | 'b' =>
2515 Pic.Picture.Expanded (Index) := 'b';
2516 Skip;
2518 when others => return;
2519 end case;
2520 end loop;
2521 end Trailing_Currency;
2523 ----------------------
2524 -- Zero_Suppression --
2525 ----------------------
2527 procedure Zero_Suppression is
2528 begin
2529 Debug_Start ("Zero_Suppression");
2531 Pic.Floater := 'Z';
2532 Pic.Start_Float := Index;
2533 Pic.End_Float := Index;
2534 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2535 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2537 Skip; -- Known Z
2539 loop
2540 -- Even a single Z is a valid picture
2542 if At_End then
2543 Set_State (Okay);
2544 return;
2545 end if;
2547 case Look is
2548 when '_' | '0' | '/' =>
2549 Pic.End_Float := Index;
2550 Skip;
2552 when 'B' | 'b' =>
2553 Pic.End_Float := Index;
2554 Pic.Picture.Expanded (Index) := 'b';
2555 Skip;
2557 when 'Z' | 'z' =>
2558 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2560 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2561 Pic.End_Float := Index;
2562 Set_State (Okay);
2563 Skip;
2565 when '9' =>
2566 Set_State (Okay);
2567 Number_Completion;
2568 return;
2570 when '.' | 'V' | 'v' =>
2571 Pic.Radix_Position := Index;
2572 Skip;
2573 Number_Fraction_Or_Z_Fill;
2574 return;
2576 when '#' | '$' =>
2577 Trailing_Currency;
2578 Set_State (Okay);
2579 return;
2581 when others =>
2582 return;
2583 end case;
2584 end loop;
2585 end Zero_Suppression;
2587 -- Start of processing for Precalculate
2589 begin
2590 Picture_String;
2592 if Debug then
2593 Ada.Text_IO.New_Line;
2594 Ada.Text_IO.Put (" Picture : """ &
2595 Pic.Picture.Expanded (1 .. Pic.Picture.Length) & """,");
2596 Ada.Text_IO.Put (" Floater : '" & Pic.Floater & "',");
2597 end if;
2599 if State = Reject then
2600 raise Picture_Error;
2601 end if;
2603 Debug_Integer (Pic.Radix_Position, "Radix Positon : ");
2604 Debug_Integer (Pic.Sign_Position, "Sign Positon : ");
2605 Debug_Integer (Pic.Second_Sign, "Second Sign : ");
2606 Debug_Integer (Pic.Start_Float, "Start Float : ");
2607 Debug_Integer (Pic.End_Float, "End Float : ");
2608 Debug_Integer (Pic.Start_Currency, "Start Currency : ");
2609 Debug_Integer (Pic.End_Currency, "End Currency : ");
2610 Debug_Integer (Pic.Max_Leading_Digits, "Max Leading Digits : ");
2611 Debug_Integer (Pic.Max_Trailing_Digits, "Max Trailing Digits : ");
2613 if Debug then
2614 Ada.Text_IO.New_Line;
2615 end if;
2617 exception
2619 when Constraint_Error =>
2621 -- To deal with special cases like null strings.
2623 raise Picture_Error;
2625 end Precalculate;
2627 ----------------
2628 -- To_Picture --
2629 ----------------
2631 function To_Picture
2632 (Pic_String : in String;
2633 Blank_When_Zero : in Boolean := False)
2634 return Picture
2636 Result : Picture;
2638 begin
2639 declare
2640 Item : constant String := Expand (Pic_String);
2642 begin
2643 Result.Contents.Picture := (Item'Length, Item);
2644 Result.Contents.Original_BWZ := Blank_When_Zero;
2645 Result.Contents.Blank_When_Zero := Blank_When_Zero;
2646 Precalculate (Result.Contents);
2647 return Result;
2648 end;
2650 exception
2651 when others =>
2652 raise Picture_Error;
2654 end To_Picture;
2656 -----------
2657 -- Valid --
2658 -----------
2660 function Valid
2661 (Pic_String : in String;
2662 Blank_When_Zero : in Boolean := False)
2663 return Boolean
2665 begin
2666 declare
2667 Expanded_Pic : constant String := Expand (Pic_String);
2668 -- Raises Picture_Error if Item not well-formed
2670 Format_Rec : Format_Record;
2672 begin
2673 Format_Rec.Picture := (Expanded_Pic'Length, Expanded_Pic);
2674 Format_Rec.Blank_When_Zero := Blank_When_Zero;
2675 Format_Rec.Original_BWZ := Blank_When_Zero;
2676 Precalculate (Format_Rec);
2678 -- False only if Blank_When_0 is True but the pic string has a '*'
2680 return not Blank_When_Zero or
2681 Strings_Fixed.Index (Expanded_Pic, "*") = 0;
2682 end;
2684 exception
2685 when others => return False;
2687 end Valid;
2689 --------------------
2690 -- Decimal_Output --
2691 --------------------
2693 package body Decimal_Output is
2695 -----------
2696 -- Image --
2697 -----------
2699 function Image
2700 (Item : in Num;
2701 Pic : in Picture;
2702 Currency : in String := Default_Currency;
2703 Fill : in Character := Default_Fill;
2704 Separator : in Character := Default_Separator;
2705 Radix_Mark : in Character := Default_Radix_Mark)
2706 return String
2708 begin
2709 return Format_Number
2710 (Pic.Contents, Num'Image (Item),
2711 Currency, Fill, Separator, Radix_Mark);
2712 end Image;
2714 ------------
2715 -- Length --
2716 ------------
2718 function Length
2719 (Pic : in Picture;
2720 Currency : in String := Default_Currency)
2721 return Natural
2723 Picstr : constant String := Pic_String (Pic);
2724 V_Adjust : Integer := 0;
2725 Cur_Adjust : Integer := 0;
2727 begin
2728 -- Check if Picstr has 'V' or '$'
2730 -- If 'V', then length is 1 less than otherwise
2732 -- If '$', then length is Currency'Length-1 more than otherwise
2734 -- This should use the string handling package ???
2736 for J in Picstr'Range loop
2737 if Picstr (J) = 'V' then
2738 V_Adjust := -1;
2740 elsif Picstr (J) = '$' then
2741 Cur_Adjust := Currency'Length - 1;
2742 end if;
2743 end loop;
2745 return Picstr'Length - V_Adjust + Cur_Adjust;
2746 end Length;
2748 ---------
2749 -- Put --
2750 ---------
2752 procedure Put
2753 (File : in Text_IO.File_Type;
2754 Item : in Num;
2755 Pic : in Picture;
2756 Currency : in String := Default_Currency;
2757 Fill : in Character := Default_Fill;
2758 Separator : in Character := Default_Separator;
2759 Radix_Mark : in Character := Default_Radix_Mark)
2761 begin
2762 Text_IO.Put (File, Image (Item, Pic,
2763 Currency, Fill, Separator, Radix_Mark));
2764 end Put;
2766 procedure Put
2767 (Item : in Num;
2768 Pic : in Picture;
2769 Currency : in String := Default_Currency;
2770 Fill : in Character := Default_Fill;
2771 Separator : in Character := Default_Separator;
2772 Radix_Mark : in Character := Default_Radix_Mark)
2774 begin
2775 Text_IO.Put (Image (Item, Pic,
2776 Currency, Fill, Separator, Radix_Mark));
2777 end Put;
2779 procedure Put
2780 (To : out String;
2781 Item : in Num;
2782 Pic : in Picture;
2783 Currency : in String := Default_Currency;
2784 Fill : in Character := Default_Fill;
2785 Separator : in Character := Default_Separator;
2786 Radix_Mark : in Character := Default_Radix_Mark)
2788 Result : constant String :=
2789 Image (Item, Pic, Currency, Fill, Separator, Radix_Mark);
2791 begin
2792 if Result'Length > To'Length then
2793 raise Text_IO.Layout_Error;
2794 else
2795 Strings_Fixed.Move (Source => Result, Target => To,
2796 Justify => Strings.Right);
2797 end if;
2798 end Put;
2800 -----------
2801 -- Valid --
2802 -----------
2804 function Valid
2805 (Item : Num;
2806 Pic : in Picture;
2807 Currency : in String := Default_Currency)
2808 return Boolean
2810 begin
2811 declare
2812 Temp : constant String := Image (Item, Pic, Currency);
2813 pragma Warnings (Off, Temp);
2814 begin
2815 return True;
2816 end;
2818 exception
2819 when Layout_Error => return False;
2821 end Valid;
2823 end Decimal_Output;
2825 end Ada.Text_IO.Editing;