OSDN Git Service

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