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-wtedit.adb < prev    next >
Text File  |  2000-07-19  |  77KB  |  2,787 lines

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