(extendsfdf2): Add pattern accidentally deleted when cirrus instructions were
[official-gcc.git] / gcc / ada / a-wtedit.adb
blobb1da5ef3f88c998de0d9a88a017fb18a37519059
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- A D A . W I D E _ T E X T _ I O . E D I T I N G --
6 -- --
7 -- B o d y --
8 -- --
9 -- --
10 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
29 -- --
30 -- GNAT was originally developed by the GNAT team at New York University. --
31 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 -- --
33 ------------------------------------------------------------------------------
35 with Ada.Strings.Fixed;
36 with Ada.Strings.Wide_Fixed;
38 package body Ada.Wide_Text_IO.Editing is
40 package Strings renames Ada.Strings;
41 package Strings_Fixed renames Ada.Strings.Fixed;
42 package Strings_Wide_Fixed renames Ada.Strings.Wide_Fixed;
43 package Wide_Text_IO renames Ada.Wide_Text_IO;
45 -----------------------
46 -- Local_Subprograms --
47 -----------------------
49 function To_Wide (C : Character) return Wide_Character;
50 pragma Inline (To_Wide);
51 -- Convert Character to corresponding Wide_Character
53 ---------------------
54 -- Blank_When_Zero --
55 ---------------------
57 function Blank_When_Zero (Pic : in Picture) return Boolean is
58 begin
59 return Pic.Contents.Original_BWZ;
60 end Blank_When_Zero;
62 --------------------
63 -- Decimal_Output --
64 --------------------
66 package body Decimal_Output is
68 -----------
69 -- Image --
70 -----------
72 function Image
73 (Item : in Num;
74 Pic : in Picture;
75 Currency : in Wide_String := Default_Currency;
76 Fill : in Wide_Character := Default_Fill;
77 Separator : in Wide_Character := Default_Separator;
78 Radix_Mark : in Wide_Character := Default_Radix_Mark)
79 return Wide_String
81 begin
82 return Format_Number
83 (Pic.Contents, Num'Image (Item),
84 Currency, Fill, Separator, Radix_Mark);
85 end Image;
87 ------------
88 -- Length --
89 ------------
91 function Length
92 (Pic : in Picture;
93 Currency : in Wide_String := Default_Currency)
94 return Natural
96 Picstr : constant String := Pic_String (Pic);
97 V_Adjust : Integer := 0;
98 Cur_Adjust : Integer := 0;
100 begin
101 -- Check if Picstr has 'V' or '$'
103 -- If 'V', then length is 1 less than otherwise
105 -- If '$', then length is Currency'Length-1 more than otherwise
107 -- This should use the string handling package ???
109 for J in Picstr'Range loop
110 if Picstr (J) = 'V' then
111 V_Adjust := -1;
113 elsif Picstr (J) = '$' then
114 Cur_Adjust := Currency'Length - 1;
115 end if;
116 end loop;
118 return Picstr'Length - V_Adjust + Cur_Adjust;
119 end Length;
121 ---------
122 -- Put --
123 ---------
125 procedure Put
126 (File : in Wide_Text_IO.File_Type;
127 Item : in Num;
128 Pic : in Picture;
129 Currency : in Wide_String := Default_Currency;
130 Fill : in Wide_Character := Default_Fill;
131 Separator : in Wide_Character := Default_Separator;
132 Radix_Mark : in Wide_Character := Default_Radix_Mark)
134 begin
135 Wide_Text_IO.Put (File, Image (Item, Pic,
136 Currency, Fill, Separator, Radix_Mark));
137 end Put;
139 procedure Put
140 (Item : in Num;
141 Pic : in Picture;
142 Currency : in Wide_String := Default_Currency;
143 Fill : in Wide_Character := Default_Fill;
144 Separator : in Wide_Character := Default_Separator;
145 Radix_Mark : in Wide_Character := Default_Radix_Mark)
147 begin
148 Wide_Text_IO.Put (Image (Item, Pic,
149 Currency, Fill, Separator, Radix_Mark));
150 end Put;
152 procedure Put
153 (To : out Wide_String;
154 Item : in Num;
155 Pic : in Picture;
156 Currency : in Wide_String := Default_Currency;
157 Fill : in Wide_Character := Default_Fill;
158 Separator : in Wide_Character := Default_Separator;
159 Radix_Mark : in Wide_Character := Default_Radix_Mark)
161 Result : constant Wide_String :=
162 Image (Item, Pic, Currency, Fill, Separator, Radix_Mark);
164 begin
165 if Result'Length > To'Length then
166 raise Wide_Text_IO.Layout_Error;
167 else
168 Strings_Wide_Fixed.Move (Source => Result, Target => To,
169 Justify => Strings.Right);
170 end if;
171 end Put;
173 -----------
174 -- Valid --
175 -----------
177 function Valid
178 (Item : Num;
179 Pic : in Picture;
180 Currency : in Wide_String := Default_Currency)
181 return Boolean
183 begin
184 declare
185 Temp : constant Wide_String := Image (Item, Pic, Currency);
186 pragma Warnings (Off, Temp);
188 begin
189 return True;
190 end;
192 exception
193 when Layout_Error => return False;
195 end Valid;
197 end Decimal_Output;
199 ------------
200 -- Expand --
201 ------------
203 function Expand (Picture : in String) return String is
204 Result : String (1 .. MAX_PICSIZE);
205 Picture_Index : Integer := Picture'First;
206 Result_Index : Integer := Result'First;
207 Count : Natural;
208 Last : Integer;
210 begin
211 if Picture'Length < 1 then
212 raise Picture_Error;
213 end if;
215 if Picture (Picture'First) = '(' then
216 raise Picture_Error;
217 end if;
219 loop
220 case Picture (Picture_Index) is
222 when '(' =>
224 -- We now need to scan out the count after a left paren.
225 -- In the non-wide version we used Integer_IO.Get, but
226 -- that is not convenient here, since we don't want to
227 -- drag in normal Text_IO just for this purpose. So we
228 -- do the scan ourselves, with the normal validity checks.
230 Last := Picture_Index + 1;
231 Count := 0;
233 if Picture (Last) not in '0' .. '9' then
234 raise Picture_Error;
235 end if;
237 Count := Character'Pos (Picture (Last)) - Character'Pos ('0');
238 Last := Last + 1;
240 loop
241 if Last > Picture'Last then
242 raise Picture_Error;
243 end if;
245 if Picture (Last) = '_' then
246 if Picture (Last - 1) = '_' then
247 raise Picture_Error;
248 end if;
250 elsif Picture (Last) = ')' then
251 exit;
253 elsif Picture (Last) not in '0' .. '9' then
254 raise Picture_Error;
256 else
257 Count := Count * 10
258 + Character'Pos (Picture (Last)) -
259 Character'Pos ('0');
260 end if;
262 Last := Last + 1;
263 end loop;
265 -- In what follows note that one copy of the repeated
266 -- character has already been made, so a count of one is a
267 -- no-op, and a count of zero erases a character.
269 for J in 2 .. Count loop
270 Result (Result_Index + J - 2) := Picture (Picture_Index - 1);
271 end loop;
273 Result_Index := Result_Index + Count - 1;
275 -- Last was a ')' throw it away too.
277 Picture_Index := Last + 1;
279 when ')' =>
280 raise Picture_Error;
282 when others =>
283 Result (Result_Index) := Picture (Picture_Index);
284 Picture_Index := Picture_Index + 1;
285 Result_Index := Result_Index + 1;
287 end case;
289 exit when Picture_Index > Picture'Last;
290 end loop;
292 return Result (1 .. Result_Index - 1);
294 exception
295 when others =>
296 raise Picture_Error;
298 end Expand;
300 -------------------
301 -- Format_Number --
302 -------------------
304 function Format_Number
305 (Pic : Format_Record;
306 Number : String;
307 Currency_Symbol : Wide_String;
308 Fill_Character : Wide_Character;
309 Separator_Character : Wide_Character;
310 Radix_Point : Wide_Character)
311 return Wide_String
313 Attrs : Number_Attributes := Parse_Number_String (Number);
314 Position : Integer;
315 Rounded : String := Number;
317 Sign_Position : Integer := Pic.Sign_Position; -- may float.
319 Answer : Wide_String (1 .. Pic.Picture.Length);
320 Last : Integer;
321 Currency_Pos : Integer := Pic.Start_Currency;
323 Dollar : Boolean := False;
324 -- Overridden immediately if necessary.
326 Zero : Boolean := True;
327 -- Set to False when a non-zero digit is output.
329 begin
331 -- If the picture has fewer decimal places than the number, the image
332 -- must be rounded according to the usual rules.
334 if Attrs.Has_Fraction then
335 declare
336 R : constant Integer :=
337 (Attrs.End_Of_Fraction - Attrs.Start_Of_Fraction + 1)
338 - Pic.Max_Trailing_Digits;
339 R_Pos : Integer;
341 begin
342 if R > 0 then
343 R_Pos := Rounded'Length - R;
345 if Rounded (R_Pos + 1) > '4' then
347 if Rounded (R_Pos) = '.' then
348 R_Pos := R_Pos - 1;
349 end if;
351 if Rounded (R_Pos) /= '9' then
352 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
353 else
354 Rounded (R_Pos) := '0';
355 R_Pos := R_Pos - 1;
357 while R_Pos > 1 loop
358 if Rounded (R_Pos) = '.' then
359 R_Pos := R_Pos - 1;
360 end if;
362 if Rounded (R_Pos) /= '9' then
363 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
364 exit;
365 else
366 Rounded (R_Pos) := '0';
367 R_Pos := R_Pos - 1;
368 end if;
369 end loop;
371 -- The rounding may add a digit in front. Either the
372 -- leading blank or the sign (already captured) can
373 -- be overwritten.
375 if R_Pos = 1 then
376 Rounded (R_Pos) := '1';
377 Attrs.Start_Of_Int := Attrs.Start_Of_Int - 1;
378 end if;
379 end if;
380 end if;
381 end if;
382 end;
383 end if;
385 for J in Answer'Range loop
386 Answer (J) := To_Wide (Pic.Picture.Expanded (J));
387 end loop;
389 if Pic.Start_Currency /= Invalid_Position then
390 Dollar := Answer (Pic.Start_Currency) = '$';
391 end if;
393 -- Fix up "direct inserts" outside the playing field. Set up as one
394 -- loop to do the beginning, one (reverse) loop to do the end.
396 Last := 1;
397 loop
398 exit when Last = Pic.Start_Float;
399 exit when Last = Pic.Radix_Position;
400 exit when Answer (Last) = '9';
402 case Answer (Last) is
404 when '_' =>
405 Answer (Last) := Separator_Character;
407 when 'b' =>
408 Answer (Last) := ' ';
410 when others =>
411 null;
413 end case;
415 exit when Last = Answer'Last;
417 Last := Last + 1;
418 end loop;
420 -- Now for the end...
422 for J in reverse Last .. Answer'Last loop
423 exit when J = Pic.Radix_Position;
425 -- Do this test First, Separator_Character can equal Pic.Floater.
427 if Answer (J) = Pic.Floater then
428 exit;
429 end if;
431 case Answer (J) is
433 when '_' =>
434 Answer (J) := Separator_Character;
436 when 'b' =>
437 Answer (J) := ' ';
439 when '9' =>
440 exit;
442 when others =>
443 null;
445 end case;
446 end loop;
448 -- Non-floating sign
450 if Pic.Start_Currency /= -1
451 and then Answer (Pic.Start_Currency) = '#'
452 and then Pic.Floater /= '#'
453 then
454 if Currency_Symbol'Length >
455 Pic.End_Currency - Pic.Start_Currency + 1
456 then
457 raise Picture_Error;
459 elsif Currency_Symbol'Length =
460 Pic.End_Currency - Pic.Start_Currency + 1
461 then
462 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
463 Currency_Symbol;
465 elsif Pic.Radix_Position = Invalid_Position
466 or else Pic.Start_Currency < Pic.Radix_Position
467 then
468 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
469 (others => ' ');
470 Answer (Pic.End_Currency - Currency_Symbol'Length + 1 ..
471 Pic.End_Currency) := Currency_Symbol;
473 else
474 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
475 (others => ' ');
476 Answer (Pic.Start_Currency ..
477 Pic.Start_Currency + Currency_Symbol'Length - 1) :=
478 Currency_Symbol;
479 end if;
480 end if;
482 -- Fill in leading digits
484 if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
485 Pic.Max_Leading_Digits
486 then
487 raise Layout_Error;
488 end if;
490 if Pic.Radix_Position = Invalid_Position then
491 Position := Answer'Last;
492 else
493 Position := Pic.Radix_Position - 1;
494 end if;
496 for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop
498 while Answer (Position) /= '9'
499 and Answer (Position) /= Pic.Floater
500 loop
501 if Answer (Position) = '_' then
502 Answer (Position) := Separator_Character;
504 elsif Answer (Position) = 'b' then
505 Answer (Position) := ' ';
506 end if;
508 Position := Position - 1;
509 end loop;
511 Answer (Position) := To_Wide (Rounded (J));
513 if Rounded (J) /= '0' then
514 Zero := False;
515 end if;
517 Position := Position - 1;
518 end loop;
520 -- Do lead float
522 if Pic.Start_Float = Invalid_Position then
524 -- No leading floats, but need to change '9' to '0', '_' to
525 -- Separator_Character and 'b' to ' '.
527 for J in Last .. Position loop
529 -- Last set when fixing the "uninteresting" leaders above.
530 -- Don't duplicate the work.
532 if Answer (J) = '9' then
533 Answer (J) := '0';
535 elsif Answer (J) = '_' then
536 Answer (J) := Separator_Character;
538 elsif Answer (J) = 'b' then
539 Answer (J) := ' ';
541 end if;
543 end loop;
545 elsif Pic.Floater = '<'
546 or else
547 Pic.Floater = '+'
548 or else
549 Pic.Floater = '-'
550 then
551 for J in Pic.End_Float .. Position loop -- May be null range.
552 if Answer (J) = '9' then
553 Answer (J) := '0';
555 elsif Answer (J) = '_' then
556 Answer (J) := Separator_Character;
558 elsif Answer (J) = 'b' then
559 Answer (J) := ' ';
561 end if;
562 end loop;
564 if Position > Pic.End_Float then
565 Position := Pic.End_Float;
566 end if;
568 for J in Pic.Start_Float .. Position - 1 loop
569 Answer (J) := ' ';
570 end loop;
572 Answer (Position) := Pic.Floater;
573 Sign_Position := Position;
575 elsif Pic.Floater = '$' then
577 for J in Pic.End_Float .. Position loop -- May be null range.
578 if Answer (J) = '9' then
579 Answer (J) := '0';
581 elsif Answer (J) = '_' then
582 Answer (J) := ' '; -- no separator before leftmost digit.
584 elsif Answer (J) = 'b' then
585 Answer (J) := ' ';
586 end if;
587 end loop;
589 if Position > Pic.End_Float then
590 Position := Pic.End_Float;
591 end if;
593 for J in Pic.Start_Float .. Position - 1 loop
594 Answer (J) := ' ';
595 end loop;
597 Answer (Position) := Pic.Floater;
598 Currency_Pos := Position;
600 elsif Pic.Floater = '*' then
602 for J in Pic.End_Float .. Position loop -- May be null range.
603 if Answer (J) = '9' then
604 Answer (J) := '0';
606 elsif Answer (J) = '_' then
607 Answer (J) := Separator_Character;
609 elsif Answer (J) = 'b' then
610 Answer (J) := '*';
611 end if;
612 end loop;
614 if Position > Pic.End_Float then
615 Position := Pic.End_Float;
616 end if;
618 for J in Pic.Start_Float .. Position loop
619 Answer (J) := '*';
620 end loop;
622 else
623 if Pic.Floater = '#' then
624 Currency_Pos := Currency_Symbol'Length;
625 end if;
627 for J in reverse Pic.Start_Float .. Position loop
628 case Answer (J) is
630 when '*' =>
631 Answer (J) := Fill_Character;
633 when 'Z' | 'b' | '/' | '0' =>
634 Answer (J) := ' ';
636 when '9' =>
637 Answer (J) := '0';
639 when '.' | 'V' | 'v' | '<' | '$' | '+' | '-' =>
640 null;
642 when '#' =>
643 if Currency_Pos = 0 then
644 Answer (J) := ' ';
645 else
646 Answer (J) := Currency_Symbol (Currency_Pos);
647 Currency_Pos := Currency_Pos - 1;
648 end if;
650 when '_' =>
652 case Pic.Floater is
654 when '*' =>
655 Answer (J) := Fill_Character;
657 when 'Z' | 'b' =>
658 Answer (J) := ' ';
660 when '#' =>
661 if Currency_Pos = 0 then
662 Answer (J) := ' ';
664 else
665 Answer (J) := Currency_Symbol (Currency_Pos);
666 Currency_Pos := Currency_Pos - 1;
667 end if;
669 when others =>
670 null;
672 end case;
674 when others =>
675 null;
677 end case;
678 end loop;
680 if Pic.Floater = '#' and then Currency_Pos /= 0 then
681 raise Layout_Error;
682 end if;
683 end if;
685 -- Do sign
687 if Sign_Position = Invalid_Position then
688 if Attrs.Negative then
689 raise Layout_Error;
690 end if;
692 else
693 if Attrs.Negative then
694 case Answer (Sign_Position) is
695 when 'C' | 'D' | '-' =>
696 null;
698 when '+' =>
699 Answer (Sign_Position) := '-';
701 when '<' =>
702 Answer (Sign_Position) := '(';
703 Answer (Pic.Second_Sign) := ')';
705 when others =>
706 raise Picture_Error;
708 end case;
710 else -- positive
712 case Answer (Sign_Position) is
714 when '-' =>
715 Answer (Sign_Position) := ' ';
717 when '<' | 'C' | 'D' =>
718 Answer (Sign_Position) := ' ';
719 Answer (Pic.Second_Sign) := ' ';
721 when '+' =>
722 null;
724 when others =>
725 raise Picture_Error;
727 end case;
728 end if;
729 end if;
731 -- Fill in trailing digits
733 if Pic.Max_Trailing_Digits > 0 then
735 if Attrs.Has_Fraction then
736 Position := Attrs.Start_Of_Fraction;
737 Last := Pic.Radix_Position + 1;
739 for J in Last .. Answer'Last loop
741 if Answer (J) = '9' or Answer (J) = Pic.Floater then
742 Answer (J) := To_Wide (Rounded (Position));
744 if Rounded (Position) /= '0' then
745 Zero := False;
746 end if;
748 Position := Position + 1;
749 Last := J + 1;
751 -- Used up fraction but remember place in Answer
753 exit when Position > Attrs.End_Of_Fraction;
755 elsif Answer (J) = 'b' then
756 Answer (J) := ' ';
758 elsif Answer (J) = '_' then
759 Answer (J) := Separator_Character;
761 end if;
763 Last := J + 1;
764 end loop;
766 Position := Last;
768 else
769 Position := Pic.Radix_Position + 1;
770 end if;
772 -- Now fill remaining 9's with zeros and _ with separators
774 Last := Answer'Last;
776 for J in Position .. Last loop
777 if Answer (J) = '9' then
778 Answer (J) := '0';
780 elsif Answer (J) = Pic.Floater then
781 Answer (J) := '0';
783 elsif Answer (J) = '_' then
784 Answer (J) := Separator_Character;
786 elsif Answer (J) = 'b' then
787 Answer (J) := ' ';
789 end if;
790 end loop;
792 Position := Last + 1;
794 else
795 if Pic.Floater = '#' and then Currency_Pos /= 0 then
796 raise Layout_Error;
797 end if;
799 -- No trailing digits, but now J may need to stick in a currency
800 -- symbol or sign.
802 if Pic.Start_Currency = Invalid_Position then
803 Position := Answer'Last + 1;
804 else
805 Position := Pic.Start_Currency;
806 end if;
807 end if;
809 for J in Position .. Answer'Last loop
811 if Pic.Start_Currency /= Invalid_Position and then
812 Answer (Pic.Start_Currency) = '#' then
813 Currency_Pos := 1;
814 end if;
816 -- Note: There are some weird cases J can imagine with 'b' or '#'
817 -- in currency strings where the following code will cause
818 -- glitches. The trick is to tell when the character in the
819 -- answer should be checked, and when to look at the original
820 -- string. Some other time. RIE 11/26/96 ???
822 case Answer (J) is
823 when '*' =>
824 Answer (J) := Fill_Character;
826 when 'b' =>
827 Answer (J) := ' ';
829 when '#' =>
830 if Currency_Pos > Currency_Symbol'Length then
831 Answer (J) := ' ';
833 else
834 Answer (J) := Currency_Symbol (Currency_Pos);
835 Currency_Pos := Currency_Pos + 1;
836 end if;
838 when '_' =>
840 case Pic.Floater is
842 when '*' =>
843 Answer (J) := Fill_Character;
845 when 'Z' | 'z' =>
846 Answer (J) := ' ';
848 when '#' =>
849 if Currency_Pos > Currency_Symbol'Length then
850 Answer (J) := ' ';
851 else
852 Answer (J) := Currency_Symbol (Currency_Pos);
853 Currency_Pos := Currency_Pos + 1;
854 end if;
856 when others =>
857 null;
859 end case;
861 when others =>
862 exit;
864 end case;
865 end loop;
867 -- Now get rid of Blank_when_Zero and complete Star fill.
869 if Zero and Pic.Blank_When_Zero then
871 -- Value is zero, and blank it.
873 Last := Answer'Last;
875 if Dollar then
876 Last := Last - 1 + Currency_Symbol'Length;
877 end if;
879 if Pic.Radix_Position /= Invalid_Position and then
880 Answer (Pic.Radix_Position) = 'V' then
881 Last := Last - 1;
882 end if;
884 return Wide_String'(1 .. Last => ' ');
886 elsif Zero and Pic.Star_Fill then
887 Last := Answer'Last;
889 if Dollar then
890 Last := Last - 1 + Currency_Symbol'Length;
891 end if;
893 if Pic.Radix_Position /= Invalid_Position then
895 if Answer (Pic.Radix_Position) = 'V' then
896 Last := Last - 1;
898 elsif Dollar then
899 if Pic.Radix_Position > Pic.Start_Currency then
900 return Wide_String' (1 .. Pic.Radix_Position - 1 => '*') &
901 Radix_Point &
902 Wide_String' (Pic.Radix_Position + 1 .. Last => '*');
904 else
905 return
906 Wide_String'
907 (1 ..
908 Pic.Radix_Position + Currency_Symbol'Length - 2
909 => '*') &
910 Radix_Point &
911 Wide_String'
912 (Pic.Radix_Position + Currency_Symbol'Length .. Last
913 => '*');
914 end if;
916 else
917 return
918 Wide_String'(1 .. Pic.Radix_Position - 1 => '*') &
919 Radix_Point &
920 Wide_String'(Pic.Radix_Position + 1 .. Last => '*');
921 end if;
922 end if;
924 return Wide_String' (1 .. Last => '*');
925 end if;
927 -- This was once a simple return statement, now there are nine
928 -- different return cases. Not to mention the five above to deal
929 -- with zeros. Why not split things out?
931 -- Processing the radix and sign expansion separately
932 -- would require lots of copying--the string and some of its
933 -- indices--without really simplifying the logic. The cases are:
935 -- 1) Expand $, replace '.' with Radix_Point
936 -- 2) No currency expansion, replace '.' with Radix_Point
937 -- 3) Expand $, radix blanked
938 -- 4) No currency expansion, radix blanked
939 -- 5) Elide V
940 -- 6) Expand $, Elide V
941 -- 7) Elide V, Expand $ (Two cases depending on order.)
942 -- 8) No radix, expand $
943 -- 9) No radix, no currency expansion
945 if Pic.Radix_Position /= Invalid_Position then
947 if Answer (Pic.Radix_Position) = '.' then
948 Answer (Pic.Radix_Position) := Radix_Point;
950 if Dollar then
952 -- 1) Expand $, replace '.' with Radix_Point
954 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
955 Answer (Currency_Pos + 1 .. Answer'Last);
957 else
958 -- 2) No currency expansion, replace '.' with Radix_Point
960 return Answer;
961 end if;
963 elsif Answer (Pic.Radix_Position) = ' ' then -- blanked radix.
964 if Dollar then
966 -- 3) Expand $, radix blanked
968 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
969 Answer (Currency_Pos + 1 .. Answer'Last);
971 else
972 -- 4) No expansion, radix blanked
974 return Answer;
975 end if;
977 -- V cases
979 else
980 if not Dollar then
982 -- 5) Elide V
984 return Answer (1 .. Pic.Radix_Position - 1) &
985 Answer (Pic.Radix_Position + 1 .. Answer'Last);
987 elsif Currency_Pos < Pic.Radix_Position then
989 -- 6) Expand $, Elide V
991 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
992 Answer (Currency_Pos + 1 .. Pic.Radix_Position - 1) &
993 Answer (Pic.Radix_Position + 1 .. Answer'Last);
995 else
996 -- 7) Elide V, Expand $
998 return Answer (1 .. Pic.Radix_Position - 1) &
999 Answer (Pic.Radix_Position + 1 .. Currency_Pos - 1) &
1000 Currency_Symbol &
1001 Answer (Currency_Pos + 1 .. Answer'Last);
1002 end if;
1003 end if;
1005 elsif Dollar then
1007 -- 8) No radix, expand $
1009 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
1010 Answer (Currency_Pos + 1 .. Answer'Last);
1012 else
1013 -- 9) No radix, no currency expansion
1015 return Answer;
1016 end if;
1018 end Format_Number;
1020 -------------------------
1021 -- Parse_Number_String --
1022 -------------------------
1024 function Parse_Number_String (Str : String) return Number_Attributes is
1025 Answer : Number_Attributes;
1027 begin
1028 for J in Str'Range loop
1029 case Str (J) is
1031 when ' ' =>
1032 null; -- ignore
1034 when '1' .. '9' =>
1036 -- Decide if this is the start of a number.
1037 -- If so, figure out which one...
1039 if Answer.Has_Fraction then
1040 Answer.End_Of_Fraction := J;
1041 else
1042 if Answer.Start_Of_Int = Invalid_Position then
1043 -- start integer
1044 Answer.Start_Of_Int := J;
1045 end if;
1046 Answer.End_Of_Int := J;
1047 end if;
1049 when '0' =>
1051 -- Only count a zero before the decimal point if it follows a
1052 -- non-zero digit. After the decimal point, zeros will be
1053 -- counted if followed by a non-zero digit.
1055 if not Answer.Has_Fraction then
1056 if Answer.Start_Of_Int /= Invalid_Position then
1057 Answer.End_Of_Int := J;
1058 end if;
1059 end if;
1061 when '-' =>
1063 -- Set negative
1065 Answer.Negative := True;
1067 when '.' =>
1069 -- Close integer, start fraction
1071 if Answer.Has_Fraction then
1072 raise Picture_Error;
1073 end if;
1075 -- Two decimal points is a no-no.
1077 Answer.Has_Fraction := True;
1078 Answer.End_Of_Fraction := J;
1080 -- Could leave this at Invalid_Position, but this seems the
1081 -- right way to indicate a null range...
1083 Answer.Start_Of_Fraction := J + 1;
1084 Answer.End_Of_Int := J - 1;
1086 when others =>
1087 raise Picture_Error; -- can this happen? probably not!
1088 end case;
1089 end loop;
1091 if Answer.Start_Of_Int = Invalid_Position then
1092 Answer.Start_Of_Int := Answer.End_Of_Int + 1;
1093 end if;
1095 -- No significant (intger) digits needs a null range.
1097 return Answer;
1099 end Parse_Number_String;
1101 ----------------
1102 -- Pic_String --
1103 ----------------
1105 -- The following ensures that we return B and not b being careful not
1106 -- to break things which expect lower case b for blank. See CXF3A02.
1108 function Pic_String (Pic : in Picture) return String is
1109 Temp : String (1 .. Pic.Contents.Picture.Length) :=
1110 Pic.Contents.Picture.Expanded;
1111 begin
1112 for J in Temp'Range loop
1113 if Temp (J) = 'b' then Temp (J) := 'B'; end if;
1114 end loop;
1116 return Temp;
1117 end Pic_String;
1119 ------------------
1120 -- Precalculate --
1121 ------------------
1123 procedure Precalculate (Pic : in out Format_Record) is
1125 Computed_BWZ : Boolean := True;
1127 type Legality is (Okay, Reject);
1128 State : Legality := Reject;
1129 -- Start in reject, which will reject null strings.
1131 Index : Pic_Index := Pic.Picture.Expanded'First;
1133 function At_End return Boolean;
1134 pragma Inline (At_End);
1136 procedure Set_State (L : Legality);
1137 pragma Inline (Set_State);
1139 function Look return Character;
1140 pragma Inline (Look);
1142 function Is_Insert return Boolean;
1143 pragma Inline (Is_Insert);
1145 procedure Skip;
1146 pragma Inline (Skip);
1148 procedure Trailing_Currency;
1149 procedure Trailing_Bracket;
1150 procedure Number_Fraction;
1151 procedure Number_Completion;
1152 procedure Number_Fraction_Or_Bracket;
1153 procedure Number_Fraction_Or_Z_Fill;
1154 procedure Zero_Suppression;
1155 procedure Floating_Bracket;
1156 procedure Number_Fraction_Or_Star_Fill;
1157 procedure Star_Suppression;
1158 procedure Number_Fraction_Or_Dollar;
1159 procedure Leading_Dollar;
1160 procedure Number_Fraction_Or_Pound;
1161 procedure Leading_Pound;
1162 procedure Picture;
1163 procedure Floating_Plus;
1164 procedure Floating_Minus;
1165 procedure Picture_Plus;
1166 procedure Picture_Minus;
1167 procedure Picture_Bracket;
1168 procedure Number;
1169 procedure Optional_RHS_Sign;
1170 procedure Picture_String;
1172 ------------
1173 -- At_End --
1174 ------------
1176 function At_End return Boolean is
1177 begin
1178 return Index > Pic.Picture.Length;
1179 end At_End;
1181 ----------------------
1182 -- Floating_Bracket --
1183 ----------------------
1185 -- Note that Floating_Bracket is only called with an acceptable
1186 -- prefix. But we don't set Okay, because we must end with a '>'.
1188 procedure Floating_Bracket is
1189 begin
1190 Pic.Floater := '<';
1191 Pic.End_Float := Index;
1192 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1194 -- First bracket wasn't counted...
1196 Skip; -- known '<'
1198 loop
1199 if At_End then
1200 return;
1201 end if;
1203 case Look is
1205 when '_' | '0' | '/' =>
1206 Pic.End_Float := Index;
1207 Skip;
1209 when 'B' | 'b' =>
1210 Pic.End_Float := Index;
1211 Pic.Picture.Expanded (Index) := 'b';
1212 Skip;
1214 when '<' =>
1215 Pic.End_Float := Index;
1216 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1217 Skip;
1219 when '9' =>
1220 Number_Completion;
1222 when '$' =>
1223 Leading_Dollar;
1225 when '#' =>
1226 Leading_Pound;
1228 when 'V' | 'v' | '.' =>
1229 Pic.Radix_Position := Index;
1230 Skip;
1231 Number_Fraction_Or_Bracket;
1232 return;
1234 when others =>
1235 return;
1236 end case;
1237 end loop;
1238 end Floating_Bracket;
1240 --------------------
1241 -- Floating_Minus --
1242 --------------------
1244 procedure Floating_Minus is
1245 begin
1246 loop
1247 if At_End then
1248 return;
1249 end if;
1251 case Look is
1252 when '_' | '0' | '/' =>
1253 Pic.End_Float := Index;
1254 Skip;
1256 when 'B' | 'b' =>
1257 Pic.End_Float := Index;
1258 Pic.Picture.Expanded (Index) := 'b';
1259 Skip;
1261 when '-' =>
1262 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1263 Pic.End_Float := Index;
1264 Skip;
1266 when '9' =>
1267 Number_Completion;
1268 return;
1270 when '.' | 'V' | 'v' =>
1271 Pic.Radix_Position := Index;
1272 Skip; -- Radix
1274 while Is_Insert loop
1275 Skip;
1276 end loop;
1278 if At_End then
1279 return;
1280 end if;
1282 if Look = '-' then
1283 loop
1284 if At_End then
1285 return;
1286 end if;
1288 case Look is
1290 when '-' =>
1291 Pic.Max_Trailing_Digits :=
1292 Pic.Max_Trailing_Digits + 1;
1293 Pic.End_Float := Index;
1294 Skip;
1296 when '_' | '0' | '/' =>
1297 Skip;
1299 when 'B' | 'b' =>
1300 Pic.Picture.Expanded (Index) := 'b';
1301 Skip;
1303 when others =>
1304 return;
1306 end case;
1307 end loop;
1309 else
1310 Number_Completion;
1311 end if;
1313 return;
1315 when others =>
1316 return;
1317 end case;
1318 end loop;
1319 end Floating_Minus;
1321 -------------------
1322 -- Floating_Plus --
1323 -------------------
1325 procedure Floating_Plus is
1326 begin
1327 loop
1328 if At_End then
1329 return;
1330 end if;
1332 case Look is
1333 when '_' | '0' | '/' =>
1334 Pic.End_Float := Index;
1335 Skip;
1337 when 'B' | 'b' =>
1338 Pic.End_Float := Index;
1339 Pic.Picture.Expanded (Index) := 'b';
1340 Skip;
1342 when '+' =>
1343 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1344 Pic.End_Float := Index;
1345 Skip;
1347 when '9' =>
1348 Number_Completion;
1349 return;
1351 when '.' | 'V' | 'v' =>
1352 Pic.Radix_Position := Index;
1353 Skip; -- Radix
1355 while Is_Insert loop
1356 Skip;
1357 end loop;
1359 if At_End then
1360 return;
1361 end if;
1363 if Look = '+' then
1364 loop
1365 if At_End then
1366 return;
1367 end if;
1369 case Look is
1371 when '+' =>
1372 Pic.Max_Trailing_Digits :=
1373 Pic.Max_Trailing_Digits + 1;
1374 Pic.End_Float := Index;
1375 Skip;
1377 when '_' | '0' | '/' =>
1378 Skip;
1380 when 'B' | 'b' =>
1381 Pic.Picture.Expanded (Index) := 'b';
1382 Skip;
1384 when others =>
1385 return;
1387 end case;
1388 end loop;
1390 else
1391 Number_Completion;
1392 end if;
1394 return;
1396 when others =>
1397 return;
1399 end case;
1400 end loop;
1401 end Floating_Plus;
1403 ---------------
1404 -- Is_Insert --
1405 ---------------
1407 function Is_Insert return Boolean is
1408 begin
1409 if At_End then
1410 return False;
1411 end if;
1413 case Pic.Picture.Expanded (Index) is
1415 when '_' | '0' | '/' => return True;
1417 when 'B' | 'b' =>
1418 Pic.Picture.Expanded (Index) := 'b'; -- canonical
1419 return True;
1421 when others => return False;
1422 end case;
1423 end Is_Insert;
1425 --------------------
1426 -- Leading_Dollar --
1427 --------------------
1429 -- Note that Leading_Dollar can be called in either State.
1430 -- It will set state to Okay only if a 9 or (second) $
1431 -- is encountered.
1433 -- Also notice the tricky bit with State and Zero_Suppression.
1434 -- Zero_Suppression is Picture_Error if a '$' or a '9' has been
1435 -- encountered, exactly the cases where State has been set.
1437 procedure Leading_Dollar is
1438 begin
1439 -- Treat as a floating dollar, and unwind otherwise.
1441 Pic.Floater := '$';
1442 Pic.Start_Currency := Index;
1443 Pic.End_Currency := Index;
1444 Pic.Start_Float := Index;
1445 Pic.End_Float := Index;
1447 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1448 -- currency place.
1450 Skip; -- known '$'
1452 loop
1453 if At_End then
1454 return;
1455 end if;
1457 case Look is
1459 when '_' | '0' | '/' =>
1460 Pic.End_Float := Index;
1461 Skip;
1463 -- A trailing insertion character is not part of the
1464 -- floating currency, so need to look ahead.
1466 if Look /= '$' then
1467 Pic.End_Float := Pic.End_Float - 1;
1468 end if;
1470 when 'B' | 'b' =>
1471 Pic.End_Float := Index;
1472 Pic.Picture.Expanded (Index) := 'b';
1473 Skip;
1475 when 'Z' | 'z' =>
1476 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1478 if State = Okay then
1479 raise Picture_Error;
1480 else
1481 -- Will overwrite Floater and Start_Float
1483 Zero_Suppression;
1484 end if;
1486 when '*' =>
1487 if State = Okay then
1488 raise Picture_Error;
1489 else
1490 -- Will overwrite Floater and Start_Float
1492 Star_Suppression;
1493 end if;
1495 when '$' =>
1496 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1497 Pic.End_Float := Index;
1498 Pic.End_Currency := Index;
1499 Set_State (Okay); Skip;
1501 when '9' =>
1502 if State /= Okay then
1503 Pic.Floater := '!';
1504 Pic.Start_Float := Invalid_Position;
1505 Pic.End_Float := Invalid_Position;
1506 end if;
1508 -- A single dollar does not a floating make.
1510 Number_Completion;
1511 return;
1513 when 'V' | 'v' | '.' =>
1514 if State /= Okay then
1515 Pic.Floater := '!';
1516 Pic.Start_Float := Invalid_Position;
1517 Pic.End_Float := Invalid_Position;
1518 end if;
1520 -- Only one dollar before the sign is okay,
1521 -- but doesn't float.
1523 Pic.Radix_Position := Index;
1524 Skip;
1525 Number_Fraction_Or_Dollar;
1526 return;
1528 when others =>
1529 return;
1531 end case;
1532 end loop;
1533 end Leading_Dollar;
1535 -------------------
1536 -- Leading_Pound --
1537 -------------------
1539 -- This one is complex! A Leading_Pound can be fixed or floating,
1540 -- but in some cases the decision has to be deferred until we leave
1541 -- this procedure. Also note that Leading_Pound can be called in
1542 -- either State.
1544 -- It will set state to Okay only if a 9 or (second) # is
1545 -- encountered.
1547 -- One Last note: In ambiguous cases, the currency is treated as
1548 -- floating unless there is only one '#'.
1550 procedure Leading_Pound is
1552 Inserts : Boolean := False;
1553 -- Set to True if a '_', '0', '/', 'B', or 'b' is encountered
1555 Must_Float : Boolean := False;
1556 -- Set to true if a '#' occurs after an insert.
1558 begin
1559 -- Treat as a floating currency. If it isn't, this will be
1560 -- overwritten later.
1562 Pic.Floater := '#';
1564 Pic.Start_Currency := Index;
1565 Pic.End_Currency := Index;
1566 Pic.Start_Float := Index;
1567 Pic.End_Float := Index;
1569 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1570 -- currency place.
1572 Pic.Max_Currency_Digits := 1; -- we've seen one.
1574 Skip; -- known '#'
1576 loop
1577 if At_End then
1578 return;
1579 end if;
1581 case Look is
1583 when '_' | '0' | '/' =>
1584 Pic.End_Float := Index;
1585 Inserts := True;
1586 Skip;
1588 when 'B' | 'b' =>
1589 Pic.Picture.Expanded (Index) := 'b';
1590 Pic.End_Float := Index;
1591 Inserts := True;
1592 Skip;
1594 when 'Z' | 'z' =>
1595 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1597 if Must_Float then
1598 raise Picture_Error;
1599 else
1600 Pic.Max_Leading_Digits := 0;
1602 -- Will overwrite Floater and Start_Float
1604 Zero_Suppression;
1605 end if;
1607 when '*' =>
1608 if Must_Float then
1609 raise Picture_Error;
1610 else
1611 Pic.Max_Leading_Digits := 0;
1613 -- Will overwrite Floater and Start_Float
1615 Star_Suppression;
1616 end if;
1618 when '#' =>
1619 if Inserts then
1620 Must_Float := True;
1621 end if;
1623 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1624 Pic.End_Float := Index;
1625 Pic.End_Currency := Index;
1626 Set_State (Okay);
1627 Skip;
1629 when '9' =>
1630 if State /= Okay then
1632 -- A single '#' doesn't float.
1634 Pic.Floater := '!';
1635 Pic.Start_Float := Invalid_Position;
1636 Pic.End_Float := Invalid_Position;
1637 end if;
1639 Number_Completion;
1640 return;
1642 when 'V' | 'v' | '.' =>
1643 if State /= Okay then
1644 Pic.Floater := '!';
1645 Pic.Start_Float := Invalid_Position;
1646 Pic.End_Float := Invalid_Position;
1647 end if;
1649 -- Only one pound before the sign is okay,
1650 -- but doesn't float.
1652 Pic.Radix_Position := Index;
1653 Skip;
1654 Number_Fraction_Or_Pound;
1655 return;
1657 when others =>
1658 return;
1659 end case;
1660 end loop;
1661 end Leading_Pound;
1663 ----------
1664 -- Look --
1665 ----------
1667 function Look return Character is
1668 begin
1669 if At_End then
1670 raise Picture_Error;
1671 end if;
1673 return Pic.Picture.Expanded (Index);
1674 end Look;
1676 ------------
1677 -- Number --
1678 ------------
1680 procedure Number is
1681 begin
1682 loop
1684 case Look is
1685 when '_' | '0' | '/' =>
1686 Skip;
1688 when 'B' | 'b' =>
1689 Pic.Picture.Expanded (Index) := 'b';
1690 Skip;
1692 when '9' =>
1693 Computed_BWZ := False;
1694 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1695 Set_State (Okay);
1696 Skip;
1698 when '.' | 'V' | 'v' =>
1699 Pic.Radix_Position := Index;
1700 Skip;
1701 Number_Fraction;
1702 return;
1704 when others =>
1705 return;
1707 end case;
1709 if At_End then
1710 return;
1711 end if;
1713 -- Will return in Okay state if a '9' was seen.
1715 end loop;
1716 end Number;
1718 -----------------------
1719 -- Number_Completion --
1720 -----------------------
1722 procedure Number_Completion is
1723 begin
1724 while not At_End loop
1725 case Look is
1727 when '_' | '0' | '/' =>
1728 Skip;
1730 when 'B' | 'b' =>
1731 Pic.Picture.Expanded (Index) := 'b';
1732 Skip;
1734 when '9' =>
1735 Computed_BWZ := False;
1736 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1737 Set_State (Okay);
1738 Skip;
1740 when 'V' | 'v' | '.' =>
1741 Pic.Radix_Position := Index;
1742 Skip;
1743 Number_Fraction;
1744 return;
1746 when others =>
1747 return;
1748 end case;
1749 end loop;
1750 end Number_Completion;
1752 ---------------------
1753 -- Number_Fraction --
1754 ---------------------
1756 procedure Number_Fraction is
1757 begin
1758 -- Note that number fraction can be called in either State.
1759 -- It will set state to Valid only if a 9 is encountered.
1761 loop
1762 if At_End then
1763 return;
1764 end if;
1766 case Look is
1767 when '_' | '0' | '/' =>
1768 Skip;
1770 when 'B' | 'b' =>
1771 Pic.Picture.Expanded (Index) := 'b';
1772 Skip;
1774 when '9' =>
1775 Computed_BWZ := False;
1776 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1777 Set_State (Okay); Skip;
1779 when others =>
1780 return;
1781 end case;
1782 end loop;
1783 end Number_Fraction;
1785 --------------------------------
1786 -- Number_Fraction_Or_Bracket --
1787 --------------------------------
1789 procedure Number_Fraction_Or_Bracket is
1790 begin
1791 loop
1792 if At_End then
1793 return;
1794 end if;
1796 case Look is
1798 when '_' | '0' | '/' => Skip;
1800 when 'B' | 'b' =>
1801 Pic.Picture.Expanded (Index) := 'b';
1802 Skip;
1804 when '<' =>
1805 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1806 Pic.End_Float := Index;
1807 Skip;
1809 loop
1810 if At_End then
1811 return;
1812 end if;
1814 case Look is
1815 when '_' | '0' | '/' =>
1816 Skip;
1818 when 'B' | 'b' =>
1819 Pic.Picture.Expanded (Index) := 'b';
1820 Skip;
1822 when '<' =>
1823 Pic.Max_Trailing_Digits :=
1824 Pic.Max_Trailing_Digits + 1;
1825 Pic.End_Float := Index;
1826 Skip;
1828 when others =>
1829 return;
1830 end case;
1831 end loop;
1833 when others =>
1834 Number_Fraction;
1835 return;
1836 end case;
1837 end loop;
1838 end Number_Fraction_Or_Bracket;
1840 -------------------------------
1841 -- Number_Fraction_Or_Dollar --
1842 -------------------------------
1844 procedure Number_Fraction_Or_Dollar is
1845 begin
1846 loop
1847 if At_End then
1848 return;
1849 end if;
1851 case Look is
1852 when '_' | '0' | '/' =>
1853 Skip;
1855 when 'B' | 'b' =>
1856 Pic.Picture.Expanded (Index) := 'b';
1857 Skip;
1859 when '$' =>
1860 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1861 Pic.End_Float := Index;
1862 Skip;
1864 loop
1865 if At_End then
1866 return;
1867 end if;
1869 case Look is
1870 when '_' | '0' | '/' =>
1871 Skip;
1873 when 'B' | 'b' =>
1874 Pic.Picture.Expanded (Index) := 'b';
1875 Skip;
1877 when '$' =>
1878 Pic.Max_Trailing_Digits :=
1879 Pic.Max_Trailing_Digits + 1;
1880 Pic.End_Float := Index;
1881 Skip;
1883 when others =>
1884 return;
1885 end case;
1886 end loop;
1888 when others =>
1889 Number_Fraction;
1890 return;
1891 end case;
1892 end loop;
1893 end Number_Fraction_Or_Dollar;
1895 ------------------------------
1896 -- Number_Fraction_Or_Pound --
1897 ------------------------------
1899 procedure Number_Fraction_Or_Pound is
1900 begin
1901 loop
1902 if At_End then
1903 return;
1904 end if;
1906 case Look is
1908 when '_' | '0' | '/' =>
1909 Skip;
1911 when 'B' | 'b' =>
1912 Pic.Picture.Expanded (Index) := 'b';
1913 Skip;
1915 when '#' =>
1916 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1917 Pic.End_Float := Index;
1918 Skip;
1920 loop
1921 if At_End then
1922 return;
1923 end if;
1925 case Look is
1927 when '_' | '0' | '/' =>
1928 Skip;
1930 when 'B' | 'b' =>
1931 Pic.Picture.Expanded (Index) := 'b';
1932 Skip;
1934 when '#' =>
1935 Pic.Max_Trailing_Digits :=
1936 Pic.Max_Trailing_Digits + 1;
1937 Pic.End_Float := Index;
1938 Skip;
1940 when others =>
1941 return;
1943 end case;
1944 end loop;
1946 when others =>
1947 Number_Fraction;
1948 return;
1950 end case;
1951 end loop;
1952 end Number_Fraction_Or_Pound;
1954 ----------------------------------
1955 -- Number_Fraction_Or_Star_Fill --
1956 ----------------------------------
1958 procedure Number_Fraction_Or_Star_Fill is
1959 begin
1960 loop
1961 if At_End then
1962 return;
1963 end if;
1965 case Look is
1967 when '_' | '0' | '/' =>
1968 Skip;
1970 when 'B' | 'b' =>
1971 Pic.Picture.Expanded (Index) := 'b';
1972 Skip;
1974 when '*' =>
1975 Pic.Star_Fill := True;
1976 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1977 Pic.End_Float := Index;
1978 Skip;
1980 loop
1981 if At_End then
1982 return;
1983 end if;
1985 case Look is
1987 when '_' | '0' | '/' =>
1988 Skip;
1990 when 'B' | 'b' =>
1991 Pic.Picture.Expanded (Index) := 'b';
1992 Skip;
1994 when '*' =>
1995 Pic.Star_Fill := True;
1996 Pic.Max_Trailing_Digits :=
1997 Pic.Max_Trailing_Digits + 1;
1998 Pic.End_Float := Index;
1999 Skip;
2001 when others =>
2002 return;
2003 end case;
2004 end loop;
2006 when others =>
2007 Number_Fraction;
2008 return;
2010 end case;
2011 end loop;
2012 end Number_Fraction_Or_Star_Fill;
2014 -------------------------------
2015 -- Number_Fraction_Or_Z_Fill --
2016 -------------------------------
2018 procedure Number_Fraction_Or_Z_Fill is
2019 begin
2020 loop
2021 if At_End then
2022 return;
2023 end if;
2025 case Look is
2027 when '_' | '0' | '/' =>
2028 Skip;
2030 when 'B' | 'b' =>
2031 Pic.Picture.Expanded (Index) := 'b';
2032 Skip;
2034 when 'Z' | 'z' =>
2035 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
2036 Pic.End_Float := Index;
2037 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2039 Skip;
2041 loop
2042 if At_End then
2043 return;
2044 end if;
2046 case Look is
2048 when '_' | '0' | '/' =>
2049 Skip;
2051 when 'B' | 'b' =>
2052 Pic.Picture.Expanded (Index) := 'b';
2053 Skip;
2055 when 'Z' | 'z' =>
2056 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2058 Pic.Max_Trailing_Digits :=
2059 Pic.Max_Trailing_Digits + 1;
2060 Pic.End_Float := Index;
2061 Skip;
2063 when others =>
2064 return;
2065 end case;
2066 end loop;
2068 when others =>
2069 Number_Fraction;
2070 return;
2071 end case;
2072 end loop;
2073 end Number_Fraction_Or_Z_Fill;
2075 -----------------------
2076 -- Optional_RHS_Sign --
2077 -----------------------
2079 procedure Optional_RHS_Sign is
2080 begin
2081 if At_End then
2082 return;
2083 end if;
2085 case Look is
2087 when '+' | '-' =>
2088 Pic.Sign_Position := Index;
2089 Skip;
2090 return;
2092 when 'C' | 'c' =>
2093 Pic.Sign_Position := Index;
2094 Pic.Picture.Expanded (Index) := 'C';
2095 Skip;
2097 if Look = 'R' or Look = 'r' then
2098 Pic.Second_Sign := Index;
2099 Pic.Picture.Expanded (Index) := 'R';
2100 Skip;
2102 else
2103 raise Picture_Error;
2104 end if;
2106 return;
2108 when 'D' | 'd' =>
2109 Pic.Sign_Position := Index;
2110 Pic.Picture.Expanded (Index) := 'D';
2111 Skip;
2113 if Look = 'B' or Look = 'b' then
2114 Pic.Second_Sign := Index;
2115 Pic.Picture.Expanded (Index) := 'B';
2116 Skip;
2118 else
2119 raise Picture_Error;
2120 end if;
2122 return;
2124 when '>' =>
2125 if Pic.Picture.Expanded (Pic.Sign_Position) = '<' then
2126 Pic.Second_Sign := Index;
2127 Skip;
2129 else
2130 raise Picture_Error;
2131 end if;
2133 when others =>
2134 return;
2136 end case;
2137 end Optional_RHS_Sign;
2139 -------------
2140 -- Picture --
2141 -------------
2143 -- Note that Picture can be called in either State.
2145 -- It will set state to Valid only if a 9 is encountered or floating
2146 -- currency is called.
2148 procedure Picture is
2149 begin
2150 loop
2151 if At_End then
2152 return;
2153 end if;
2155 case Look is
2157 when '_' | '0' | '/' =>
2158 Skip;
2160 when 'B' | 'b' =>
2161 Pic.Picture.Expanded (Index) := 'b';
2162 Skip;
2164 when '$' =>
2165 Leading_Dollar;
2166 return;
2168 when '#' =>
2169 Leading_Pound;
2170 return;
2172 when '9' =>
2173 Computed_BWZ := False;
2174 Set_State (Okay);
2175 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2176 Skip;
2178 when 'V' | 'v' | '.' =>
2179 Pic.Radix_Position := Index;
2180 Skip;
2181 Number_Fraction;
2182 Trailing_Currency;
2183 return;
2185 when others =>
2186 return;
2188 end case;
2189 end loop;
2190 end Picture;
2192 ---------------------
2193 -- Picture_Bracket --
2194 ---------------------
2196 procedure Picture_Bracket is
2197 begin
2198 Pic.Sign_Position := Index;
2199 Pic.Sign_Position := Index;
2201 -- Treat as a floating sign, and unwind otherwise.
2203 Pic.Floater := '<';
2204 Pic.Start_Float := Index;
2205 Pic.End_Float := Index;
2207 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2208 -- sign place.
2210 Skip; -- Known Bracket
2212 loop
2213 case Look is
2215 when '_' | '0' | '/' =>
2216 Pic.End_Float := Index;
2217 Skip;
2219 when 'B' | 'b' =>
2220 Pic.End_Float := Index;
2221 Pic.Picture.Expanded (Index) := 'b';
2222 Skip;
2224 when '<' =>
2225 Set_State (Okay); -- "<<>" is enough.
2226 Floating_Bracket;
2227 Trailing_Currency;
2228 Trailing_Bracket;
2229 return;
2231 when '$' | '#' | '9' | '*' =>
2232 if State /= Okay then
2233 Pic.Floater := '!';
2234 Pic.Start_Float := Invalid_Position;
2235 Pic.End_Float := Invalid_Position;
2236 end if;
2238 Picture;
2239 Trailing_Bracket;
2240 Set_State (Okay);
2241 return;
2243 when '.' | 'V' | 'v' =>
2244 if State /= Okay then
2245 Pic.Floater := '!';
2246 Pic.Start_Float := Invalid_Position;
2247 Pic.End_Float := Invalid_Position;
2248 end if;
2250 -- Don't assume that state is okay, haven't seen a digit
2252 Picture;
2253 Trailing_Bracket;
2254 return;
2256 when others =>
2257 raise Picture_Error;
2259 end case;
2260 end loop;
2261 end Picture_Bracket;
2263 -------------------
2264 -- Picture_Minus --
2265 -------------------
2267 procedure Picture_Minus is
2268 begin
2269 Pic.Sign_Position := Index;
2271 -- Treat as a floating sign, and unwind otherwise.
2273 Pic.Floater := '-';
2274 Pic.Start_Float := Index;
2275 Pic.End_Float := Index;
2277 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2278 -- sign place.
2280 Skip; -- Known Minus
2282 loop
2283 case Look is
2285 when '_' | '0' | '/' =>
2286 Pic.End_Float := Index;
2287 Skip;
2289 when 'B' | 'b' =>
2290 Pic.End_Float := Index;
2291 Pic.Picture.Expanded (Index) := 'b';
2292 Skip;
2294 when '-' =>
2295 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2296 Pic.End_Float := Index;
2297 Skip;
2298 Set_State (Okay); -- "-- " is enough.
2299 Floating_Minus;
2300 Trailing_Currency;
2301 return;
2303 when '$' | '#' | '9' | '*' =>
2304 if State /= Okay then
2305 Pic.Floater := '!';
2306 Pic.Start_Float := Invalid_Position;
2307 Pic.End_Float := Invalid_Position;
2308 end if;
2310 Picture;
2311 Set_State (Okay);
2312 return;
2314 when 'Z' | 'z' =>
2316 -- Can't have Z and a floating sign.
2318 if State = Okay then
2319 Set_State (Reject);
2320 end if;
2322 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2323 Zero_Suppression;
2324 Trailing_Currency;
2325 Optional_RHS_Sign;
2326 return;
2328 when '.' | 'V' | 'v' =>
2329 if State /= Okay then
2330 Pic.Floater := '!';
2331 Pic.Start_Float := Invalid_Position;
2332 Pic.End_Float := Invalid_Position;
2333 end if;
2335 -- Don't assume that state is okay, haven't seen a digit.
2337 Picture;
2338 return;
2340 when others =>
2341 return;
2343 end case;
2344 end loop;
2345 end Picture_Minus;
2347 ------------------
2348 -- Picture_Plus --
2349 ------------------
2351 procedure Picture_Plus is
2352 begin
2353 Pic.Sign_Position := Index;
2355 -- Treat as a floating sign, and unwind otherwise.
2357 Pic.Floater := '+';
2358 Pic.Start_Float := Index;
2359 Pic.End_Float := Index;
2361 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2362 -- sign place.
2364 Skip; -- Known Plus
2366 loop
2367 case Look is
2369 when '_' | '0' | '/' =>
2370 Pic.End_Float := Index;
2371 Skip;
2373 when 'B' | 'b' =>
2374 Pic.End_Float := Index;
2375 Pic.Picture.Expanded (Index) := 'b';
2376 Skip;
2378 when '+' =>
2379 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2380 Pic.End_Float := Index;
2381 Skip;
2382 Set_State (Okay); -- "++" is enough.
2383 Floating_Plus;
2384 Trailing_Currency;
2385 return;
2387 when '$' | '#' | '9' | '*' =>
2388 if State /= Okay then
2389 Pic.Floater := '!';
2390 Pic.Start_Float := Invalid_Position;
2391 Pic.End_Float := Invalid_Position;
2392 end if;
2394 Picture;
2395 Set_State (Okay);
2396 return;
2398 when 'Z' | 'z' =>
2399 if State = Okay then
2400 Set_State (Reject);
2401 end if;
2403 -- Can't have Z and a floating sign.
2405 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2407 -- '+Z' is acceptable
2409 Set_State (Okay);
2411 Zero_Suppression;
2412 Trailing_Currency;
2413 Optional_RHS_Sign;
2414 return;
2416 when '.' | 'V' | 'v' =>
2417 if State /= Okay then
2418 Pic.Floater := '!';
2419 Pic.Start_Float := Invalid_Position;
2420 Pic.End_Float := Invalid_Position;
2421 end if;
2423 -- Don't assume that state is okay, haven't seen a digit.
2425 Picture;
2426 return;
2428 when others =>
2429 return;
2431 end case;
2432 end loop;
2433 end Picture_Plus;
2435 --------------------
2436 -- Picture_String --
2437 --------------------
2439 procedure Picture_String is
2440 begin
2441 while Is_Insert loop
2442 Skip;
2443 end loop;
2445 case Look is
2447 when '$' | '#' =>
2448 Picture;
2449 Optional_RHS_Sign;
2451 when '+' =>
2452 Picture_Plus;
2454 when '-' =>
2455 Picture_Minus;
2457 when '<' =>
2458 Picture_Bracket;
2460 when 'Z' | 'z' =>
2461 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2462 Zero_Suppression;
2463 Trailing_Currency;
2464 Optional_RHS_Sign;
2466 when '*' =>
2467 Star_Suppression;
2468 Trailing_Currency;
2469 Optional_RHS_Sign;
2471 when '9' | '.' | 'V' | 'v' =>
2472 Number;
2473 Trailing_Currency;
2474 Optional_RHS_Sign;
2476 when others =>
2477 raise Picture_Error;
2479 end case;
2481 -- Blank when zero either if the PIC does not contain a '9' or if
2482 -- requested by the user and no '*'
2484 Pic.Blank_When_Zero :=
2485 (Computed_BWZ or Pic.Blank_When_Zero) and not Pic.Star_Fill;
2487 -- Star fill if '*' and no '9'.
2489 Pic.Star_Fill := Pic.Star_Fill and Computed_BWZ;
2491 if not At_End then
2492 Set_State (Reject);
2493 end if;
2495 end Picture_String;
2497 ---------------
2498 -- Set_State --
2499 ---------------
2501 procedure Set_State (L : Legality) is
2502 begin
2503 State := L;
2504 end Set_State;
2506 ----------
2507 -- Skip --
2508 ----------
2510 procedure Skip is
2511 begin
2512 Index := Index + 1;
2513 end Skip;
2515 ----------------------
2516 -- Star_Suppression --
2517 ----------------------
2519 procedure Star_Suppression is
2520 begin
2521 Pic.Floater := '*';
2522 Pic.Start_Float := Index;
2523 Pic.End_Float := Index;
2524 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2525 Set_State (Okay);
2527 -- Even a single * is a valid picture
2529 Pic.Star_Fill := True;
2530 Skip; -- Known *
2532 loop
2533 if At_End then
2534 return;
2535 end if;
2537 case Look is
2539 when '_' | '0' | '/' =>
2540 Pic.End_Float := Index;
2541 Skip;
2543 when 'B' | 'b' =>
2544 Pic.End_Float := Index;
2545 Pic.Picture.Expanded (Index) := 'b';
2546 Skip;
2548 when '*' =>
2549 Pic.End_Float := Index;
2550 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2551 Set_State (Okay); Skip;
2553 when '9' =>
2554 Set_State (Okay);
2555 Number_Completion;
2556 return;
2558 when '.' | 'V' | 'v' =>
2559 Pic.Radix_Position := Index;
2560 Skip;
2561 Number_Fraction_Or_Star_Fill;
2562 return;
2564 when '#' | '$' =>
2565 Trailing_Currency;
2566 Set_State (Okay);
2567 return;
2569 when others => raise Picture_Error;
2570 end case;
2571 end loop;
2572 end Star_Suppression;
2574 ----------------------
2575 -- Trailing_Bracket --
2576 ----------------------
2578 procedure Trailing_Bracket is
2579 begin
2580 if Look = '>' then
2581 Pic.Second_Sign := Index;
2582 Skip;
2583 else
2584 raise Picture_Error;
2585 end if;
2586 end Trailing_Bracket;
2588 -----------------------
2589 -- Trailing_Currency --
2590 -----------------------
2592 procedure Trailing_Currency is
2593 begin
2594 if At_End then
2595 return;
2596 end if;
2598 if Look = '$' then
2599 Pic.Start_Currency := Index;
2600 Pic.End_Currency := Index;
2601 Skip;
2603 else
2604 while not At_End and then Look = '#' loop
2605 if Pic.Start_Currency = Invalid_Position then
2606 Pic.Start_Currency := Index;
2607 end if;
2609 Pic.End_Currency := Index;
2610 Skip;
2611 end loop;
2612 end if;
2614 loop
2615 if At_End then
2616 return;
2617 end if;
2619 case Look is
2620 when '_' | '0' | '/' => Skip;
2622 when 'B' | 'b' =>
2623 Pic.Picture.Expanded (Index) := 'b';
2624 Skip;
2626 when others => return;
2627 end case;
2628 end loop;
2629 end Trailing_Currency;
2631 ----------------------
2632 -- Zero_Suppression --
2633 ----------------------
2635 procedure Zero_Suppression is
2636 begin
2637 Pic.Floater := 'Z';
2638 Pic.Start_Float := Index;
2639 Pic.End_Float := Index;
2640 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2641 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2643 Skip; -- Known Z
2645 loop
2646 -- Even a single Z is a valid picture
2648 if At_End then
2649 Set_State (Okay);
2650 return;
2651 end if;
2653 case Look is
2654 when '_' | '0' | '/' =>
2655 Pic.End_Float := Index;
2656 Skip;
2658 when 'B' | 'b' =>
2659 Pic.End_Float := Index;
2660 Pic.Picture.Expanded (Index) := 'b';
2661 Skip;
2663 when 'Z' | 'z' =>
2664 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2666 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2667 Pic.End_Float := Index;
2668 Set_State (Okay);
2669 Skip;
2671 when '9' =>
2672 Set_State (Okay);
2673 Number_Completion;
2674 return;
2676 when '.' | 'V' | 'v' =>
2677 Pic.Radix_Position := Index;
2678 Skip;
2679 Number_Fraction_Or_Z_Fill;
2680 return;
2682 when '#' | '$' =>
2683 Trailing_Currency;
2684 Set_State (Okay);
2685 return;
2687 when others =>
2688 return;
2689 end case;
2690 end loop;
2691 end Zero_Suppression;
2693 -- Start of processing for Precalculate
2695 begin
2696 Picture_String;
2698 if State = Reject then
2699 raise Picture_Error;
2700 end if;
2702 exception
2704 when Constraint_Error =>
2706 -- To deal with special cases like null strings.
2708 raise Picture_Error;
2710 end Precalculate;
2712 ----------------
2713 -- To_Picture --
2714 ----------------
2716 function To_Picture
2717 (Pic_String : in String;
2718 Blank_When_Zero : in Boolean := False)
2719 return Picture
2721 Result : Picture;
2723 begin
2724 declare
2725 Item : constant String := Expand (Pic_String);
2727 begin
2728 Result.Contents.Picture := (Item'Length, Item);
2729 Result.Contents.Original_BWZ := Blank_When_Zero;
2730 Result.Contents.Blank_When_Zero := Blank_When_Zero;
2731 Precalculate (Result.Contents);
2732 return Result;
2733 end;
2735 exception
2736 when others =>
2737 raise Picture_Error;
2739 end To_Picture;
2741 -------------
2742 -- To_Wide --
2743 -------------
2745 function To_Wide (C : Character) return Wide_Character is
2746 begin
2747 return Wide_Character'Val (Character'Pos (C));
2748 end To_Wide;
2750 -----------
2751 -- Valid --
2752 -----------
2754 function Valid
2755 (Pic_String : in String;
2756 Blank_When_Zero : in Boolean := False)
2757 return Boolean
2759 begin
2760 declare
2761 Expanded_Pic : constant String := Expand (Pic_String);
2762 -- Raises Picture_Error if Item not well-formed
2764 Format_Rec : Format_Record;
2766 begin
2767 Format_Rec.Picture := (Expanded_Pic'Length, Expanded_Pic);
2768 Format_Rec.Blank_When_Zero := Blank_When_Zero;
2769 Format_Rec.Original_BWZ := Blank_When_Zero;
2770 Precalculate (Format_Rec);
2772 -- False only if Blank_When_0 is True but the pic string
2773 -- has a '*'
2775 return not Blank_When_Zero or
2776 Strings_Fixed.Index (Expanded_Pic, "*") = 0;
2777 end;
2779 exception
2780 when others => return False;
2782 end Valid;
2784 end Ada.Wide_Text_IO.Editing;