OSDN Git Service

PR c++/27714
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-ztedit.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                        GNAT RUN-TIME COMPONENTS                          --
4 --                                                                          --
5 --        A D A . W I D E _ 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-2006, 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_Wide_Fixed;
36
37 package body Ada.Wide_Wide_Text_IO.Editing is
38
39    package Strings            renames Ada.Strings;
40    package Strings_Fixed      renames Ada.Strings.Fixed;
41    package Strings_Wide_Wide_Fixed renames Ada.Strings.Wide_Wide_Fixed;
42    package Wide_Wide_Text_IO       renames Ada.Wide_Wide_Text_IO;
43
44    -----------------------
45    -- Local_Subprograms --
46    -----------------------
47
48    function To_Wide (C : Character) return Wide_Wide_Character;
49    pragma Inline (To_Wide);
50    --  Convert Character to corresponding Wide_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_Wide_String    := Default_Currency;
75          Fill       : Wide_Wide_Character := Default_Fill;
76          Separator  : Wide_Wide_Character := Default_Separator;
77          Radix_Mark : Wide_Wide_Character := Default_Radix_Mark)
78          return Wide_Wide_String
79       is
80       begin
81          return Format_Number
82             (Pic.Contents, Num'Image (Item),
83              Currency, Fill, Separator, Radix_Mark);
84       end Image;
85
86       ------------
87       -- Length --
88       ------------
89
90       function Length
91         (Pic      : Picture;
92          Currency : Wide_Wide_String := Default_Currency) return Natural
93       is
94          Picstr     : constant String := Pic_String (Pic);
95          V_Adjust   : Integer := 0;
96          Cur_Adjust : Integer := 0;
97
98       begin
99          --  Check if Picstr has 'V' or '$'
100
101          --  If 'V', then length is 1 less than otherwise
102
103          --  If '$', then length is Currency'Length-1 more than otherwise
104
105          --  This should use the string handling package ???
106
107          for J in Picstr'Range loop
108             if Picstr (J) = 'V' then
109                V_Adjust := -1;
110
111             elsif Picstr (J) = '$' then
112                Cur_Adjust := Currency'Length - 1;
113             end if;
114          end loop;
115
116          return Picstr'Length - V_Adjust + Cur_Adjust;
117       end Length;
118
119       ---------
120       -- Put --
121       ---------
122
123       procedure Put
124         (File       : Wide_Wide_Text_IO.File_Type;
125          Item       : Num;
126          Pic        : Picture;
127          Currency   : Wide_Wide_String    := Default_Currency;
128          Fill       : Wide_Wide_Character := Default_Fill;
129          Separator  : Wide_Wide_Character := Default_Separator;
130          Radix_Mark : Wide_Wide_Character := Default_Radix_Mark)
131       is
132       begin
133          Wide_Wide_Text_IO.Put (File, Image (Item, Pic,
134                                    Currency, Fill, Separator, Radix_Mark));
135       end Put;
136
137       procedure Put
138         (Item       : Num;
139          Pic        : Picture;
140          Currency   : Wide_Wide_String    := Default_Currency;
141          Fill       : Wide_Wide_Character := Default_Fill;
142          Separator  : Wide_Wide_Character := Default_Separator;
143          Radix_Mark : Wide_Wide_Character := Default_Radix_Mark)
144       is
145       begin
146          Wide_Wide_Text_IO.Put (Image (Item, Pic,
147                              Currency, Fill, Separator, Radix_Mark));
148       end Put;
149
150       procedure Put
151         (To         : out Wide_Wide_String;
152          Item       : Num;
153          Pic        : Picture;
154          Currency   : Wide_Wide_String    := Default_Currency;
155          Fill       : Wide_Wide_Character := Default_Fill;
156          Separator  : Wide_Wide_Character := Default_Separator;
157          Radix_Mark : Wide_Wide_Character := Default_Radix_Mark)
158       is
159          Result : constant Wide_Wide_String :=
160            Image (Item, Pic, Currency, Fill, Separator, Radix_Mark);
161
162       begin
163          if Result'Length > To'Length then
164             raise Wide_Wide_Text_IO.Layout_Error;
165          else
166             Strings_Wide_Wide_Fixed.Move (Source => Result, Target => To,
167                                      Justify => Strings.Right);
168          end if;
169       end Put;
170
171       -----------
172       -- Valid --
173       -----------
174
175       function Valid
176         (Item     : Num;
177          Pic      : Picture;
178          Currency : Wide_Wide_String := Default_Currency) return Boolean
179       is
180       begin
181          declare
182             Temp : constant Wide_Wide_String := Image (Item, Pic, Currency);
183             pragma Warnings (Off, Temp);
184          begin
185             return True;
186          end;
187
188       exception
189          when Layout_Error => return False;
190
191       end Valid;
192    end Decimal_Output;
193
194    ------------
195    -- Expand --
196    ------------
197
198    function Expand (Picture : String) return String is
199       Result        : String (1 .. MAX_PICSIZE);
200       Picture_Index : Integer := Picture'First;
201       Result_Index  : Integer := Result'First;
202       Count         : Natural;
203       Last          : Integer;
204
205    begin
206       if Picture'Length < 1 then
207          raise Picture_Error;
208       end if;
209
210       if Picture (Picture'First) = '(' then
211          raise Picture_Error;
212       end if;
213
214       loop
215          case Picture (Picture_Index) is
216
217             when '(' =>
218
219                --  We now need to scan out the count after a left paren. In
220                --  the non-wide version we used Integer_IO.Get, but that is
221                --  not convenient here, since we don't want to drag in normal
222                --  Text_IO just for this purpose. So we do the scan ourselves,
223                --  with the normal validity checks.
224
225                Last := Picture_Index + 1;
226                Count := 0;
227
228                if Picture (Last) not in '0' .. '9' then
229                   raise Picture_Error;
230                end if;
231
232                Count := Character'Pos (Picture (Last)) - Character'Pos ('0');
233                Last := Last + 1;
234
235                loop
236                   if Last > Picture'Last then
237                      raise Picture_Error;
238                   end if;
239
240                   if Picture (Last) = '_' then
241                      if Picture (Last - 1) = '_' then
242                         raise Picture_Error;
243                      end if;
244
245                   elsif Picture (Last) = ')' then
246                      exit;
247
248                   elsif Picture (Last) not in '0' .. '9' then
249                      raise Picture_Error;
250
251                   else
252                      Count := Count * 10
253                                 +  Character'Pos (Picture (Last)) -
254                                    Character'Pos ('0');
255                   end if;
256
257                   Last := Last + 1;
258                end loop;
259
260                --  In what follows note that one copy of the repeated
261                --  character has already been made, so a count of one is
262                --  no-op, and a count of zero erases a character.
263
264                for J in 2 .. Count loop
265                   Result (Result_Index + J - 2) := Picture (Picture_Index - 1);
266                end loop;
267
268                Result_Index := Result_Index + Count - 1;
269
270                --  Last was a ')' throw it away too
271
272                Picture_Index := Last + 1;
273
274             when ')' =>
275                raise Picture_Error;
276
277             when others =>
278                Result (Result_Index) := Picture (Picture_Index);
279                Picture_Index := Picture_Index + 1;
280                Result_Index := Result_Index + 1;
281
282          end case;
283
284          exit when Picture_Index > Picture'Last;
285       end loop;
286
287       return Result (1 .. Result_Index - 1);
288
289    exception
290       when others =>
291          raise Picture_Error;
292    end Expand;
293
294    -------------------
295    -- Format_Number --
296    -------------------
297
298    function Format_Number
299      (Pic                 : Format_Record;
300       Number              : String;
301       Currency_Symbol     : Wide_Wide_String;
302       Fill_Character      : Wide_Wide_Character;
303       Separator_Character : Wide_Wide_Character;
304       Radix_Point         : Wide_Wide_Character) return Wide_Wide_String
305    is
306       Attrs    : Number_Attributes := Parse_Number_String (Number);
307       Position : Integer;
308       Rounded  : String := Number;
309
310       Sign_Position : Integer := Pic.Sign_Position; --  may float.
311
312       Answer       : Wide_Wide_String (1 .. Pic.Picture.Length);
313       Last         : Integer;
314       Currency_Pos : Integer := Pic.Start_Currency;
315
316       Dollar : Boolean := False;
317       --  Overridden immediately if necessary
318
319       Zero : Boolean := True;
320       --  Set to False when a non-zero digit is output
321
322    begin
323
324       --  If the picture has fewer decimal places than the number, the image
325       --  must be rounded according to the usual rules.
326
327       if Attrs.Has_Fraction then
328          declare
329             R : constant Integer :=
330               (Attrs.End_Of_Fraction - Attrs.Start_Of_Fraction + 1)
331                 - Pic.Max_Trailing_Digits;
332             R_Pos : Integer;
333
334          begin
335             if R > 0 then
336                R_Pos := Rounded'Length - R;
337
338                if Rounded (R_Pos + 1) > '4' then
339
340                   if Rounded (R_Pos) = '.' then
341                      R_Pos := R_Pos - 1;
342                   end if;
343
344                   if Rounded (R_Pos) /= '9' then
345                      Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
346                   else
347                      Rounded (R_Pos) := '0';
348                      R_Pos := R_Pos - 1;
349
350                      while R_Pos > 1 loop
351                         if Rounded (R_Pos) = '.' then
352                            R_Pos := R_Pos - 1;
353                         end if;
354
355                         if Rounded (R_Pos) /= '9' then
356                            Rounded (R_Pos) := Character'Succ (Rounded (R_Pos));
357                            exit;
358                         else
359                            Rounded (R_Pos) := '0';
360                            R_Pos := R_Pos - 1;
361                         end if;
362                      end loop;
363
364                      --  The rounding may add a digit in front. Either the
365                      --  leading blank or the sign (already captured) can be
366                      --  overwritten.
367
368                      if R_Pos = 1 then
369                         Rounded (R_Pos) := '1';
370                         Attrs.Start_Of_Int := Attrs.Start_Of_Int - 1;
371                      end if;
372                   end if;
373                end if;
374             end if;
375          end;
376       end if;
377
378       for J in Answer'Range loop
379          Answer (J) := To_Wide (Pic.Picture.Expanded (J));
380       end loop;
381
382       if Pic.Start_Currency /= Invalid_Position then
383          Dollar := Answer (Pic.Start_Currency) = '$';
384       end if;
385
386       --  Fix up "direct inserts" outside the playing field. Set up as one
387       --  loop to do the beginning, one (reverse) loop to do the end.
388
389       Last := 1;
390       loop
391          exit when Last = Pic.Start_Float;
392          exit when Last = Pic.Radix_Position;
393          exit when Answer (Last) = '9';
394
395          case Answer (Last) is
396
397             when '_' =>
398                Answer (Last) := Separator_Character;
399
400             when 'b' =>
401                Answer (Last) := ' ';
402
403             when others =>
404                null;
405
406          end case;
407
408          exit when Last = Answer'Last;
409
410          Last := Last + 1;
411       end loop;
412
413       --  Now for the end...
414
415       for J in reverse Last .. Answer'Last loop
416          exit when J = Pic.Radix_Position;
417
418          --  Do this test First, Separator_Character can equal Pic.Floater
419
420          if Answer (J) = Pic.Floater then
421             exit;
422          end if;
423
424          case Answer (J) is
425
426             when '_' =>
427                Answer (J) := Separator_Character;
428
429             when 'b' =>
430                Answer (J) := ' ';
431
432             when '9' =>
433                exit;
434
435             when others =>
436                null;
437
438          end case;
439       end loop;
440
441       --  Non-floating sign
442
443       if Pic.Start_Currency /= -1
444         and then Answer (Pic.Start_Currency) = '#'
445         and then Pic.Floater /= '#'
446       then
447          if Currency_Symbol'Length >
448             Pic.End_Currency - Pic.Start_Currency + 1
449          then
450             raise Picture_Error;
451
452          elsif Currency_Symbol'Length =
453             Pic.End_Currency - Pic.Start_Currency + 1
454          then
455             Answer (Pic.Start_Currency .. Pic.End_Currency) :=
456               Currency_Symbol;
457
458          elsif Pic.Radix_Position = Invalid_Position
459            or else Pic.Start_Currency < Pic.Radix_Position
460          then
461             Answer (Pic.Start_Currency .. Pic.End_Currency) :=
462                                                         (others => ' ');
463             Answer (Pic.End_Currency - Currency_Symbol'Length + 1 ..
464                     Pic.End_Currency) := Currency_Symbol;
465
466          else
467             Answer (Pic.Start_Currency .. Pic.End_Currency) :=
468                                                         (others => ' ');
469             Answer (Pic.Start_Currency ..
470                     Pic.Start_Currency + Currency_Symbol'Length - 1) :=
471                                                         Currency_Symbol;
472          end if;
473       end if;
474
475       --  Fill in leading digits
476
477       if Attrs.End_Of_Int - Attrs.Start_Of_Int + 1 >
478                                                 Pic.Max_Leading_Digits
479       then
480          raise Layout_Error;
481       end if;
482
483       if Pic.Radix_Position = Invalid_Position then
484          Position := Answer'Last;
485       else
486          Position := Pic.Radix_Position - 1;
487       end if;
488
489       for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop
490
491          while Answer (Position) /= '9'
492            and Answer (Position) /= Pic.Floater
493          loop
494             if Answer (Position) = '_' then
495                Answer (Position) := Separator_Character;
496
497             elsif Answer (Position) = 'b' then
498                Answer (Position) := ' ';
499             end if;
500
501             Position := Position - 1;
502          end loop;
503
504          Answer (Position) := To_Wide (Rounded (J));
505
506          if Rounded (J) /= '0' then
507             Zero := False;
508          end if;
509
510          Position := Position - 1;
511       end loop;
512
513       --  Do lead float
514
515       if Pic.Start_Float = Invalid_Position then
516
517          --  No leading floats, but need to change '9' to '0', '_' to
518          --  Separator_Character and 'b' to ' '.
519
520          for J in Last .. Position loop
521
522             --  Last set when fixing the "uninteresting" leaders above.
523             --  Don't duplicate the work.
524
525             if Answer (J) = '9' then
526                Answer (J) := '0';
527
528             elsif Answer (J) = '_' then
529                Answer (J) := Separator_Character;
530
531             elsif Answer (J) = 'b' then
532                Answer (J) := ' ';
533
534             end if;
535
536          end loop;
537
538       elsif Pic.Floater = '<'
539               or else
540             Pic.Floater = '+'
541               or else
542             Pic.Floater = '-'
543       then
544          for J in Pic.End_Float .. Position loop --  May be null range
545             if Answer (J) = '9' then
546                Answer (J) := '0';
547
548             elsif Answer (J) = '_' then
549                Answer (J) := Separator_Character;
550
551             elsif Answer (J) = 'b' then
552                Answer (J) := ' ';
553
554             end if;
555          end loop;
556
557          if Position > Pic.End_Float then
558             Position := Pic.End_Float;
559          end if;
560
561          for J in Pic.Start_Float .. Position - 1 loop
562             Answer (J) := ' ';
563          end loop;
564
565          Answer (Position) := Pic.Floater;
566          Sign_Position     := Position;
567
568       elsif Pic.Floater = '$' then
569
570          for J in Pic.End_Float .. Position loop --  May be null range
571             if Answer (J) = '9' then
572                Answer (J) := '0';
573
574             elsif Answer (J) = '_' then
575                Answer (J) := ' ';   --  no separator before leftmost digit
576
577             elsif Answer (J) = 'b' then
578                Answer (J) := ' ';
579             end if;
580          end loop;
581
582          if Position > Pic.End_Float then
583             Position := Pic.End_Float;
584          end if;
585
586          for J in Pic.Start_Float .. Position - 1 loop
587             Answer (J) := ' ';
588          end loop;
589
590          Answer (Position) := Pic.Floater;
591          Currency_Pos      := Position;
592
593       elsif Pic.Floater = '*' then
594
595          for J in Pic.End_Float .. Position loop --  May be null range
596             if Answer (J) = '9' then
597                Answer (J) := '0';
598
599             elsif Answer (J) = '_' then
600                Answer (J) := Separator_Character;
601
602             elsif Answer (J) = 'b' then
603                Answer (J) := '*';
604             end if;
605          end loop;
606
607          if Position > Pic.End_Float then
608             Position := Pic.End_Float;
609          end if;
610
611          for J in Pic.Start_Float .. Position loop
612             Answer (J) := '*';
613          end loop;
614
615       else
616          if Pic.Floater = '#' then
617             Currency_Pos := Currency_Symbol'Length;
618          end if;
619
620          for J in reverse Pic.Start_Float .. Position loop
621             case Answer (J) is
622
623                when '*' =>
624                   Answer (J) := Fill_Character;
625
626                when 'Z' | 'b' | '/' | '0' =>
627                   Answer (J) := ' ';
628
629                when '9' =>
630                   Answer (J) := '0';
631
632                when '.' | 'V' | 'v' | '<' | '$' | '+' | '-' =>
633                   null;
634
635                when '#' =>
636                   if Currency_Pos = 0 then
637                      Answer (J) := ' ';
638                   else
639                      Answer (J)   := Currency_Symbol (Currency_Pos);
640                      Currency_Pos := Currency_Pos - 1;
641                   end if;
642
643                when '_' =>
644
645                   case Pic.Floater is
646
647                      when '*' =>
648                         Answer (J) := Fill_Character;
649
650                      when 'Z' | 'b' =>
651                         Answer (J) := ' ';
652
653                      when '#' =>
654                         if Currency_Pos = 0 then
655                            Answer (J) := ' ';
656
657                         else
658                            Answer (J)   := Currency_Symbol (Currency_Pos);
659                            Currency_Pos := Currency_Pos - 1;
660                         end if;
661
662                      when others =>
663                         null;
664
665                   end case;
666
667                when others =>
668                   null;
669
670             end case;
671          end loop;
672
673          if Pic.Floater = '#' and then Currency_Pos /= 0 then
674             raise Layout_Error;
675          end if;
676       end if;
677
678       --  Do sign
679
680       if Sign_Position = Invalid_Position then
681          if Attrs.Negative then
682             raise Layout_Error;
683          end if;
684
685       else
686          if Attrs.Negative then
687             case Answer (Sign_Position) is
688                when 'C' | 'D' | '-' =>
689                   null;
690
691                when '+' =>
692                   Answer (Sign_Position) := '-';
693
694                when '<' =>
695                   Answer (Sign_Position)   := '(';
696                   Answer (Pic.Second_Sign) := ')';
697
698                when others =>
699                   raise Picture_Error;
700
701             end case;
702
703          else --  positive
704
705             case Answer (Sign_Position) is
706
707                when '-' =>
708                   Answer (Sign_Position) := ' ';
709
710                when '<' | 'C' | 'D' =>
711                   Answer (Sign_Position)   := ' ';
712                   Answer (Pic.Second_Sign) := ' ';
713
714                when '+' =>
715                   null;
716
717                when others =>
718                   raise Picture_Error;
719
720             end case;
721          end if;
722       end if;
723
724       --  Fill in trailing digits
725
726       if Pic.Max_Trailing_Digits > 0 then
727
728          if Attrs.Has_Fraction then
729             Position := Attrs.Start_Of_Fraction;
730             Last     := Pic.Radix_Position + 1;
731
732             for J in Last .. Answer'Last loop
733
734                if Answer (J) = '9' or Answer (J) = Pic.Floater then
735                   Answer (J) := To_Wide (Rounded (Position));
736
737                   if Rounded (Position) /= '0' then
738                      Zero := False;
739                   end if;
740
741                   Position := Position + 1;
742                   Last     := J + 1;
743
744                   --  Used up fraction but remember place in Answer
745
746                   exit when Position > Attrs.End_Of_Fraction;
747
748                elsif Answer (J) = 'b' then
749                   Answer (J) := ' ';
750
751                elsif Answer (J) = '_' then
752                   Answer (J) := Separator_Character;
753
754                end if;
755
756                Last := J + 1;
757             end loop;
758
759             Position := Last;
760
761          else
762             Position := Pic.Radix_Position + 1;
763          end if;
764
765          --  Now fill remaining 9's with zeros and _ with separators
766
767          Last := Answer'Last;
768
769          for J in Position .. Last loop
770             if Answer (J) = '9' then
771                Answer (J) := '0';
772
773             elsif Answer (J) = Pic.Floater then
774                Answer (J) := '0';
775
776             elsif Answer (J) = '_' then
777                Answer (J) := Separator_Character;
778
779             elsif Answer (J) = 'b' then
780                Answer (J) := ' ';
781
782             end if;
783          end loop;
784
785          Position := Last + 1;
786
787       else
788          if Pic.Floater = '#' and then Currency_Pos /= 0 then
789             raise Layout_Error;
790          end if;
791
792          --  No trailing digits, but now J may need to stick in a currency
793          --  symbol or sign.
794
795          if Pic.Start_Currency = Invalid_Position then
796             Position := Answer'Last + 1;
797          else
798             Position := Pic.Start_Currency;
799          end if;
800       end if;
801
802       for J in Position .. Answer'Last loop
803
804          if Pic.Start_Currency /= Invalid_Position and then
805             Answer (Pic.Start_Currency) = '#' then
806             Currency_Pos := 1;
807          end if;
808
809          --  Note: There are some weird cases J can imagine with 'b' or '#'
810          --  in currency strings where the following code will cause
811          --  glitches. The trick is to tell when the character in the
812          --  answer should be checked, and when to look at the original
813          --  string. Some other time. RIE 11/26/96 ???
814
815          case Answer (J) is
816             when '*' =>
817                Answer (J) := Fill_Character;
818
819             when 'b' =>
820                Answer (J) := ' ';
821
822             when '#' =>
823                if Currency_Pos > Currency_Symbol'Length then
824                   Answer (J) := ' ';
825
826                else
827                   Answer (J)   := Currency_Symbol (Currency_Pos);
828                   Currency_Pos := Currency_Pos + 1;
829                end if;
830
831             when '_' =>
832
833                case Pic.Floater is
834
835                   when '*' =>
836                      Answer (J) := Fill_Character;
837
838                   when 'Z' | 'z' =>
839                      Answer (J) := ' ';
840
841                   when '#' =>
842                      if Currency_Pos > Currency_Symbol'Length then
843                         Answer (J) := ' ';
844                      else
845                         Answer (J)   := Currency_Symbol (Currency_Pos);
846                         Currency_Pos := Currency_Pos + 1;
847                      end if;
848
849                   when others =>
850                      null;
851
852                end case;
853
854             when others =>
855                exit;
856
857          end case;
858       end loop;
859
860       --  Now get rid of Blank_when_Zero and complete Star fill
861
862       if Zero and Pic.Blank_When_Zero then
863
864          --  Value is zero, and blank it
865
866          Last := Answer'Last;
867
868          if Dollar then
869             Last := Last - 1 + Currency_Symbol'Length;
870          end if;
871
872          if Pic.Radix_Position /= Invalid_Position and then
873             Answer (Pic.Radix_Position) = 'V' then
874             Last := Last - 1;
875          end if;
876
877          return Wide_Wide_String'(1 .. Last => ' ');
878
879       elsif Zero and Pic.Star_Fill then
880          Last := Answer'Last;
881
882          if Dollar then
883             Last := Last - 1 + Currency_Symbol'Length;
884          end if;
885
886          if Pic.Radix_Position /= Invalid_Position then
887
888             if Answer (Pic.Radix_Position) = 'V' then
889                Last := Last - 1;
890
891             elsif Dollar then
892                if Pic.Radix_Position > Pic.Start_Currency then
893                   return
894                      Wide_Wide_String'(1 .. Pic.Radix_Position - 1 => '*') &
895                      Radix_Point &
896                      Wide_Wide_String'(Pic.Radix_Position + 1 .. Last => '*');
897
898                else
899                   return
900                      Wide_Wide_String'
901                      (1 ..
902                       Pic.Radix_Position + Currency_Symbol'Length - 2
903                                              => '*') &
904                      Radix_Point &
905                      Wide_Wide_String'
906                        (Pic.Radix_Position + Currency_Symbol'Length .. Last
907                                              => '*');
908                end if;
909
910             else
911                return
912                  Wide_Wide_String'(1 .. Pic.Radix_Position - 1 => '*') &
913                  Radix_Point &
914                  Wide_Wide_String'(Pic.Radix_Position + 1 .. Last => '*');
915             end if;
916          end if;
917
918          return Wide_Wide_String'(1 .. Last => '*');
919       end if;
920
921       --  This was once a simple return statement, now there are nine
922       --  different return cases.  Not to mention the five above to deal
923       --  with zeros.  Why not split things out?
924
925       --  Processing the radix and sign expansion separately
926       --  would require lots of copying--the string and some of its
927       --  indicies--without really simplifying the logic.  The cases are:
928
929       --  1) Expand $, replace '.' with Radix_Point
930       --  2) No currency expansion, replace '.' with Radix_Point
931       --  3) Expand $, radix blanked
932       --  4) No currency expansion, radix blanked
933       --  5) Elide V
934       --  6) Expand $, Elide V
935       --  7) Elide V, Expand $ (Two cases depending on order.)
936       --  8) No radix, expand $
937       --  9) No radix, no currency expansion
938
939       if Pic.Radix_Position /= Invalid_Position then
940
941          if Answer (Pic.Radix_Position) = '.' then
942             Answer (Pic.Radix_Position) := Radix_Point;
943
944             if Dollar then
945
946                --  1) Expand $, replace '.' with Radix_Point
947
948                return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
949                   Answer (Currency_Pos + 1 .. Answer'Last);
950
951             else
952                --  2) No currency expansion, replace '.' with Radix_Point
953
954                return Answer;
955             end if;
956
957          elsif Answer (Pic.Radix_Position) = ' ' then --  blanked radix.
958             if Dollar then
959
960                --  3) Expand $, radix blanked
961
962                return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
963                  Answer (Currency_Pos + 1 .. Answer'Last);
964
965             else
966                --  4) No expansion, radix blanked
967
968                return Answer;
969             end if;
970
971          --  V cases
972
973          else
974             if not Dollar then
975
976                --  5) Elide V
977
978                return Answer (1 .. Pic.Radix_Position - 1) &
979                   Answer (Pic.Radix_Position + 1 .. Answer'Last);
980
981             elsif Currency_Pos < Pic.Radix_Position then
982
983                --  6) Expand $, Elide V
984
985                return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
986                   Answer (Currency_Pos + 1 .. Pic.Radix_Position - 1) &
987                   Answer (Pic.Radix_Position + 1 .. Answer'Last);
988
989             else
990                --  7) Elide V, Expand $
991
992                return Answer (1 .. Pic.Radix_Position - 1) &
993                   Answer (Pic.Radix_Position + 1 .. Currency_Pos - 1) &
994                   Currency_Symbol &
995                   Answer (Currency_Pos + 1 .. Answer'Last);
996             end if;
997          end if;
998
999       elsif Dollar then
1000
1001          --  8) No radix, expand $
1002
1003          return Answer (1 .. Currency_Pos - 1) & Currency_Symbol &
1004             Answer (Currency_Pos + 1 .. Answer'Last);
1005
1006       else
1007          --  9) No radix, no currency expansion
1008
1009          return Answer;
1010       end if;
1011    end Format_Number;
1012
1013    -------------------------
1014    -- Parse_Number_String --
1015    -------------------------
1016
1017    function Parse_Number_String (Str : String) return Number_Attributes is
1018       Answer : Number_Attributes;
1019
1020    begin
1021       for J in Str'Range loop
1022          case Str (J) is
1023
1024             when ' ' =>
1025                null; --  ignore
1026
1027             when '1' .. '9' =>
1028
1029                --  Decide if this is the start of a number.
1030                --  If so, figure out which one...
1031
1032                if Answer.Has_Fraction then
1033                   Answer.End_Of_Fraction := J;
1034                else
1035                   if Answer.Start_Of_Int = Invalid_Position then
1036                      --  start integer
1037                      Answer.Start_Of_Int := J;
1038                   end if;
1039                   Answer.End_Of_Int := J;
1040                end if;
1041
1042             when '0' =>
1043
1044                --  Only count a zero before the decimal point if it follows a
1045                --  non-zero digit.  After the decimal point, zeros will be
1046                --  counted if followed by a non-zero digit.
1047
1048                if not Answer.Has_Fraction then
1049                   if Answer.Start_Of_Int /= Invalid_Position then
1050                      Answer.End_Of_Int := J;
1051                   end if;
1052                end if;
1053
1054             when '-' =>
1055
1056                --  Set negative
1057
1058                Answer.Negative := True;
1059
1060             when '.' =>
1061
1062                --  Close integer, start fraction
1063
1064                if Answer.Has_Fraction then
1065                   raise Picture_Error;
1066                end if;
1067
1068                --  Two decimal points is a no-no
1069
1070                Answer.Has_Fraction    := True;
1071                Answer.End_Of_Fraction := J;
1072
1073                --  Could leave this at Invalid_Position, but this seems the
1074                --  right way to indicate a null range...
1075
1076                Answer.Start_Of_Fraction := J + 1;
1077                Answer.End_Of_Int        := J - 1;
1078
1079             when others =>
1080                raise Picture_Error; -- can this happen? probably not!
1081          end case;
1082       end loop;
1083
1084       if Answer.Start_Of_Int = Invalid_Position then
1085          Answer.Start_Of_Int := Answer.End_Of_Int + 1;
1086       end if;
1087
1088       --  No significant (intger) digits needs a null range
1089
1090       return Answer;
1091    end Parse_Number_String;
1092
1093    ----------------
1094    -- Pic_String --
1095    ----------------
1096
1097    --  The following ensures that we return B and not b being careful not
1098    --  to break things which expect lower case b for blank. See CXF3A02.
1099
1100    function Pic_String (Pic : Picture) return String is
1101       Temp : String (1 .. Pic.Contents.Picture.Length) :=
1102                               Pic.Contents.Picture.Expanded;
1103    begin
1104       for J in Temp'Range loop
1105          if Temp (J) = 'b' then Temp (J) := 'B'; 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. It will set
1422       --  state to Okay only if a 9 or (second) is encountered.
1423
1424       --  Also notice the tricky bit with State and Zero_Suppression.
1425       --  Zero_Suppression is Picture_Error if a '$' or a '9' has been
1426       --  encountered, exactly the cases where State has been set.
1427
1428       procedure Leading_Dollar is
1429       begin
1430          --  Treat as a floating dollar, and unwind otherwise
1431
1432          Pic.Floater := '$';
1433          Pic.Start_Currency := Index;
1434          Pic.End_Currency := Index;
1435          Pic.Start_Float := Index;
1436          Pic.End_Float := Index;
1437
1438          --  Don't increment Pic.Max_Leading_Digits, we need one "real"
1439          --  currency place.
1440
1441          Skip; --  known '$'
1442
1443          loop
1444             if At_End then
1445                return;
1446             end if;
1447
1448             case Look is
1449
1450                when '_' | '0' | '/' =>
1451                   Pic.End_Float := Index;
1452                   Skip;
1453
1454                   --  A trailing insertion character is not part of the
1455                   --  floating currency, so need to look ahead.
1456
1457                   if Look /= '$' then
1458                      Pic.End_Float := Pic.End_Float - 1;
1459                   end if;
1460
1461                when 'B' | 'b'  =>
1462                   Pic.End_Float := Index;
1463                   Pic.Picture.Expanded (Index) := 'b';
1464                   Skip;
1465
1466                when 'Z' | 'z' =>
1467                   Pic.Picture.Expanded (Index) := 'Z'; -- consistency
1468
1469                   if State = Okay then
1470                      raise Picture_Error;
1471                   else
1472                      --  Will overwrite Floater and Start_Float
1473
1474                      Zero_Suppression;
1475                   end if;
1476
1477                when '*' =>
1478                   if State = Okay then
1479                      raise Picture_Error;
1480                   else
1481                      --  Will overwrite Floater and Start_Float
1482
1483                      Star_Suppression;
1484                   end if;
1485
1486                when '$' =>
1487                   Pic.Max_Leading_Digits := Pic.Max_Leading_Digits + 1;
1488                   Pic.End_Float := Index;
1489                   Pic.End_Currency := Index;
1490                   Set_State (Okay); Skip;
1491
1492                when '9' =>
1493                   if State /= Okay then
1494                      Pic.Floater := '!';
1495                      Pic.Start_Float := Invalid_Position;
1496                      Pic.End_Float := Invalid_Position;
1497                   end if;
1498
1499                   --  A single dollar does not a floating make
1500
1501                   Number_Completion;
1502                   return;
1503
1504                when 'V' | 'v' | '.' =>
1505                   if State /= Okay then
1506                      Pic.Floater := '!';
1507                      Pic.Start_Float := Invalid_Position;
1508                      Pic.End_Float := Invalid_Position;
1509                   end if;
1510
1511                   --  Only one dollar before the sign is okay, but doesn't
1512                   --  float.
1513
1514                   Pic.Radix_Position := Index;
1515                   Skip;
1516                   Number_Fraction_Or_Dollar;
1517                   return;
1518
1519                when others =>
1520                   return;
1521
1522             end case;
1523          end loop;
1524       end Leading_Dollar;
1525
1526       -------------------
1527       -- Leading_Pound --
1528       -------------------
1529
1530       --  This one is complex!  A Leading_Pound can be fixed or floating,
1531       --  but in some cases the decision has to be deferred until we leave
1532       --  this procedure.  Also note that Leading_Pound can be called in
1533       --  either State.
1534
1535       --  It will set state to Okay only if a 9 or (second) # is 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_Wide_Character is
2735    begin
2736       return Wide_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_Wide_Text_IO.Editing;