OSDN Git Service

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