home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / a-teioed.adb < prev    next >
Text File  |  2000-07-19  |  78KB  |  2,831 lines

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