OSDN Git Service

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