e23c60e78a0cf121c85ea19317b4aa3d2da753ae
[gcc.git] / gcc / ada / a-wtedit.adb
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 -- Copyright (C) 1992-2009, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
31
32 with Ada.Strings.Fixed;
33 with Ada.Strings.Wide_Fixed;
34
35 package body Ada.Wide_Text_IO.Editing is
36
37 package Strings renames Ada.Strings;
38 package Strings_Fixed renames Ada.Strings.Fixed;
39 package Strings_Wide_Fixed renames Ada.Strings.Wide_Fixed;
40 package Wide_Text_IO renames Ada.Wide_Text_IO;
41
42 -----------------------
43 -- Local_Subprograms --
44 -----------------------
45
46 function To_Wide (C : Character) return Wide_Character;
47 pragma Inline (To_Wide);
48 -- Convert Character to corresponding Wide_Character
49
50 ---------------------
51 -- Blank_When_Zero --
52 ---------------------
53
54 function Blank_When_Zero (Pic : Picture) return Boolean is
55 begin
56 return Pic.Contents.Original_BWZ;
57 end Blank_When_Zero;
58
59 --------------------
60 -- Decimal_Output --
61 --------------------
62
63 package body Decimal_Output is
64
65 -----------
66 -- Image --
67 -----------
68
69 function Image
70 (Item : Num;
71 Pic : Picture;
72 Currency : Wide_String := Default_Currency;
73 Fill : Wide_Character := Default_Fill;
74 Separator : Wide_Character := Default_Separator;
75 Radix_Mark : Wide_Character := Default_Radix_Mark) return Wide_String
76 is
77 begin
78 return Format_Number
79 (Pic.Contents, Num'Image (Item),
80 Currency, Fill, Separator, Radix_Mark);
81 end Image;
82
83 ------------
84 -- Length --
85 ------------
86
87 function Length
88 (Pic : Picture;
89 Currency : Wide_String := Default_Currency) return Natural
90 is
91 Picstr : constant String := Pic_String (Pic);
92 V_Adjust : Integer := 0;
93 Cur_Adjust : Integer := 0;
94
95 begin
96 -- Check if Picstr has 'V' or '$'
97
98 -- If 'V', then length is 1 less than otherwise
99
100 -- If '$', then length is Currency'Length-1 more than otherwise
101
102 -- This should use the string handling package ???
103
104 for J in Picstr'Range loop
105 if Picstr (J) = 'V' then
106 V_Adjust := -1;
107
108 elsif Picstr (J) = '$' then
109 Cur_Adjust := Currency'Length - 1;
110 end if;
111 end loop;
112
113 return Picstr'Length - V_Adjust + Cur_Adjust;
114 end Length;
115
116 ---------
117 -- Put --
118 ---------
119
120 procedure Put
121 (File : Wide_Text_IO.File_Type;
122 Item : Num;
123 Pic : Picture;
124 Currency : Wide_String := Default_Currency;
125 Fill : Wide_Character := Default_Fill;
126 Separator : Wide_Character := Default_Separator;
127 Radix_Mark : Wide_Character := Default_Radix_Mark)
128 is
129 begin
130 Wide_Text_IO.Put (File, Image (Item, Pic,
131 Currency, Fill, Separator, Radix_Mark));
132 end Put;
133
134 procedure Put
135 (Item : Num;
136 Pic : Picture;
137 Currency : Wide_String := Default_Currency;
138 Fill : Wide_Character := Default_Fill;
139 Separator : Wide_Character := Default_Separator;
140 Radix_Mark : Wide_Character := Default_Radix_Mark)
141 is
142 begin
143 Wide_Text_IO.Put (Image (Item, Pic,
144 Currency, Fill, Separator, Radix_Mark));
145 end Put;
146
147 procedure Put
148 (To : out Wide_String;
149 Item : Num;
150 Pic : Picture;
151 Currency : Wide_String := Default_Currency;
152 Fill : Wide_Character := Default_Fill;
153 Separator : Wide_Character := Default_Separator;
154 Radix_Mark : Wide_Character := Default_Radix_Mark)
155 is
156 Result : constant Wide_String :=
157 Image (Item, Pic, Currency, Fill, Separator, Radix_Mark);
158
159 begin
160 if Result'Length > To'Length then
161 raise Wide_Text_IO.Layout_Error;
162 else
163 Strings_Wide_Fixed.Move (Source => Result, Target => To,
164 Justify => Strings.Right);
165 end if;
166 end Put;
167
168 -----------
169 -- Valid --
170 -----------
171
172 function Valid
173 (Item : Num;
174 Pic : Picture;
175 Currency : Wide_String := Default_Currency) return Boolean
176 is
177 begin
178 declare
179 Temp : constant Wide_String := Image (Item, Pic, Currency);
180 pragma Warnings (Off, Temp);
181 begin
182 return True;
183 end;
184
185 exception
186 when Layout_Error => return False;
187
188 end Valid;
189 end Decimal_Output;
190
191 ------------
192 -- Expand --
193 ------------
194
195 function Expand (Picture : String) return String is
196 Result : String (1 .. MAX_PICSIZE);
197 Picture_Index : Integer := Picture'First;
198 Result_Index : Integer := Result'First;
199 Count : Natural;
200 Last : Integer;
201
202 begin
203 if Picture'Length < 1 then
204 raise Picture_Error;
205 end if;
206
207 if Picture (Picture'First) = '(' then
208 raise Picture_Error;
209 end if;
210
211 loop
212 case Picture (Picture_Index) is
213
214 when '(' =>
215
216 -- We now need to scan out the count after a left paren. In
217 -- the non-wide version we used Integer_IO.Get, but that is
218 -- not convenient here, since we don't want to drag in normal
219 -- Text_IO just for this purpose. So we do the scan ourselves,
220 -- with the normal validity checks.
221
222 Last := Picture_Index + 1;
223 Count := 0;
224
225 if Picture (Last) not in '0' .. '9' then
226 raise Picture_Error;
227 end if;
228
229 Count := Character'Pos (Picture (Last)) - Character'Pos ('0');
230 Last := Last + 1;
231
232 loop
233 if Last > Picture'Last then
234 raise Picture_Error;
235 end if;
236
237 if Picture (Last) = '_' then
238 if Picture (Last - 1) = '_' then
239 raise Picture_Error;
240 end if;
241
242 elsif Picture (Last) = ')' then
243 exit;
244
245 elsif Picture (Last) not in '0' .. '9' then
246 raise Picture_Error;
247
248 else
249 Count := Count * 10
250 + Character'Pos (Picture (Last)) -
251 Character'Pos ('0');
252 end if;
253
254 Last := Last + 1;
255 end loop;
256
257 -- In what follows note that one copy of the repeated
258 -- character has already been made, so a count of one is
259 -- no-op, and a count of zero erases a character.
260
261 for J in 2 .. Count loop
262 Result (Result_Index + J - 2) := Picture (Picture_Index - 1);
263 end loop;
264
265 Result_Index := Result_Index + Count - 1;
266
267 -- Last was a ')' throw it away too
268
269 Picture_Index := Last + 1;
270
271 when ')' =>
272 raise Picture_Error;
273
274 when others =>
275 Result (Result_Index) := Picture (Picture_Index);
276 Picture_Index := Picture_Index + 1;
277 Result_Index := Result_Index + 1;
278
279 end case;
280
281 exit when Picture_Index > Picture'Last;
282 end loop;
283
284 return Result (1 .. Result_Index - 1);
285
286 exception
287 when others =>
288 raise Picture_Error;
289 end Expand;
290
291 -------------------
292 -- Format_Number --
293 -------------------
294
295 function Format_Number
296 (Pic : Format_Record;
297 Number : String;
298 Currency_Symbol : Wide_String;
299 Fill_Character : Wide_Character;
300 Separator_Character : Wide_Character;
301 Radix_Point : Wide_Character) return Wide_String
302 is
303 Attrs : Number_Attributes := Parse_Number_String (Number);
304 Position : Integer;
305 Rounded : String := Number;
306
307 Sign_Position : Integer := Pic.Sign_Position; -- may float.
308
309 Answer : Wide_String (1 .. Pic.Picture.Length);
310 Last : Integer;
311 Currency_Pos : Integer := Pic.Start_Currency;
312
313 Dollar : Boolean := False;
314 -- Overridden immediately if necessary
315
316 Zero : Boolean := True;
317 -- Set to False when a non-zero digit is output
318
319 begin
320
321 -- If the picture has fewer decimal places than the number, the image
322 -- must be rounded according to the usual rules.
323
324 if Attrs.Has_Fraction then
325 declare
326 R : constant Integer :=
327 (Attrs.End_Of_Fraction - Attrs.Start_Of_Fraction + 1)
328 - Pic.Max_Trailing_Digits;
329 R_Pos : Integer;
330
331 begin
332 if R > 0 then
333 R_Pos := Rounded'Length - R;
334
335 if Rounded (R_Pos + 1) > '4' then
336
337 if Rounded (R_Pos) = '.' then
338 R_Pos := R_Pos - 1;
339 end if;
340
341 if Rounded (R_Pos) /= '9' then
342 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
343 else
344 Rounded (R_Pos) := '0';
345 R_Pos := R_Pos - 1;
346
347 while R_Pos > 1 loop
348 if Rounded (R_Pos) = '.' then
349 R_Pos := R_Pos - 1;
350 end if;
351
352 if Rounded (R_Pos) /= '9' then
353 Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
354 exit;
355 else
356 Rounded (R_Pos) := '0';
357 R_Pos := R_Pos - 1;
358 end if;
359 end loop;
360
361 -- The rounding may add a digit in front. Either the
362 -- leading blank or the sign (already captured) can be
363 -- overwritten.
364
365 if R_Pos = 1 then
366 Rounded (R_Pos) := '1';
367 Attrs.Start_Of_Int := Attrs.Start_Of_Int - 1;
368 end if;
369 end if;
370 end if;
371 end if;
372 end;
373 end if;
374
375 for J in Answer'Range loop
376 Answer (J) := To_Wide (Pic.Picture.Expanded (J));
377 end loop;
378
379 if Pic.Start_Currency /= Invalid_Position then
380 Dollar := Answer (Pic.Start_Currency) = '$';
381 end if;
382
383 -- Fix up "direct inserts" outside the playing field. Set up as one
384 -- loop to do the beginning, one (reverse) loop to do the end.
385
386 Last := 1;
387 loop
388 exit when Last = Pic.Start_Float;
389 exit when Last = Pic.Radix_Position;
390 exit when Answer (Last) = '9';
391
392 case Answer (Last) is
393
394 when '_' =>
395 Answer (Last) := Separator_Character;
396
397 when 'b' =>
398 Answer (Last) := ' ';
399
400 when others =>
401 null;
402
403 end case;
404
405 exit when Last = Answer'Last;
406
407 Last := Last + 1;
408 end loop;
409
410 -- Now for the end...
411
412 for J in reverse Last .. Answer'Last loop
413 exit when J = Pic.Radix_Position;
414
415 -- Do this test First, Separator_Character can equal Pic.Floater
416
417 if Answer (J) = Pic.Floater then
418 exit;
419 end if;
420
421 case Answer (J) is
422
423 when '_' =>
424 Answer (J) := Separator_Character;
425
426 when 'b' =>
427 Answer (J) := ' ';
428
429 when '9' =>
430 exit;
431
432 when others =>
433 null;
434
435 end case;
436 end loop;
437
438 -- Non-floating sign
439
440 if Pic.Start_Currency /= -1
441 and then Answer (Pic.Start_Currency) = '#'
442 and then Pic.Floater /= '#'
443 then
444 if Currency_Symbol'Length >
445 Pic.End_Currency - Pic.Start_Currency + 1
446 then
447 raise Picture_Error;
448
449 elsif Currency_Symbol'Length =
450 Pic.End_Currency - Pic.Start_Currency + 1
451 then
452 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
453 Currency_Symbol;
454
455 elsif Pic.Radix_Position = Invalid_Position
456 or else Pic.Start_Currency < Pic.Radix_Position
457 then
458 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
459 (others => ' ');
460 Answer (Pic.End_Currency - Currency_Symbol'Length + 1 ..
461 Pic.End_Currency) := Currency_Symbol;
462
463 else
464 Answer (Pic.Start_Currency .. Pic.End_Currency) :=
465 (others => ' ');
466 Answer (Pic.Start_Currency ..
467 Pic.Start_Currency + Currency_Symbol'Length - 1) :=
468 Currency_Symbol;
469 end if;
470 end if;
471
472 -- Fill in leading digits
473
474 if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
475 Pic.Max_Leading_Digits
476 then
477 raise Layout_Error;
478 end if;
479
480 if Pic.Radix_Position = Invalid_Position then
481 Position := Answer'Last;
482 else
483 Position := Pic.Radix_Position - 1;
484 end if;
485
486 for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop
487
488 while Answer (Position) /= '9'
489 and Answer (Position) /= Pic.Floater
490 loop
491 if Answer (Position) = '_' then
492 Answer (Position) := Separator_Character;
493
494 elsif Answer (Position) = 'b' then
495 Answer (Position) := ' ';
496 end if;
497
498 Position := Position - 1;
499 end loop;
500
501 Answer (Position) := To_Wide (Rounded (J));
502
503 if Rounded (J) /= '0' then
504 Zero := False;
505 end if;
506
507 Position := Position - 1;
508 end loop;
509
510 -- Do lead float
511
512 if Pic.Start_Float = Invalid_Position then
513
514 -- No leading floats, but need to change '9' to '0', '_' to
515 -- Separator_Character and 'b' to ' '.
516
517 for J in Last .. Position loop
518
519 -- Last set when fixing the "uninteresting" leaders above.
520 -- Don't duplicate the work.
521
522 if Answer (J) = '9' then
523 Answer (J) := '0';
524
525 elsif Answer (J) = '_' then
526 Answer (J) := Separator_Character;
527
528 elsif Answer (J) = 'b' then
529 Answer (J) := ' ';
530
531 end if;
532
533 end loop;
534
535 elsif Pic.Floater = '<'
536 or else
537 Pic.Floater = '+'
538 or else
539 Pic.Floater = '-'
540 then
541 for J in Pic.End_Float .. Position loop -- May be null range
542 if Answer (J) = '9' then
543 Answer (J) := '0';
544
545 elsif Answer (J) = '_' then
546 Answer (J) := Separator_Character;
547
548 elsif Answer (J) = 'b' then
549 Answer (J) := ' ';
550
551 end if;
552 end loop;
553
554 if Position > Pic.End_Float then
555 Position := Pic.End_Float;
556 end if;
557
558 for J in Pic.Start_Float .. Position - 1 loop
559 Answer (J) := ' ';
560 end loop;
561
562 Answer (Position) := Pic.Floater;
563 Sign_Position := Position;
564
565 elsif Pic.Floater = '$' then
566
567 for J in Pic.End_Float .. Position loop -- May be null range
568 if Answer (J) = '9' then
569 Answer (J) := '0';
570
571 elsif Answer (J) = '_' then
572 Answer (J) := ' '; -- no separator before leftmost digit
573
574 elsif Answer (J) = 'b' then
575 Answer (J) := ' ';
576 end if;
577 end loop;
578
579 if Position > Pic.End_Float then
580 Position := Pic.End_Float;
581 end if;
582
583 for J in Pic.Start_Float .. Position - 1 loop
584 Answer (J) := ' ';
585 end loop;
586
587 Answer (Position) := Pic.Floater;
588 Currency_Pos := Position;
589
590 elsif Pic.Floater = '*' then
591
592 for J in Pic.End_Float .. Position loop -- May be null range
593 if Answer (J) = '9' then
594 Answer (J) := '0';
595
596 elsif Answer (J) = '_' then
597 Answer (J) := Separator_Character;
598
599 elsif Answer (J) = 'b' then
600 Answer (J) := '*';
601 end if;
602 end loop;
603
604 if Position > Pic.End_Float then
605 Position := Pic.End_Float;
606 end if;
607
608 for J in Pic.Start_Float .. Position loop
609 Answer (J) := '*';
610 end loop;
611
612 else
613 if Pic.Floater = '#' then
614 Currency_Pos := Currency_Symbol'Length;
615 end if;
616
617 for J in reverse Pic.Start_Float .. Position loop
618 case Answer (J) is
619
620 when '*' =>
621 Answer (J) := Fill_Character;
622
623 when 'Z' | 'b' | '/' | '0' =>
624 Answer (J) := ' ';
625
626 when '9' =>
627 Answer (J) := '0';
628
629 when '.' | 'V' | 'v' | '<' | '$' | '+' | '-' =>
630 null;
631
632 when '#' =>
633 if Currency_Pos = 0 then
634 Answer (J) := ' ';
635 else
636 Answer (J) := Currency_Symbol (Currency_Pos);
637 Currency_Pos := Currency_Pos - 1;
638 end if;
639
640 when '_' =>
641
642 case Pic.Floater is
643
644 when '*' =>
645 Answer (J) := Fill_Character;
646
647 when 'Z' | 'b' =>
648 Answer (J) := ' ';
649
650 when '#' =>
651 if Currency_Pos = 0 then
652 Answer (J) := ' ';
653
654 else
655 Answer (J) := Currency_Symbol (Currency_Pos);
656 Currency_Pos := Currency_Pos - 1;
657 end if;
658
659 when others =>
660 null;
661
662 end case;
663
664 when others =>
665 null;
666
667 end case;
668 end loop;
669
670 if Pic.Floater = '#' and then Currency_Pos /= 0 then
671 raise Layout_Error;
672 end if;
673 end if;
674
675 -- Do sign
676
677 if Sign_Position = Invalid_Position then
678 if Attrs.Negative then
679 raise Layout_Error;
680 end if;
681
682 else
683 if Attrs.Negative then
684 case Answer (Sign_Position) is
685 when 'C' | 'D' | '-' =>
686 null;
687
688 when '+' =>
689 Answer (Sign_Position) := '-';
690
691 when '<' =>
692 Answer (Sign_Position) := '(';
693 Answer (Pic.Second_Sign) := ')';
694
695 when others =>
696 raise Picture_Error;
697
698 end case;
699
700 else -- positive
701
702 case Answer (Sign_Position) is
703
704 when '-' =>
705 Answer (Sign_Position) := ' ';
706
707 when '<' | 'C' | 'D' =>
708 Answer (Sign_Position) := ' ';
709 Answer (Pic.Second_Sign) := ' ';
710
711 when '+' =>
712 null;
713
714 when others =>
715 raise Picture_Error;
716
717 end case;
718 end if;
719 end if;
720
721 -- Fill in trailing digits
722
723 if Pic.Max_Trailing_Digits > 0 then
724
725 if Attrs.Has_Fraction then
726 Position := Attrs.Start_Of_Fraction;
727 Last := Pic.Radix_Position + 1;
728
729 for J in Last .. Answer'Last loop
730
731 if Answer (J) = '9' or Answer (J) = Pic.Floater then
732 Answer (J) := To_Wide (Rounded (Position));
733
734 if Rounded (Position) /= '0' then
735 Zero := False;
736 end if;
737
738 Position := Position + 1;
739 Last := J + 1;
740
741 -- Used up fraction but remember place in Answer
742
743 exit when Position > Attrs.End_Of_Fraction;
744
745 elsif Answer (J) = 'b' then
746 Answer (J) := ' ';
747
748 elsif Answer (J) = '_' then
749 Answer (J) := Separator_Character;
750
751 end if;
752
753 Last := J + 1;
754 end loop;
755
756 Position := Last;
757
758 else
759 Position := Pic.Radix_Position + 1;
760 end if;
761
762 -- Now fill remaining 9's with zeros and _ with separators
763
764 Last := Answer'Last;
765
766 for J in Position .. Last loop
767 if Answer (J) = '9' then
768 Answer (J) := '0';
769
770 elsif Answer (J) = Pic.Floater then
771 Answer (J) := '0';
772
773 elsif Answer (J) = '_' then
774 Answer (J) := Separator_Character;
775
776 elsif Answer (J) = 'b' then
777 Answer (J) := ' ';
778
779 end if;
780 end loop;
781
782 Position := Last + 1;
783
784 else
785 if Pic.Floater = '#' and then Currency_Pos /= 0 then
786 raise Layout_Error;
787 end if;
788
789 -- No trailing digits, but now J may need to stick in a currency
790 -- symbol or sign.
791
792 if Pic.Start_Currency = Invalid_Position then
793 Position := Answer'Last + 1;
794 else
795 Position := Pic.Start_Currency;
796 end if;
797 end if;
798
799 for J in Position .. Answer'Last loop
800
801 if Pic.Start_Currency /= Invalid_Position and then
802 Answer (Pic.Start_Currency) = '#' then
803 Currency_Pos := 1;
804 end if;
805
806 -- Note: There are some weird cases J can imagine with 'b' or '#'
807 -- in currency strings where the following code will cause
808 -- glitches. The trick is to tell when the character in the
809 -- answer should be checked, and when to look at the original
810 -- string. Some other time. RIE 11/26/96 ???
811
812 case Answer (J) is
813 when '*' =>
814 Answer (J) := Fill_Character;
815
816 when 'b' =>
817 Answer (J) := ' ';
818
819 when '#' =>
820 if Currency_Pos > Currency_Symbol'Length then
821 Answer (J) := ' ';
822
823 else
824 Answer (J) := Currency_Symbol (Currency_Pos);
825 Currency_Pos := Currency_Pos + 1;
826 end if;
827
828 when '_' =>
829
830 case Pic.Floater is
831
832 when '*' =>
833 Answer (J) := Fill_Character;
834
835 when 'Z' | 'z' =>
836 Answer (J) := ' ';
837
838 when '#' =>
839 if Currency_Pos > Currency_Symbol'Length then
840 Answer (J) := ' ';
841 else
842 Answer (J) := Currency_Symbol (Currency_Pos);
843 Currency_Pos := Currency_Pos + 1;
844 end if;
845
846 when others =>
847 null;
848
849 end case;
850
851 when others =>
852 exit;
853
854 end case;
855 end loop;
856
857 -- Now get rid of Blank_when_Zero and complete Star fill
858
859 if Zero and Pic.Blank_When_Zero then
860
861 -- Value is zero, and blank it
862
863 Last := Answer'Last;
864
865 if Dollar then
866 Last := Last - 1 + Currency_Symbol'Length;
867 end if;
868
869 if Pic.Radix_Position /= Invalid_Position and then
870 Answer (Pic.Radix_Position) = 'V' then
871 Last := Last - 1;
872 end if;
873
874 return Wide_String'(1 .. Last => ' ');
875
876 elsif Zero and Pic.Star_Fill then
877 Last := Answer'Last;
878
879 if Dollar then
880 Last := Last - 1 + Currency_Symbol'Length;
881 end if;
882
883 if Pic.Radix_Position /= Invalid_Position then
884
885 if Answer (Pic.Radix_Position) = 'V' then
886 Last := Last - 1;
887
888 elsif Dollar then
889 if Pic.Radix_Position > Pic.Start_Currency then
890 return Wide_String'(1 .. Pic.Radix_Position - 1 => '*') &
891 Radix_Point &
892 Wide_String'(Pic.Radix_Position + 1 .. Last => '*');
893
894 else
895 return
896 Wide_String'
897 (1 ..
898 Pic.Radix_Position + Currency_Symbol'Length - 2
899 => '*') &
900 Radix_Point &
901 Wide_String'
902 (Pic.Radix_Position + Currency_Symbol'Length .. Last
903 => '*');
904 end if;
905
906 else
907 return
908 Wide_String'(1 .. Pic.Radix_Position - 1 => '*') &
909 Radix_Point &
910 Wide_String'(Pic.Radix_Position + 1 .. Last => '*');
911 end if;
912 end if;
913
914 return Wide_String'(1 .. Last => '*');
915 end if;
916
917 -- This was once a simple return statement, now there are nine
918 -- different return cases. Not to mention the five above to deal
919 -- with zeros. Why not split things out?
920
921 -- Processing the radix and sign expansion separately
922 -- would require lots of copying--the string and some of its
923 -- indicies--without really simplifying the logic. The cases are:
924
925 -- 1) Expand $, replace '.' with Radix_Point
926 -- 2) No currency expansion, replace '.' with Radix_Point
927 -- 3) Expand $, radix blanked
928 -- 4) No currency expansion, radix blanked
929 -- 5) Elide V
930 -- 6) Expand $, Elide V
931 -- 7) Elide V, Expand $ (Two cases depending on order.)
932 -- 8) No radix, expand $
933 -- 9) No radix, no currency expansion
934
935 if Pic.Radix_Position /= Invalid_Position then
936
937 if Answer (Pic.Radix_Position) = '.' then
938 Answer (Pic.Radix_Position) := Radix_Point;
939
940 if Dollar then
941
942 -- 1) Expand $, replace '.' with Radix_Point
943
944 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
945 Answer (Currency_Pos + 1 .. Answer'Last);
946
947 else
948 -- 2) No currency expansion, replace '.' with Radix_Point
949
950 return Answer;
951 end if;
952
953 elsif Answer (Pic.Radix_Position) = ' ' then -- blanked radix.
954 if Dollar then
955
956 -- 3) Expand $, radix blanked
957
958 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
959 Answer (Currency_Pos + 1 .. Answer'Last);
960
961 else
962 -- 4) No expansion, radix blanked
963
964 return Answer;
965 end if;
966
967 -- V cases
968
969 else
970 if not Dollar then
971
972 -- 5) Elide V
973
974 return Answer (1 .. Pic.Radix_Position - 1) &
975 Answer (Pic.Radix_Position + 1 .. Answer'Last);
976
977 elsif Currency_Pos < Pic.Radix_Position then
978
979 -- 6) Expand $, Elide V
980
981 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
982 Answer (Currency_Pos + 1 .. Pic.Radix_Position - 1) &
983 Answer (Pic.Radix_Position + 1 .. Answer'Last);
984
985 else
986 -- 7) Elide V, Expand $
987
988 return Answer (1 .. Pic.Radix_Position - 1) &
989 Answer (Pic.Radix_Position + 1 .. Currency_Pos - 1) &
990 Currency_Symbol &
991 Answer (Currency_Pos + 1 .. Answer'Last);
992 end if;
993 end if;
994
995 elsif Dollar then
996
997 -- 8) No radix, expand $
998
999 return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
1000 Answer (Currency_Pos + 1 .. Answer'Last);
1001
1002 else
1003 -- 9) No radix, no currency expansion
1004
1005 return Answer;
1006 end if;
1007 end Format_Number;
1008
1009 -------------------------
1010 -- Parse_Number_String --
1011 -------------------------
1012
1013 function Parse_Number_String (Str : String) return Number_Attributes is
1014 Answer : Number_Attributes;
1015
1016 begin
1017 for J in Str'Range loop
1018 case Str (J) is
1019
1020 when ' ' =>
1021 null; -- ignore
1022
1023 when '1' .. '9' =>
1024
1025 -- Decide if this is the start of a number.
1026 -- If so, figure out which one...
1027
1028 if Answer.Has_Fraction then
1029 Answer.End_Of_Fraction := J;
1030 else
1031 if Answer.Start_Of_Int = Invalid_Position then
1032 -- start integer
1033 Answer.Start_Of_Int := J;
1034 end if;
1035 Answer.End_Of_Int := J;
1036 end if;
1037
1038 when '0' =>
1039
1040 -- Only count a zero before the decimal point if it follows a
1041 -- non-zero digit. After the decimal point, zeros will be
1042 -- counted if followed by a non-zero digit.
1043
1044 if not Answer.Has_Fraction then
1045 if Answer.Start_Of_Int /= Invalid_Position then
1046 Answer.End_Of_Int := J;
1047 end if;
1048 end if;
1049
1050 when '-' =>
1051
1052 -- Set negative
1053
1054 Answer.Negative := True;
1055
1056 when '.' =>
1057
1058 -- Close integer, start fraction
1059
1060 if Answer.Has_Fraction then
1061 raise Picture_Error;
1062 end if;
1063
1064 -- Two decimal points is a no-no
1065
1066 Answer.Has_Fraction := True;
1067 Answer.End_Of_Fraction := J;
1068
1069 -- Could leave this at Invalid_Position, but this seems the
1070 -- right way to indicate a null range...
1071
1072 Answer.Start_Of_Fraction := J + 1;
1073 Answer.End_Of_Int := J - 1;
1074
1075 when others =>
1076 raise Picture_Error; -- can this happen? probably not!
1077 end case;
1078 end loop;
1079
1080 if Answer.Start_Of_Int = Invalid_Position then
1081 Answer.Start_Of_Int := Answer.End_Of_Int + 1;
1082 end if;
1083
1084 -- No significant (intger) digits needs a null range
1085
1086 return Answer;
1087 end Parse_Number_String;
1088
1089 ----------------
1090 -- Pic_String --
1091 ----------------
1092
1093 -- The following ensures that we return B and not b being careful not
1094 -- to break things which expect lower case b for blank. See CXF3A02.
1095
1096 function Pic_String (Pic : Picture) return String is
1097 Temp : String (1 .. Pic.Contents.Picture.Length) :=
1098 Pic.Contents.Picture.Expanded;
1099 begin
1100 for J in Temp'Range loop
1101 if Temp (J) = 'b' then
1102 Temp (J) := 'B';
1103 end if;
1104 end loop;
1105
1106 return Temp;
1107 end Pic_String;
1108
1109 ------------------
1110 -- Precalculate --
1111 ------------------
1112
1113 procedure Precalculate (Pic : in out Format_Record) is
1114
1115 Computed_BWZ : Boolean := True;
1116
1117 type Legality is (Okay, Reject);
1118 State : Legality := Reject;
1119 -- Start in reject, which will reject null strings
1120
1121 Index : Pic_Index := Pic.Picture.Expanded'First;
1122
1123 function At_End return Boolean;
1124 pragma Inline (At_End);
1125
1126 procedure Set_State (L : Legality);
1127 pragma Inline (Set_State);
1128
1129 function Look return Character;
1130 pragma Inline (Look);
1131
1132 function Is_Insert return Boolean;
1133 pragma Inline (Is_Insert);
1134
1135 procedure Skip;
1136 pragma Inline (Skip);
1137
1138 procedure Trailing_Currency;
1139 procedure Trailing_Bracket;
1140 procedure Number_Fraction;
1141 procedure Number_Completion;
1142 procedure Number_Fraction_Or_Bracket;
1143 procedure Number_Fraction_Or_Z_Fill;
1144 procedure Zero_Suppression;
1145 procedure Floating_Bracket;
1146 procedure Number_Fraction_Or_Star_Fill;
1147 procedure Star_Suppression;
1148 procedure Number_Fraction_Or_Dollar;
1149 procedure Leading_Dollar;
1150 procedure Number_Fraction_Or_Pound;
1151 procedure Leading_Pound;
1152 procedure Picture;
1153 procedure Floating_Plus;
1154 procedure Floating_Minus;
1155 procedure Picture_Plus;
1156 procedure Picture_Minus;
1157 procedure Picture_Bracket;
1158 procedure Number;
1159 procedure Optional_RHS_Sign;
1160 procedure Picture_String;
1161
1162 ------------
1163 -- At_End --
1164 ------------
1165
1166 function At_End return Boolean is
1167 begin
1168 return Index > Pic.Picture.Length;
1169 end At_End;
1170
1171 ----------------------
1172 -- Floating_Bracket --
1173 ----------------------
1174
1175 -- Note that Floating_Bracket is only called with an acceptable
1176 -- prefix. But we don't set Okay, because we must end with a '>'.
1177
1178 procedure Floating_Bracket is
1179 begin
1180 Pic.Floater := '<';
1181 Pic.End_Float := Index;
1182 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1183
1184 -- First bracket wasn't counted...
1185
1186 Skip; -- known '<'
1187
1188 loop
1189 if At_End then
1190 return;
1191 end if;
1192
1193 case Look is
1194
1195 when '_' | '0' | '/' =>
1196 Pic.End_Float := Index;
1197 Skip;
1198
1199 when 'B' | 'b' =>
1200 Pic.End_Float := Index;
1201 Pic.Picture.Expanded (Index) := 'b';
1202 Skip;
1203
1204 when '<' =>
1205 Pic.End_Float := Index;
1206 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1207 Skip;
1208
1209 when '9' =>
1210 Number_Completion;
1211
1212 when '$' =>
1213 Leading_Dollar;
1214
1215 when '#' =>
1216 Leading_Pound;
1217
1218 when 'V' | 'v' | '.' =>
1219 Pic.Radix_Position := Index;
1220 Skip;
1221 Number_Fraction_Or_Bracket;
1222 return;
1223
1224 when others =>
1225 return;
1226 end case;
1227 end loop;
1228 end Floating_Bracket;
1229
1230 --------------------
1231 -- Floating_Minus --
1232 --------------------
1233
1234 procedure Floating_Minus is
1235 begin
1236 loop
1237 if At_End then
1238 return;
1239 end if;
1240
1241 case Look is
1242 when '_' | '0' | '/' =>
1243 Pic.End_Float := Index;
1244 Skip;
1245
1246 when 'B' | 'b' =>
1247 Pic.End_Float := Index;
1248 Pic.Picture.Expanded (Index) := 'b';
1249 Skip;
1250
1251 when '-' =>
1252 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1253 Pic.End_Float := Index;
1254 Skip;
1255
1256 when '9' =>
1257 Number_Completion;
1258 return;
1259
1260 when '.' | 'V' | 'v' =>
1261 Pic.Radix_Position := Index;
1262 Skip; -- Radix
1263
1264 while Is_Insert loop
1265 Skip;
1266 end loop;
1267
1268 if At_End then
1269 return;
1270 end if;
1271
1272 if Look = '-' then
1273 loop
1274 if At_End then
1275 return;
1276 end if;
1277
1278 case Look is
1279
1280 when '-' =>
1281 Pic.Max_Trailing_Digits :=
1282 Pic.Max_Trailing_Digits + 1;
1283 Pic.End_Float := Index;
1284 Skip;
1285
1286 when '_' | '0' | '/' =>
1287 Skip;
1288
1289 when 'B' | 'b' =>
1290 Pic.Picture.Expanded (Index) := 'b';
1291 Skip;
1292
1293 when others =>
1294 return;
1295
1296 end case;
1297 end loop;
1298
1299 else
1300 Number_Completion;
1301 end if;
1302
1303 return;
1304
1305 when others =>
1306 return;
1307 end case;
1308 end loop;
1309 end Floating_Minus;
1310
1311 -------------------
1312 -- Floating_Plus --
1313 -------------------
1314
1315 procedure Floating_Plus is
1316 begin
1317 loop
1318 if At_End then
1319 return;
1320 end if;
1321
1322 case Look is
1323 when '_' | '0' | '/' =>
1324 Pic.End_Float := Index;
1325 Skip;
1326
1327 when 'B' | 'b' =>
1328 Pic.End_Float := Index;
1329 Pic.Picture.Expanded (Index) := 'b';
1330 Skip;
1331
1332 when '+' =>
1333 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1334 Pic.End_Float := Index;
1335 Skip;
1336
1337 when '9' =>
1338 Number_Completion;
1339 return;
1340
1341 when '.' | 'V' | 'v' =>
1342 Pic.Radix_Position := Index;
1343 Skip; -- Radix
1344
1345 while Is_Insert loop
1346 Skip;
1347 end loop;
1348
1349 if At_End then
1350 return;
1351 end if;
1352
1353 if Look = '+' then
1354 loop
1355 if At_End then
1356 return;
1357 end if;
1358
1359 case Look is
1360
1361 when '+' =>
1362 Pic.Max_Trailing_Digits :=
1363 Pic.Max_Trailing_Digits + 1;
1364 Pic.End_Float := Index;
1365 Skip;
1366
1367 when '_' | '0' | '/' =>
1368 Skip;
1369
1370 when 'B' | 'b' =>
1371 Pic.Picture.Expanded (Index) := 'b';
1372 Skip;
1373
1374 when others =>
1375 return;
1376
1377 end case;
1378 end loop;
1379
1380 else
1381 Number_Completion;
1382 end if;
1383
1384 return;
1385
1386 when others =>
1387 return;
1388
1389 end case;
1390 end loop;
1391 end Floating_Plus;
1392
1393 ---------------
1394 -- Is_Insert --
1395 ---------------
1396
1397 function Is_Insert return Boolean is
1398 begin
1399 if At_End then
1400 return False;
1401 end if;
1402
1403 case Pic.Picture.Expanded (Index) is
1404
1405 when '_' | '0' | '/' => return True;
1406
1407 when 'B' | 'b' =>
1408 Pic.Picture.Expanded (Index) := 'b'; -- canonical
1409 return True;
1410
1411 when others => return False;
1412 end case;
1413 end Is_Insert;
1414
1415 --------------------
1416 -- Leading_Dollar --
1417 --------------------
1418
1419 -- Note that Leading_Dollar can be called in either State.
1420 -- It will set state to Okay only if a 9 or (second) $
1421 -- is encountered.
1422
1423 -- Also notice the tricky bit with State and Zero_Suppression.
1424 -- Zero_Suppression is Picture_Error if a '$' or a '9' has been
1425 -- encountered, exactly the cases where State has been set.
1426
1427 procedure Leading_Dollar is
1428 begin
1429 -- Treat as a floating dollar, and unwind otherwise
1430
1431 Pic.Floater := '$';
1432 Pic.Start_Currency := Index;
1433 Pic.End_Currency := Index;
1434 Pic.Start_Float := Index;
1435 Pic.End_Float := Index;
1436
1437 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1438 -- currency place.
1439
1440 Skip; -- known '$'
1441
1442 loop
1443 if At_End then
1444 return;
1445 end if;
1446
1447 case Look is
1448
1449 when '_' | '0' | '/' =>
1450 Pic.End_Float := Index;
1451 Skip;
1452
1453 -- A trailing insertion character is not part of the
1454 -- floating currency, so need to look ahead.
1455
1456 if Look /= '$' then
1457 Pic.End_Float := Pic.End_Float - 1;
1458 end if;
1459
1460 when 'B' | 'b' =>
1461 Pic.End_Float := Index;
1462 Pic.Picture.Expanded (Index) := 'b';
1463 Skip;
1464
1465 when 'Z' | 'z' =>
1466 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1467
1468 if State = Okay then
1469 raise Picture_Error;
1470 else
1471 -- Will overwrite Floater and Start_Float
1472
1473 Zero_Suppression;
1474 end if;
1475
1476 when '*' =>
1477 if State = Okay then
1478 raise Picture_Error;
1479 else
1480 -- Will overwrite Floater and Start_Float
1481
1482 Star_Suppression;
1483 end if;
1484
1485 when '$' =>
1486 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1487 Pic.End_Float := Index;
1488 Pic.End_Currency := Index;
1489 Set_State (Okay); Skip;
1490
1491 when '9' =>
1492 if State /= Okay then
1493 Pic.Floater := '!';
1494 Pic.Start_Float := Invalid_Position;
1495 Pic.End_Float := Invalid_Position;
1496 end if;
1497
1498 -- A single dollar does not a floating make
1499
1500 Number_Completion;
1501 return;
1502
1503 when 'V' | 'v' | '.' =>
1504 if State /= Okay then
1505 Pic.Floater := '!';
1506 Pic.Start_Float := Invalid_Position;
1507 Pic.End_Float := Invalid_Position;
1508 end if;
1509
1510 -- Only one dollar before the sign is okay, but doesn't
1511 -- float.
1512
1513 Pic.Radix_Position := Index;
1514 Skip;
1515 Number_Fraction_Or_Dollar;
1516 return;
1517
1518 when others =>
1519 return;
1520
1521 end case;
1522 end loop;
1523 end Leading_Dollar;
1524
1525 -------------------
1526 -- Leading_Pound --
1527 -------------------
1528
1529 -- This one is complex! A Leading_Pound can be fixed or floating,
1530 -- but in some cases the decision has to be deferred until we leave
1531 -- this procedure. Also note that Leading_Pound can be called in
1532 -- either State.
1533
1534 -- It will set state to Okay only if a 9 or (second) # is
1535 -- encountered.
1536
1537 -- One Last note: In ambiguous cases, the currency is treated as
1538 -- floating unless there is only one '#'.
1539
1540 procedure Leading_Pound is
1541
1542 Inserts : Boolean := False;
1543 -- Set to True if a '_', '0', '/', 'B', or 'b' is encountered
1544
1545 Must_Float : Boolean := False;
1546 -- Set to true if a '#' occurs after an insert
1547
1548 begin
1549 -- Treat as a floating currency. If it isn't, this will be
1550 -- overwritten later.
1551
1552 Pic.Floater := '#';
1553
1554 Pic.Start_Currency := Index;
1555 Pic.End_Currency := Index;
1556 Pic.Start_Float := Index;
1557 Pic.End_Float := Index;
1558
1559 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
1560 -- currency place.
1561
1562 Pic.Max_Currency_Digits := 1; -- we've seen one.
1563
1564 Skip; -- known '#'
1565
1566 loop
1567 if At_End then
1568 return;
1569 end if;
1570
1571 case Look is
1572
1573 when '_' | '0' | '/' =>
1574 Pic.End_Float := Index;
1575 Inserts := True;
1576 Skip;
1577
1578 when 'B' | 'b' =>
1579 Pic.Picture.Expanded (Index) := 'b';
1580 Pic.End_Float := Index;
1581 Inserts := True;
1582 Skip;
1583
1584 when 'Z' | 'z' =>
1585 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1586
1587 if Must_Float then
1588 raise Picture_Error;
1589 else
1590 Pic.Max_Leading_Digits := 0;
1591
1592 -- Will overwrite Floater and Start_Float
1593
1594 Zero_Suppression;
1595 end if;
1596
1597 when '*' =>
1598 if Must_Float then
1599 raise Picture_Error;
1600 else
1601 Pic.Max_Leading_Digits := 0;
1602
1603 -- Will overwrite Floater and Start_Float
1604
1605 Star_Suppression;
1606 end if;
1607
1608 when '#' =>
1609 if Inserts then
1610 Must_Float := True;
1611 end if;
1612
1613 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1614 Pic.End_Float := Index;
1615 Pic.End_Currency := Index;
1616 Set_State (Okay);
1617 Skip;
1618
1619 when '9' =>
1620 if State /= Okay then
1621
1622 -- A single '#' doesn't float
1623
1624 Pic.Floater := '!';
1625 Pic.Start_Float := Invalid_Position;
1626 Pic.End_Float := Invalid_Position;
1627 end if;
1628
1629 Number_Completion;
1630 return;
1631
1632 when 'V' | 'v' | '.' =>
1633 if State /= Okay then
1634 Pic.Floater := '!';
1635 Pic.Start_Float := Invalid_Position;
1636 Pic.End_Float := Invalid_Position;
1637 end if;
1638
1639 -- Only one pound before the sign is okay, but doesn't
1640 -- float.
1641
1642 Pic.Radix_Position := Index;
1643 Skip;
1644 Number_Fraction_Or_Pound;
1645 return;
1646
1647 when others =>
1648 return;
1649 end case;
1650 end loop;
1651 end Leading_Pound;
1652
1653 ----------
1654 -- Look --
1655 ----------
1656
1657 function Look return Character is
1658 begin
1659 if At_End then
1660 raise Picture_Error;
1661 end if;
1662
1663 return Pic.Picture.Expanded (Index);
1664 end Look;
1665
1666 ------------
1667 -- Number --
1668 ------------
1669
1670 procedure Number is
1671 begin
1672 loop
1673
1674 case Look is
1675 when '_' | '0' | '/' =>
1676 Skip;
1677
1678 when 'B' | 'b' =>
1679 Pic.Picture.Expanded (Index) := 'b';
1680 Skip;
1681
1682 when '9' =>
1683 Computed_BWZ := False;
1684 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1685 Set_State (Okay);
1686 Skip;
1687
1688 when '.' | 'V' | 'v' =>
1689 Pic.Radix_Position := Index;
1690 Skip;
1691 Number_Fraction;
1692 return;
1693
1694 when others =>
1695 return;
1696
1697 end case;
1698
1699 if At_End then
1700 return;
1701 end if;
1702
1703 -- Will return in Okay state if a '9' was seen
1704
1705 end loop;
1706 end Number;
1707
1708 -----------------------
1709 -- Number_Completion --
1710 -----------------------
1711
1712 procedure Number_Completion is
1713 begin
1714 while not At_End loop
1715 case Look is
1716
1717 when '_' | '0' | '/' =>
1718 Skip;
1719
1720 when 'B' | 'b' =>
1721 Pic.Picture.Expanded (Index) := 'b';
1722 Skip;
1723
1724 when '9' =>
1725 Computed_BWZ := False;
1726 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1727 Set_State (Okay);
1728 Skip;
1729
1730 when 'V' | 'v' | '.' =>
1731 Pic.Radix_Position := Index;
1732 Skip;
1733 Number_Fraction;
1734 return;
1735
1736 when others =>
1737 return;
1738 end case;
1739 end loop;
1740 end Number_Completion;
1741
1742 ---------------------
1743 -- Number_Fraction --
1744 ---------------------
1745
1746 procedure Number_Fraction is
1747 begin
1748 -- Note that number fraction can be called in either State.
1749 -- It will set state to Valid only if a 9 is encountered.
1750
1751 loop
1752 if At_End then
1753 return;
1754 end if;
1755
1756 case Look is
1757 when '_' | '0' | '/' =>
1758 Skip;
1759
1760 when 'B' | 'b' =>
1761 Pic.Picture.Expanded (Index) := 'b';
1762 Skip;
1763
1764 when '9' =>
1765 Computed_BWZ := False;
1766 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1767 Set_State (Okay); Skip;
1768
1769 when others =>
1770 return;
1771 end case;
1772 end loop;
1773 end Number_Fraction;
1774
1775 --------------------------------
1776 -- Number_Fraction_Or_Bracket --
1777 --------------------------------
1778
1779 procedure Number_Fraction_Or_Bracket is
1780 begin
1781 loop
1782 if At_End then
1783 return;
1784 end if;
1785
1786 case Look is
1787
1788 when '_' | '0' | '/' => Skip;
1789
1790 when 'B' | 'b' =>
1791 Pic.Picture.Expanded (Index) := 'b';
1792 Skip;
1793
1794 when '<' =>
1795 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1796 Pic.End_Float := Index;
1797 Skip;
1798
1799 loop
1800 if At_End then
1801 return;
1802 end if;
1803
1804 case Look is
1805 when '_' | '0' | '/' =>
1806 Skip;
1807
1808 when 'B' | 'b' =>
1809 Pic.Picture.Expanded (Index) := 'b';
1810 Skip;
1811
1812 when '<' =>
1813 Pic.Max_Trailing_Digits :=
1814 Pic.Max_Trailing_Digits + 1;
1815 Pic.End_Float := Index;
1816 Skip;
1817
1818 when others =>
1819 return;
1820 end case;
1821 end loop;
1822
1823 when others =>
1824 Number_Fraction;
1825 return;
1826 end case;
1827 end loop;
1828 end Number_Fraction_Or_Bracket;
1829
1830 -------------------------------
1831 -- Number_Fraction_Or_Dollar --
1832 -------------------------------
1833
1834 procedure Number_Fraction_Or_Dollar is
1835 begin
1836 loop
1837 if At_End then
1838 return;
1839 end if;
1840
1841 case Look is
1842 when '_' | '0' | '/' =>
1843 Skip;
1844
1845 when 'B' | 'b' =>
1846 Pic.Picture.Expanded (Index) := 'b';
1847 Skip;
1848
1849 when '$' =>
1850 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1851 Pic.End_Float := Index;
1852 Skip;
1853
1854 loop
1855 if At_End then
1856 return;
1857 end if;
1858
1859 case Look is
1860 when '_' | '0' | '/' =>
1861 Skip;
1862
1863 when 'B' | 'b' =>
1864 Pic.Picture.Expanded (Index) := 'b';
1865 Skip;
1866
1867 when '$' =>
1868 Pic.Max_Trailing_Digits :=
1869 Pic.Max_Trailing_Digits + 1;
1870 Pic.End_Float := Index;
1871 Skip;
1872
1873 when others =>
1874 return;
1875 end case;
1876 end loop;
1877
1878 when others =>
1879 Number_Fraction;
1880 return;
1881 end case;
1882 end loop;
1883 end Number_Fraction_Or_Dollar;
1884
1885 ------------------------------
1886 -- Number_Fraction_Or_Pound --
1887 ------------------------------
1888
1889 procedure Number_Fraction_Or_Pound is
1890 begin
1891 loop
1892 if At_End then
1893 return;
1894 end if;
1895
1896 case Look is
1897
1898 when '_' | '0' | '/' =>
1899 Skip;
1900
1901 when 'B' | 'b' =>
1902 Pic.Picture.Expanded (Index) := 'b';
1903 Skip;
1904
1905 when '#' =>
1906 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1907 Pic.End_Float := Index;
1908 Skip;
1909
1910 loop
1911 if At_End then
1912 return;
1913 end if;
1914
1915 case Look is
1916
1917 when '_' | '0' | '/' =>
1918 Skip;
1919
1920 when 'B' | 'b' =>
1921 Pic.Picture.Expanded (Index) := 'b';
1922 Skip;
1923
1924 when '#' =>
1925 Pic.Max_Trailing_Digits :=
1926 Pic.Max_Trailing_Digits + 1;
1927 Pic.End_Float := Index;
1928 Skip;
1929
1930 when others =>
1931 return;
1932
1933 end case;
1934 end loop;
1935
1936 when others =>
1937 Number_Fraction;
1938 return;
1939
1940 end case;
1941 end loop;
1942 end Number_Fraction_Or_Pound;
1943
1944 ----------------------------------
1945 -- Number_Fraction_Or_Star_Fill --
1946 ----------------------------------
1947
1948 procedure Number_Fraction_Or_Star_Fill is
1949 begin
1950 loop
1951 if At_End then
1952 return;
1953 end if;
1954
1955 case Look is
1956
1957 when '_' | '0' | '/' =>
1958 Skip;
1959
1960 when 'B' | 'b' =>
1961 Pic.Picture.Expanded (Index) := 'b';
1962 Skip;
1963
1964 when '*' =>
1965 Pic.Star_Fill := True;
1966 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
1967 Pic.End_Float := Index;
1968 Skip;
1969
1970 loop
1971 if At_End then
1972 return;
1973 end if;
1974
1975 case Look is
1976
1977 when '_' | '0' | '/' =>
1978 Skip;
1979
1980 when 'B' | 'b' =>
1981 Pic.Picture.Expanded (Index) := 'b';
1982 Skip;
1983
1984 when '*' =>
1985 Pic.Star_Fill := True;
1986 Pic.Max_Trailing_Digits :=
1987 Pic.Max_Trailing_Digits + 1;
1988 Pic.End_Float := Index;
1989 Skip;
1990
1991 when others =>
1992 return;
1993 end case;
1994 end loop;
1995
1996 when others =>
1997 Number_Fraction;
1998 return;
1999
2000 end case;
2001 end loop;
2002 end Number_Fraction_Or_Star_Fill;
2003
2004 -------------------------------
2005 -- Number_Fraction_Or_Z_Fill --
2006 -------------------------------
2007
2008 procedure Number_Fraction_Or_Z_Fill is
2009 begin
2010 loop
2011 if At_End then
2012 return;
2013 end if;
2014
2015 case Look is
2016
2017 when '_' | '0' | '/' =>
2018 Skip;
2019
2020 when 'B' | 'b' =>
2021 Pic.Picture.Expanded (Index) := 'b';
2022 Skip;
2023
2024 when 'Z' | 'z' =>
2025 Pic.Max_Trailing_Digits := Pic.Max_Trailing_Digits + 1;
2026 Pic.End_Float := Index;
2027 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2028
2029 Skip;
2030
2031 loop
2032 if At_End then
2033 return;
2034 end if;
2035
2036 case Look is
2037
2038 when '_' | '0' | '/' =>
2039 Skip;
2040
2041 when 'B' | 'b' =>
2042 Pic.Picture.Expanded (Index) := 'b';
2043 Skip;
2044
2045 when 'Z' | 'z' =>
2046 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2047
2048 Pic.Max_Trailing_Digits :=
2049 Pic.Max_Trailing_Digits + 1;
2050 Pic.End_Float := Index;
2051 Skip;
2052
2053 when others =>
2054 return;
2055 end case;
2056 end loop;
2057
2058 when others =>
2059 Number_Fraction;
2060 return;
2061 end case;
2062 end loop;
2063 end Number_Fraction_Or_Z_Fill;
2064
2065 -----------------------
2066 -- Optional_RHS_Sign --
2067 -----------------------
2068
2069 procedure Optional_RHS_Sign is
2070 begin
2071 if At_End then
2072 return;
2073 end if;
2074
2075 case Look is
2076
2077 when '+' | '-' =>
2078 Pic.Sign_Position := Index;
2079 Skip;
2080 return;
2081
2082 when 'C' | 'c' =>
2083 Pic.Sign_Position := Index;
2084 Pic.Picture.Expanded (Index) := 'C';
2085 Skip;
2086
2087 if Look = 'R' or Look = 'r' then
2088 Pic.Second_Sign := Index;
2089 Pic.Picture.Expanded (Index) := 'R';
2090 Skip;
2091
2092 else
2093 raise Picture_Error;
2094 end if;
2095
2096 return;
2097
2098 when 'D' | 'd' =>
2099 Pic.Sign_Position := Index;
2100 Pic.Picture.Expanded (Index) := 'D';
2101 Skip;
2102
2103 if Look = 'B' or Look = 'b' then
2104 Pic.Second_Sign := Index;
2105 Pic.Picture.Expanded (Index) := 'B';
2106 Skip;
2107
2108 else
2109 raise Picture_Error;
2110 end if;
2111
2112 return;
2113
2114 when '>' =>
2115 if Pic.Picture.Expanded (Pic.Sign_Position) = '<' then
2116 Pic.Second_Sign := Index;
2117 Skip;
2118
2119 else
2120 raise Picture_Error;
2121 end if;
2122
2123 when others =>
2124 return;
2125
2126 end case;
2127 end Optional_RHS_Sign;
2128
2129 -------------
2130 -- Picture --
2131 -------------
2132
2133 -- Note that Picture can be called in either State
2134
2135 -- It will set state to Valid only if a 9 is encountered or floating
2136 -- currency is called.
2137
2138 procedure Picture is
2139 begin
2140 loop
2141 if At_End then
2142 return;
2143 end if;
2144
2145 case Look is
2146
2147 when '_' | '0' | '/' =>
2148 Skip;
2149
2150 when 'B' | 'b' =>
2151 Pic.Picture.Expanded (Index) := 'b';
2152 Skip;
2153
2154 when '$' =>
2155 Leading_Dollar;
2156 return;
2157
2158 when '#' =>
2159 Leading_Pound;
2160 return;
2161
2162 when '9' =>
2163 Computed_BWZ := False;
2164 Set_State (Okay);
2165 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2166 Skip;
2167
2168 when 'V' | 'v' | '.' =>
2169 Pic.Radix_Position := Index;
2170 Skip;
2171 Number_Fraction;
2172 Trailing_Currency;
2173 return;
2174
2175 when others =>
2176 return;
2177
2178 end case;
2179 end loop;
2180 end Picture;
2181
2182 ---------------------
2183 -- Picture_Bracket --
2184 ---------------------
2185
2186 procedure Picture_Bracket is
2187 begin
2188 Pic.Sign_Position := Index;
2189 Pic.Sign_Position := Index;
2190
2191 -- Treat as a floating sign, and unwind otherwise
2192
2193 Pic.Floater := '<';
2194 Pic.Start_Float := Index;
2195 Pic.End_Float := Index;
2196
2197 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2198 -- sign place.
2199
2200 Skip; -- Known Bracket
2201
2202 loop
2203 case Look is
2204
2205 when '_' | '0' | '/' =>
2206 Pic.End_Float := Index;
2207 Skip;
2208
2209 when 'B' | 'b' =>
2210 Pic.End_Float := Index;
2211 Pic.Picture.Expanded (Index) := 'b';
2212 Skip;
2213
2214 when '<' =>
2215 Set_State (Okay); -- "<<>" is enough.
2216 Floating_Bracket;
2217 Trailing_Currency;
2218 Trailing_Bracket;
2219 return;
2220
2221 when '$' | '#' | '9' | '*' =>
2222 if State /= Okay then
2223 Pic.Floater := '!';
2224 Pic.Start_Float := Invalid_Position;
2225 Pic.End_Float := Invalid_Position;
2226 end if;
2227
2228 Picture;
2229 Trailing_Bracket;
2230 Set_State (Okay);
2231 return;
2232
2233 when '.' | 'V' | 'v' =>
2234 if State /= Okay then
2235 Pic.Floater := '!';
2236 Pic.Start_Float := Invalid_Position;
2237 Pic.End_Float := Invalid_Position;
2238 end if;
2239
2240 -- Don't assume that state is okay, haven't seen a digit
2241
2242 Picture;
2243 Trailing_Bracket;
2244 return;
2245
2246 when others =>
2247 raise Picture_Error;
2248
2249 end case;
2250 end loop;
2251 end Picture_Bracket;
2252
2253 -------------------
2254 -- Picture_Minus --
2255 -------------------
2256
2257 procedure Picture_Minus is
2258 begin
2259 Pic.Sign_Position := Index;
2260
2261 -- Treat as a floating sign, and unwind otherwise
2262
2263 Pic.Floater := '-';
2264 Pic.Start_Float := Index;
2265 Pic.End_Float := Index;
2266
2267 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2268 -- sign place.
2269
2270 Skip; -- Known Minus
2271
2272 loop
2273 case Look is
2274
2275 when '_' | '0' | '/' =>
2276 Pic.End_Float := Index;
2277 Skip;
2278
2279 when 'B' | 'b' =>
2280 Pic.End_Float := Index;
2281 Pic.Picture.Expanded (Index) := 'b';
2282 Skip;
2283
2284 when '-' =>
2285 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2286 Pic.End_Float := Index;
2287 Skip;
2288 Set_State (Okay); -- "-- " is enough
2289 Floating_Minus;
2290 Trailing_Currency;
2291 return;
2292
2293 when '$' | '#' | '9' | '*' =>
2294 if State /= Okay then
2295 Pic.Floater := '!';
2296 Pic.Start_Float := Invalid_Position;
2297 Pic.End_Float := Invalid_Position;
2298 end if;
2299
2300 Picture;
2301 Set_State (Okay);
2302 return;
2303
2304 when 'Z' | 'z' =>
2305
2306 -- Can't have Z and a floating sign
2307
2308 if State = Okay then
2309 Set_State (Reject);
2310 end if;
2311
2312 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2313 Zero_Suppression;
2314 Trailing_Currency;
2315 Optional_RHS_Sign;
2316 return;
2317
2318 when '.' | 'V' | 'v' =>
2319 if State /= Okay then
2320 Pic.Floater := '!';
2321 Pic.Start_Float := Invalid_Position;
2322 Pic.End_Float := Invalid_Position;
2323 end if;
2324
2325 -- Don't assume that state is okay, haven't seen a digit
2326
2327 Picture;
2328 return;
2329
2330 when others =>
2331 return;
2332
2333 end case;
2334 end loop;
2335 end Picture_Minus;
2336
2337 ------------------
2338 -- Picture_Plus --
2339 ------------------
2340
2341 procedure Picture_Plus is
2342 begin
2343 Pic.Sign_Position := Index;
2344
2345 -- Treat as a floating sign, and unwind otherwise
2346
2347 Pic.Floater := '+';
2348 Pic.Start_Float := Index;
2349 Pic.End_Float := Index;
2350
2351 -- Don't increment Pic.Max_Leading_Digits, we need one "real"
2352 -- sign place.
2353
2354 Skip; -- Known Plus
2355
2356 loop
2357 case Look is
2358
2359 when '_' | '0' | '/' =>
2360 Pic.End_Float := Index;
2361 Skip;
2362
2363 when 'B' | 'b' =>
2364 Pic.End_Float := Index;
2365 Pic.Picture.Expanded (Index) := 'b';
2366 Skip;
2367
2368 when '+' =>
2369 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2370 Pic.End_Float := Index;
2371 Skip;
2372 Set_State (Okay); -- "++" is enough
2373 Floating_Plus;
2374 Trailing_Currency;
2375 return;
2376
2377 when '$' | '#' | '9' | '*' =>
2378 if State /= Okay then
2379 Pic.Floater := '!';
2380 Pic.Start_Float := Invalid_Position;
2381 Pic.End_Float := Invalid_Position;
2382 end if;
2383
2384 Picture;
2385 Set_State (Okay);
2386 return;
2387
2388 when 'Z' | 'z' =>
2389 if State = Okay then
2390 Set_State (Reject);
2391 end if;
2392
2393 -- Can't have Z and a floating sign
2394
2395 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2396
2397 -- '+Z' is acceptable
2398
2399 Set_State (Okay);
2400
2401 Zero_Suppression;
2402 Trailing_Currency;
2403 Optional_RHS_Sign;
2404 return;
2405
2406 when '.' | 'V' | 'v' =>
2407 if State /= Okay then
2408 Pic.Floater := '!';
2409 Pic.Start_Float := Invalid_Position;
2410 Pic.End_Float := Invalid_Position;
2411 end if;
2412
2413 -- Don't assume that state is okay, haven't seen a digit
2414
2415 Picture;
2416 return;
2417
2418 when others =>
2419 return;
2420
2421 end case;
2422 end loop;
2423 end Picture_Plus;
2424
2425 --------------------
2426 -- Picture_String --
2427 --------------------
2428
2429 procedure Picture_String is
2430 begin
2431 while Is_Insert loop
2432 Skip;
2433 end loop;
2434
2435 case Look is
2436
2437 when '$' | '#' =>
2438 Picture;
2439 Optional_RHS_Sign;
2440
2441 when '+' =>
2442 Picture_Plus;
2443
2444 when '-' =>
2445 Picture_Minus;
2446
2447 when '<' =>
2448 Picture_Bracket;
2449
2450 when 'Z' | 'z' =>
2451 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2452 Zero_Suppression;
2453 Trailing_Currency;
2454 Optional_RHS_Sign;
2455
2456 when '*' =>
2457 Star_Suppression;
2458 Trailing_Currency;
2459 Optional_RHS_Sign;
2460
2461 when '9' | '.' | 'V' | 'v' =>
2462 Number;
2463 Trailing_Currency;
2464 Optional_RHS_Sign;
2465
2466 when others =>
2467 raise Picture_Error;
2468
2469 end case;
2470
2471 -- Blank when zero either if the PIC does not contain a '9' or if
2472 -- requested by the user and no '*'
2473
2474 Pic.Blank_When_Zero :=
2475 (Computed_BWZ or Pic.Blank_When_Zero) and not Pic.Star_Fill;
2476
2477 -- Star fill if '*' and no '9'
2478
2479 Pic.Star_Fill := Pic.Star_Fill and Computed_BWZ;
2480
2481 if not At_End then
2482 Set_State (Reject);
2483 end if;
2484
2485 end Picture_String;
2486
2487 ---------------
2488 -- Set_State --
2489 ---------------
2490
2491 procedure Set_State (L : Legality) is
2492 begin
2493 State := L;
2494 end Set_State;
2495
2496 ----------
2497 -- Skip --
2498 ----------
2499
2500 procedure Skip is
2501 begin
2502 Index := Index + 1;
2503 end Skip;
2504
2505 ----------------------
2506 -- Star_Suppression --
2507 ----------------------
2508
2509 procedure Star_Suppression is
2510 begin
2511 Pic.Floater := '*';
2512 Pic.Start_Float := Index;
2513 Pic.End_Float := Index;
2514 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2515 Set_State (Okay);
2516
2517 -- Even a single * is a valid picture
2518
2519 Pic.Star_Fill := True;
2520 Skip; -- Known *
2521
2522 loop
2523 if At_End then
2524 return;
2525 end if;
2526
2527 case Look is
2528
2529 when '_' | '0' | '/' =>
2530 Pic.End_Float := Index;
2531 Skip;
2532
2533 when 'B' | 'b' =>
2534 Pic.End_Float := Index;
2535 Pic.Picture.Expanded (Index) := 'b';
2536 Skip;
2537
2538 when '*' =>
2539 Pic.End_Float := Index;
2540 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2541 Set_State (Okay); Skip;
2542
2543 when '9' =>
2544 Set_State (Okay);
2545 Number_Completion;
2546 return;
2547
2548 when '.' | 'V' | 'v' =>
2549 Pic.Radix_Position := Index;
2550 Skip;
2551 Number_Fraction_Or_Star_Fill;
2552 return;
2553
2554 when '#' | '$' =>
2555 Trailing_Currency;
2556 Set_State (Okay);
2557 return;
2558
2559 when others => raise Picture_Error;
2560 end case;
2561 end loop;
2562 end Star_Suppression;
2563
2564 ----------------------
2565 -- Trailing_Bracket --
2566 ----------------------
2567
2568 procedure Trailing_Bracket is
2569 begin
2570 if Look = '>' then
2571 Pic.Second_Sign := Index;
2572 Skip;
2573 else
2574 raise Picture_Error;
2575 end if;
2576 end Trailing_Bracket;
2577
2578 -----------------------
2579 -- Trailing_Currency --
2580 -----------------------
2581
2582 procedure Trailing_Currency is
2583 begin
2584 if At_End then
2585 return;
2586 end if;
2587
2588 if Look = '$' then
2589 Pic.Start_Currency := Index;
2590 Pic.End_Currency := Index;
2591 Skip;
2592
2593 else
2594 while not At_End and then Look = '#' loop
2595 if Pic.Start_Currency = Invalid_Position then
2596 Pic.Start_Currency := Index;
2597 end if;
2598
2599 Pic.End_Currency := Index;
2600 Skip;
2601 end loop;
2602 end if;
2603
2604 loop
2605 if At_End then
2606 return;
2607 end if;
2608
2609 case Look is
2610 when '_' | '0' | '/' => Skip;
2611
2612 when 'B' | 'b' =>
2613 Pic.Picture.Expanded (Index) := 'b';
2614 Skip;
2615
2616 when others => return;
2617 end case;
2618 end loop;
2619 end Trailing_Currency;
2620
2621 ----------------------
2622 -- Zero_Suppression --
2623 ----------------------
2624
2625 procedure Zero_Suppression is
2626 begin
2627 Pic.Floater := 'Z';
2628 Pic.Start_Float := Index;
2629 Pic.End_Float := Index;
2630 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2631 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2632
2633 Skip; -- Known Z
2634
2635 loop
2636 -- Even a single Z is a valid picture
2637
2638 if At_End then
2639 Set_State (Okay);
2640 return;
2641 end if;
2642
2643 case Look is
2644 when '_' | '0' | '/' =>
2645 Pic.End_Float := Index;
2646 Skip;
2647
2648 when 'B' | 'b' =>
2649 Pic.End_Float := Index;
2650 Pic.Picture.Expanded (Index) := 'b';
2651 Skip;
2652
2653 when 'Z' | 'z' =>
2654 Pic.Picture.Expanded (Index) := 'Z'; -- consistency
2655
2656 Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
2657 Pic.End_Float := Index;
2658 Set_State (Okay);
2659 Skip;
2660
2661 when '9' =>
2662 Set_State (Okay);
2663 Number_Completion;
2664 return;
2665
2666 when '.' | 'V' | 'v' =>
2667 Pic.Radix_Position := Index;
2668 Skip;
2669 Number_Fraction_Or_Z_Fill;
2670 return;
2671
2672 when '#' | '$' =>
2673 Trailing_Currency;
2674 Set_State (Okay);
2675 return;
2676
2677 when others =>
2678 return;
2679 end case;
2680 end loop;
2681 end Zero_Suppression;
2682
2683 -- Start of processing for Precalculate
2684
2685 begin
2686 Picture_String;
2687
2688 if State = Reject then
2689 raise Picture_Error;
2690 end if;
2691
2692 exception
2693
2694 when Constraint_Error =>
2695
2696 -- To deal with special cases like null strings
2697
2698 raise Picture_Error;
2699
2700 end Precalculate;
2701
2702 ----------------
2703 -- To_Picture --
2704 ----------------
2705
2706 function To_Picture
2707 (Pic_String : String;
2708 Blank_When_Zero : Boolean := False) return Picture
2709 is
2710 Result : Picture;
2711
2712 begin
2713 declare
2714 Item : constant String := Expand (Pic_String);
2715
2716 begin
2717 Result.Contents.Picture := (Item'Length, Item);
2718 Result.Contents.Original_BWZ := Blank_When_Zero;
2719 Result.Contents.Blank_When_Zero := Blank_When_Zero;
2720 Precalculate (Result.Contents);
2721 return Result;
2722 end;
2723
2724 exception
2725 when others =>
2726 raise Picture_Error;
2727
2728 end To_Picture;
2729
2730 -------------
2731 -- To_Wide --
2732 -------------
2733
2734 function To_Wide (C : Character) return Wide_Character is
2735 begin
2736 return Wide_Character'Val (Character'Pos (C));
2737 end To_Wide;
2738
2739 -----------
2740 -- Valid --
2741 -----------
2742
2743 function Valid
2744 (Pic_String : String;
2745 Blank_When_Zero : Boolean := False) return Boolean
2746 is
2747 begin
2748 declare
2749 Expanded_Pic : constant String := Expand (Pic_String);
2750 -- Raises Picture_Error if Item not well-formed
2751
2752 Format_Rec : Format_Record;
2753
2754 begin
2755 Format_Rec.Picture := (Expanded_Pic'Length, Expanded_Pic);
2756 Format_Rec.Blank_When_Zero := Blank_When_Zero;
2757 Format_Rec.Original_BWZ := Blank_When_Zero;
2758 Precalculate (Format_Rec);
2759
2760 -- False only if Blank_When_0 is True but the pic string has a '*'
2761
2762 return not Blank_When_Zero
2763 or else Strings_Fixed.Index (Expanded_Pic, "*") = 0;
2764 end;
2765
2766 exception
2767 when others => return False;
2768 end Valid;
2769
2770 end Ada.Wide_Text_IO.Editing;