with --ARM_Output,
     --ARM_Contents,
     --Ada.Text_IO,
     Ada.Exceptions,
     Ada.Strings.Fixed,
     Ada.Strings.Maps;
package body ARM_Corr is

    --
    -- Ada reference manual formatter (ARM_Form).
    --
    -- This package defines the text output object.
    -- Output objects are responsible for implementing the details of
    -- a particular format.
    --
    -- ---------------------------------------
    -- Copyright 2000, 2002, 2004, 2005, 2006, 2007, 2011, 2012
    --   AXE Consultants. All rights reserved.
    -- P.O. Box 1512, Madison WI  53701
    -- E-Mail: randy@rrsoftware.com
    --
    -- ARM_Form is free software: you can redistribute it and/or modify
    -- it under the terms of the GNU General Public License version 3
    -- as published by the Free Software Foundation.
    --
    -- AXE CONSULTANTS MAKES THIS TOOL AND SOURCE CODE AVAILABLE ON AN "AS IS"
    -- BASIS AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE ACCURACY,
    -- CAPABILITY, EFFICIENCY, MERCHANTABILITY, OR FUNCTIONING OF THIS TOOL.
    -- IN NO EVENT WILL AXE CONSULTANTS BE LIABLE FOR ANY GENERAL,
    -- CONSEQUENTIAL, INDIRECT, INCIDENTAL, EXEMPLARY, OR SPECIAL DAMAGES,
    -- EVEN IF AXE CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    -- DAMAGES.
    --
    -- A copy of the GNU General Public License is available in the file
    -- gpl-3-0.txt in the standard distribution of the ARM_Form tool.
    -- Otherwise, see <http://www.gnu.org/licenses/>.
    --
    -- If the GPLv3 license is not satisfactory for your needs, a commercial
    -- use license is available for this tool. Contact Randy at AXE Consultants
    -- for more information.
    --
    -- ---------------------------------------
    --
    -- Edit History:
    --
    --  6/ 2/05 - RLB - Created package from text and HTML versions.
    --  1/11/06 - RLB - Eliminated dispatching Create in favor of tailored
    --                  versions.
    --  1/18/06 - RLB - Added additional styles.
    --  2/ 8/06 - RLB - Added additional parameters to the table command.
    --  2/10/06 - RLB - Added even more additional parameters to the
    --                  table command.
    --          - RLB - Added picture command.
    --  9/22/06 - RLB - Added missing with.
    --  9/25/06 - RLB - Handled optional renaming of TOC.
    --          - RLB - Added Last_Column_Width to Start_Table.
    -- 10/13/06 - RLB - Added Local_Link_Start and Local_Link_End to allow
    --                  formatting in the linked text.
    --  2/ 9/07 - RLB - Changed comments on AI_Reference.
    --  2/13/07 - RLB - Revised to separate style and indent information
    --                  for paragraphs.
    -- 12/18/07 - RLB - Added Plain_Annex.
    -- 12/19/07 - RLB - Added limited colors to Text_Format.
    -- 10/18/11 - RLB - Changed to GPLv3 license.
    -- 10/25/11 - RLB - Added old insertion version to Revised_Clause_Header.
    --  8/31/12 - RLB - Added Output_Path.
    -- 10/18/12 - RLB - Added additional hanging styles.
    -- 11/26/12 - RLB - Added subdivision names to Clause_Header and
    --                  Revised_Clause_Header.

    LINE_LENGTH : constant := 78;
        -- Maximum intended line length.

    Special_Set : constant Ada.Strings.Maps.Character_Set :=
         Ada.Strings.Maps."or" (Ada.Strings.Maps.To_Set ('>'),
           Ada.Strings.Maps.To_Set ('@'));

    procedure Create (Output_Object : in out Corr_Output_Type;
                      File_Prefix : in String;
                      Output_Path : in String;
                      Title : in String := "") is
        -- Create an Output_Object for a document.
        -- The prefix of the output file names is File_Prefix - this
        -- should be no more then 5 characters allowed in file names.
        -- The result files will be written to Output_Path.
        -- The title of the document is Title.
    begin
        if Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Already valid object");
        end if;
        Output_Object.Is_Valid := True;
        Ada.Strings.Fixed.Move (Target => Output_Object.File_Prefix,
                                Source => File_Prefix);
        Ada.Strings.Fixed.Move (Target => Output_Object.Output_Path,
                                Source => Output_Path);
        Output_Object.Output_Path_Len := Output_Path'Length;
        -- We don't use the title.
    end Create;


    procedure Close (Output_Object : in out Corr_Output_Type) is
        -- Close an Output_Object. No further output to the object is
        -- allowed after this call.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Ada.Text_IO.Is_Open (Output_Object.Output_File) then
            Ada.Text_IO.Close (Output_Object.Output_File);
        end if;
        Output_Object.Is_Valid := False;
    end Close;


    procedure Section (Output_Object : in out Corr_Output_Type;
                       Section_Title : in String;
                       Section_Name : in String) is
        -- Start a new section. The title is Section_Title (this is
        -- intended for humans). The name is Section_Name (this is
        -- intended to be suitable to be a portion of a file name).
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Section in paragraph");
        end if;
        if Ada.Text_IO.Is_Open (Output_Object.Output_File) then
            Ada.Text_IO.Close (Output_Object.Output_File);
        end if;
        -- Create a new file for this section:
        -- Unix directory separator for Windows and Debian
        Ada.Text_IO.Create (Output_Object.Output_File, Ada.Text_IO.Out_File,
            Output_Object.Output_Path(1..Output_Object.Output_Path_Len) &
                Ada.Strings.Fixed.Trim (Output_Object.File_Prefix, Ada.Strings.Right) &
                "-Corr-" & Section_Name & ".TXT");
        Ada.Text_IO.New_Line (Output_Object.Output_File);
    end Section;


    procedure Set_Columns (Output_Object : in out Corr_Output_Type;
                           Number_of_Columns : in ARM_Output.Column_Count) is
        -- Set the number of columns.
        -- Raises Not_Valid_Error if in a paragraph.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "In paragraph");
        end if;
        -- No columns in text format.
    end Set_Columns;


    procedure Make_Indent (Output_Object : in out Corr_Output_Type) is
        -- Internal:
        -- Output the appropriate indent after a New_Line or Put_Line.
    begin
--Ada.Text_IO.Put_Line("Make_Indent: Amount=" & Natural'Image(Output_Object.Indent_Amount));
        for I in 1 .. Output_Object.Indent_Amount loop
            Ada.Text_IO.Put (Output_Object.Output_File, ' ');
        end loop;
        Output_Object.Char_Count := Output_Object.Indent_Amount;
        Output_Object.Out_Char_Count := Output_Object.Indent_Amount;
        Output_Object.Output_Buffer_Space_Before := False;
    end Make_Indent;


    procedure Spill (Output_Object : in out Corr_Output_Type) is
        -- Internal:
        -- Empty the output buffer in preperation for a New_Line or Put_Line.
    begin
        if Output_Object.Output_Buffer_Space_Before then
            Ada.Text_IO.Put (Output_Object.Output_File, ' ');
            Output_Object.Char_Count := Output_Object.Char_Count + 1; -- Count the space.
            Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + 1; -- Count the space.
        end if;
        if Output_Object.Output_Buffer_Len /= 0 then
            Ada.Text_IO.Put (Output_Object.Output_File,
                Output_Object.Output_Buffer (1 .. Output_Object.Output_Buffer_Len));
--Ada.Text_IO.Put_Line("Spill: Len=" & Natural'Image(Output_Object.Output_Buffer_Len) &
--     " Space added=" &  Boolean'Image(Output_Object.Output_Buffer_Space_Before) & " Text=" &
--     Output_Object.Output_Buffer (1 .. Output_Object.Output_Buffer_Len));
            Output_Object.Output_Buffer_Len := 0;
            Output_Object.Out_Char_Count := Output_Object.Out_Char_Count +
                Output_Object.Output_Buffer_Len;
        end if;
        Output_Object.Output_Buffer_Space_Before := False;
    end Spill;


    procedure Buffer (Output_Object : in out Corr_Output_Type;
                      Char : in Character) is
        -- Internal:
        -- Add Char to the output buffer. Char will *not* be a word break
        -- character.
    begin
        if Output_Object.Output_Buffer_Len = Output_Object.Output_Buffer'Last then
            -- Oops, buffer is full. Spill it, and this character.
--Ada.Text_IO.Put_Line("** Buffer overflow!!");
            Spill (Output_Object);
            Ada.Text_IO.Put (Output_Object.Output_File, Char);
            Output_Object.Char_Count := Output_Object.Char_Count + 1;
            Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + 1;
            return;
        end if;
        Output_Object.Output_Buffer_Len := Output_Object.Output_Buffer_Len + 1;
        Output_Object.Output_Buffer(Output_Object.Output_Buffer_Len) := Char;
        Output_Object.Char_Count := Output_Object.Char_Count + 1;
    end Buffer;


    procedure Buffer (Output_Object : in out Corr_Output_Type;
                      Str : in String) is
        -- Internal:
        -- Add Char to the output buffer. String will *not* include a word
        -- break character.
    begin
        if Output_Object.Output_Buffer_Len+Str'Length >= Output_Object.Output_Buffer'Last then
            -- Oops, buffer is full. Spill it.
--Ada.Text_IO.Put_Line("** Buffer overflow!!");
            Spill (Output_Object);
        end if;
        Output_Object.Output_Buffer(Output_Object.Output_Buffer_Len+1..Output_Object.Output_Buffer_Len+Str'Length)
            := Str;
        Output_Object.Output_Buffer_Len := Output_Object.Output_Buffer_Len + Str'Length;
        Output_Object.Char_Count := Output_Object.Char_Count + Str'Length;
    end Buffer;


    procedure Start_Paragraph (Output_Object : in out Corr_Output_Type;
                               Style     : in ARM_Output.Paragraph_Style_Type;
                               Indent    : in ARM_Output.Paragraph_Indent_Type;
                               Number    : in String;
                               No_Prefix : in Boolean := False;
                               Tab_Stops : in ARM_Output.Tab_Info := ARM_Output.NO_TABS;
                               No_Breaks : in Boolean := False;
                               Keep_with_Next : in Boolean := False;
                               Space_After : in ARM_Output.Space_After_Type
                                   := ARM_Output.Normal;
                               Justification : in ARM_Output.Justification_Type
                                   := ARM_Output.Default) is
        -- Start a new paragraph. The style and indent of the paragraph is as
        -- specified. The (AA)RM paragraph number (which might include update
        -- and version numbers as well: [12.1/1]) is Number. If the format is
        -- a type with a prefix (bullets, hangining items), the prefix is
        -- omitted if No_Prefix is true. Tab_Stops defines the tab stops for
        -- the paragraph. If No_Breaks is True, we will try to avoid page breaks
        -- in the paragraph. If Keep_with_Next is true, we will try to avoid
        -- separating this paragraph and the next one. (These may have no
        -- effect in formats that don't have page breaks). Space_After
        -- specifies the amount of space following the paragraph. Justification
        -- specifies the text justification for the paragraph. Not_Valid_Error
        -- is raised if Tab_Stops /= NO_TABS for a hanging or bulleted format.
        use type ARM_Output.Paragraph_Indent_Type;
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Already in paragraph");
        end if;
        Output_Object.Is_In_Paragraph := True;
        Output_Object.Is_Hanging := False;
        Output_Object.Saw_Hang_End := False;
        Output_Object.Char_Count := 0;
        Output_Object.Out_Char_Count := 0;
        Output_Object.Output_Buffer_Space_Before := False; -- Nothing in it or on the line.
        Output_Object.Output_Buffer_Len := 0;
        Output_Object.Font := ARM_Output.Default;
        Output_Object.Is_Bold := False;
        Output_Object.Is_Italic := False;
        Output_Object.Size := 0;
        Output_Object.Para_Style := Style;
        Output_Object.Para_Indent := Indent;
        Output_Object.Is_Fixed_Format := False;

        if Output_Object.Clause_Len /= 0 and then
           Number /= "" then
            Ada.Text_IO.New_Line (Output_Object.Output_File);
            Ada.Text_IO.Put (Output_Object.Output_File, "!paragraph ");
            Ada.Text_IO.Put (Output_Object.Output_File, Output_Object.Clause_Num(1..Output_Object.Clause_Len));
            Ada.Text_IO.Put (Output_Object.Output_File, '(');
            Ada.Text_IO.Put (Output_Object.Output_File, Number);
            Ada.Text_IO.Put (Output_Object.Output_File, ") [");
            Ada.Text_IO.Put (Output_Object.Output_File, ARM_Output.Paragraph_Style_Type'Image(Style) &
                        " :" & ARM_Output.Paragraph_Indent_Type'Image(Indent));
            Ada.Text_IO.Put_Line (Output_Object.Output_File, "]");
            Ada.Text_IO.New_Line (Output_Object.Output_File);
        else
            Ada.Text_IO.New_Line (Output_Object.Output_File);
        end if;

        Output_Object.Indent_Amount := Integer(Indent)*4 + 2;

        case Style is
            when ARM_Output.Normal =>
                if Indent = 0 then
                    null; -- %% Temp.
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                elsif Indent = 3 then
                    Ada.Text_IO.Put (Output_Object.Output_File, "@xindent<");
                    Output_Object.Char_Count := 9;
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;
            when ARM_Output.Wide_Above => null;
                if Indent = 0 then
                    null; -- %% Temp.
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Small =>
                if Indent = 1 then -- Notes.
                    Ada.Text_IO.Put (Output_Object.Output_File, "@xindent<@s9<");
                    Output_Object.Char_Count := 13;
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;
            when ARM_Output.Small_Wide_Above =>
                null; -- ** TBD (Unknown cases).

            when ARM_Output.Header =>
                null; -- ** TBD (Unknown cases).

            when ARM_Output.Small_Header =>
                if Indent = 1 then -- Notes Header.
                    null;
                    --Output_Object.Indent_Amount := 6; --** TBD.
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Index => null; --** TBD.
            when ARM_Output.Syntax_Summary => null; --** TBD.
            when ARM_Output.Title =>
                null; -- ** TBD (Unknown cases).

            when ARM_Output.Examples =>
                if Indent = 1 then
                    Ada.Text_IO.Put (Output_Object.Output_File, "@xcode<");
                    Output_Object.Char_Count := 7;
                    Output_Object.Is_Fixed_Format := True;
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Small_Examples => null; --** TBD.

            when ARM_Output.Swiss_Examples =>
                if Indent = 1 then
                    Ada.Text_IO.Put (Output_Object.Output_File, "@xcode<");
                    Output_Object.Char_Count := 7;
                    Output_Object.Is_Fixed_Format := True;
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Small_Swiss_Examples => null; --** TBD.

            when ARM_Output.Bulleted =>
                if Indent = 1 then
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                    if No_Prefix then
                        Ada.Text_IO.Put (Output_Object.Output_File, "@xindent<");
                        Output_Object.Char_Count := 9;
                    else
                        Ada.Text_IO.Put (Output_Object.Output_File, "@xbullet<");
                        Output_Object.Char_Count := 9;
                    end if;
                else -- Unknown/unimplemented case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Nested_Bulleted => null; --** TBD.

            when ARM_Output.Small_Bulleted => null; --** TBD.

            when ARM_Output.Small_Nested_Bulleted => null; --** TBD.

            when ARM_Output.Giant_Hanging => null; --** TBD.

            when ARM_Output.Wide_Hanging =>
                if Indent = 3 then
                    Output_Object.Indent_Amount := 0; -- %% Temp.
                    Output_Object.Is_Hanging := True;
                    if No_Prefix then
                        Output_Object.Saw_Hang_End := True;
                        Output_Object.Char_Count := 0;
                    else -- Has prefix
                        -- No units on first line.
                        Output_Object.Saw_Hang_End := False;
                        Ada.Text_IO.Put (Output_Object.Output_File, "@xhang<@xterm<");
                        Output_Object.Char_Count := 14;
                    end if;
                else -- Unknown/unimplemented case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Medium_Hanging => null; --** TBD.

            when ARM_Output.Narrow_Hanging => null; --** TBD.

            when ARM_Output.Hanging_in_Bulleted => null; --** TBD.

            when ARM_Output.Small_Giant_Hanging => null; --** TBD.

            when ARM_Output.Small_Wide_Hanging => null; --** TBD.

            when ARM_Output.Small_Medium_Hanging => null; --** TBD.

            when ARM_Output.Small_Narrow_Hanging => null; --** TBD.

            when ARM_Output.Small_Hanging_in_Bulleted => null; --** TBD.

            when ARM_Output.Enumerated => null; --** TBD.

            when ARM_Output.Small_Enumerated => null; --** TBD.

        end case;

        if Output_Object.Indent_Amount > 6 then
            for I in 1 .. (Output_Object.Indent_Amount-6)/4 loop
                Ada.Text_IO.Put (Output_Object.Output_File, "    ");
                Output_Object.Char_Count := Output_Object.Char_Count + 4;
            end loop;
        end if;

        case Style is
            when ARM_Output.Normal | ARM_Output.Wide_Above |
                 ARM_Output.Small | ARM_Output.Small_Wide_Above |
                 ARM_Output.Header | ARM_Output.Small_Header |
                 ARM_Output.Index | ARM_Output.Syntax_Summary |
                 ARM_Output.Title |
                 ARM_Output.Examples | ARM_Output.Small_Examples |
                 ARM_Output.Swiss_Examples | ARM_Output.Small_Swiss_Examples =>
                Output_Object.Tab_Stops := Tab_Stops;
                    -- We'll expand proportional stops here (text characters
                    -- are larger than the variable ones these are set up for).
                for I in 1 .. Tab_Stops.Number loop
                    if ARM_Output."=" (Tab_Stops.Stops(I).Kind,
                                       ARM_Output.Left_Proportional) then
                        Output_Object.Tab_Stops.Stops(I).Stop :=
                                (Tab_Stops.Stops(I).Stop * 5 / 4) + Output_Object.Indent_Amount;
                    else
                        Output_Object.Tab_Stops.Stops(I).Stop :=
                                Tab_Stops.Stops(I).Stop + Output_Object.Indent_Amount;
                    end if;
                end loop;
            when ARM_Output.Bulleted | ARM_Output.Nested_Bulleted |
                 ARM_Output.Small_Bulleted | ARM_Output.Small_Nested_Bulleted |
                 ARM_Output.Giant_Hanging | ARM_Output.Wide_Hanging |
                 ARM_Output.Medium_Hanging | ARM_Output.Narrow_Hanging |
                 ARM_Output.Hanging_in_Bulleted |
                 ARM_Output.Small_Giant_Hanging | ARM_Output.Small_Wide_Hanging |
                 ARM_Output.Small_Medium_Hanging | ARM_Output.Small_Narrow_Hanging |
                 ARM_Output.Small_Hanging_in_Bulleted |
                 ARM_Output.Enumerated | ARM_Output.Small_Enumerated =>
                if Tab_Stops.Number /= 0 then
                    Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                        "Tabs in hanging/bulleted paragraph");
                end if;
        end case;
        Output_Object.Out_Char_Count := Output_Object.Char_Count;

        -- Note: No_Breaks, Keep_with_Next, and Justification have no effect
        -- here.
--Ada.Text_IO.Put_Line ("Start_Paragraph - Indent=" & Natural'Image(Output_Object.Indent_Amount) & " Cnt=" &
--    Natural'Image(Output_Object.Char_Count));
    end Start_Paragraph;


    procedure End_Paragraph (Output_Object : in out Corr_Output_Type) is
        -- End a paragraph.
        use type ARM_Output.Paragraph_Indent_Type;
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
        case Output_Object.Para_Style is
            when ARM_Output.Normal =>
                if Output_Object.Para_Indent = 0 then
                    null;
                elsif Output_Object.Para_Indent = 3 then
                    Buffer (Output_Object, '>');
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;
            when ARM_Output.Wide_Above => null;
                if Output_Object.Para_Indent = 0 then
                    null; -- %% Temp.
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Small =>
                if Output_Object.Para_Indent = 1 then -- Notes.
                    Buffer (Output_Object, ">>");
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;
            when ARM_Output.Small_Wide_Above =>
                null; -- ** TBD (Unknown cases).

            when ARM_Output.Header =>
                null; -- ** TBD (Unknown cases).

            when ARM_Output.Small_Header =>
                if Output_Object.Para_Indent = 1 then -- Notes Header.
                    null;
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Index => null; --** TBD.
            when ARM_Output.Syntax_Summary => null; --** TBD.
            when ARM_Output.Title => null; --** TBD.
            when ARM_Output.Examples =>
                if Output_Object.Para_Indent = 1 then
                    Buffer (Output_Object, '>');
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Small_Examples => null; --** TBD.

            when ARM_Output.Swiss_Examples =>
                if Output_Object.Para_Indent = 1 then
                    Buffer (Output_Object, '>');
                else -- Unknown case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Small_Swiss_Examples => null; --** TBD.

            when ARM_Output.Bulleted =>
                if Output_Object.Para_Indent = 1 then
                    Buffer (Output_Object, '>');
                else -- Unknown/unimplemented case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Nested_Bulleted => null; --** TBD.

            when ARM_Output.Small_Bulleted => null; --** TBD.

            when ARM_Output.Small_Nested_Bulleted => null; --** TBD.

            when ARM_Output.Giant_Hanging => null; --** TBD.

            when ARM_Output.Wide_Hanging =>
                if Output_Object.Para_Indent = 3 then
                    Buffer (Output_Object, '>');
                else -- Unknown/unimplemented case.
                    null; -- ** Tbd.
                end if;

            when ARM_Output.Medium_Hanging => null; --** TBD.

            when ARM_Output.Narrow_Hanging => null; --** TBD.

            when ARM_Output.Hanging_in_Bulleted => null; --** TBD.

            when ARM_Output.Small_Giant_Hanging => null; --** TBD.

            when ARM_Output.Small_Wide_Hanging => null; --** TBD.

            when ARM_Output.Small_Medium_Hanging => null; --** TBD.

            when ARM_Output.Small_Narrow_Hanging => null; --** TBD.

            when ARM_Output.Small_Hanging_in_Bulleted => null; --** TBD.

            when ARM_Output.Enumerated => null; --** TBD.

            when ARM_Output.Small_Enumerated => null; --** TBD.

        end case;

        if Output_Object.Output_Buffer_Len /= 0 then
            Spill (Output_Object);
        end if;
        Output_Object.Is_In_Paragraph := False;
        Ada.Text_IO.New_Line (Output_Object.Output_File, 2); -- Double space paragraphs.
    end End_Paragraph;


    procedure Category_Header (Output_Object : in out Corr_Output_Type;
                               Header_Text : String) is
        -- Output a Category header (that is, "Legality Rules",
        -- "Dynamic Semantics", etc.)
        -- (Note: We did not use a enumeration here to insure that these
        -- headers are spelled the same in all output versions).
        -- Raises Not_Valid_Error if in a paragraph.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Header in paragraph");
        end if;
        Ada.Text_IO.New_Line (Output_Object.Output_File);
        Ada.Text_IO.Put_Line (Output_Object.Output_File, "!subheader");
        Ada.Text_IO.Put (Output_Object.Output_File, "@i<@s8<");
        if Ada.Strings.Fixed.Count (Header_Text, Special_Set) = 0 then
            Ada.Text_IO.Put (Output_Object.Output_File, Header_Text);
        else
            for I in Header_Text'Range loop
                if Header_Text(I) = '>' then
                    Ada.Text_IO.Put (Output_Object.Output_File, "@>");
                elsif Header_Text(I) = '@' then
                    Ada.Text_IO.Put (Output_Object.Output_File, "@@");
                else
                    Ada.Text_IO.Put (Output_Object.Output_File, Header_Text(I));
                end if;
            end loop;
        end if;
        Ada.Text_IO.Put (Output_Object.Output_File, ">>");
        Ada.Text_IO.New_Line (Output_Object.Output_File);
        Output_Object.Char_Count := 0;
        Output_Object.Out_Char_Count := 0;
    end Category_Header;


    procedure Clause_Header (Output_Object     : in out Corr_Output_Type;
                             Header_Text       : in String;
                             Level             : in ARM_Contents.Level_Type;
                             Clause_Number     : in String;
                             Top_Level_Subdivision_Name : in ARM_Output.Top_Level_Subdivision_Name_Kind;
                             No_Page_Break     : in Boolean := False) is
        -- Output a Clause header. The level of the header is specified
        -- in Level. The Clause Number is as specified; the top-level (and
        -- other) subdivision names are as specified. These should appear in
        -- the table of contents.
        -- For hyperlinked formats, this should generate a link target.
        -- If No_Page_Break is True, suppress any page breaks.
        -- Raises Not_Valid_Error if in a paragraph.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Header in paragraph");
        end if;
        Ada.Text_IO.New_Line (Output_Object.Output_File);

        Output_Object.Clause_Len := Clause_Number'Length;
        Output_Object.Clause_Num(1..Output_Object.Clause_Len) :=
            Clause_Number;
        -- Special for table of contents:
        if Clause_Number = "" and then
                (Header_Text = "Table of Contents" or else
                 Header_Text = "Contents") then
            Ada.Text_IO.Put (Output_Object.Output_File,
                               "!clause ");
            Ada.Text_IO.Put_Line (Output_Object.Output_File,
                               Header_Text);
            Ada.Text_IO.New_Line (Output_Object.Output_File, 2);
            Output_Object.Char_Count := 0;
            Output_Object.Out_Char_Count := 0;
            return;
        end if;

        Ada.Text_IO.Put (Output_Object.Output_File,
                         "!clause ");
        case Level is
            when ARM_Contents.Plain_Annex =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Clause_Number); -- Note: Clause_Number includes "Annex"
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Header_Text);
            when ARM_Contents.Normative_Annex =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Clause_Number); -- Note: Clause_Number includes "Annex"
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   "(normative)");
                Ada.Text_IO.New_Line (Output_Object.Output_File);
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Header_Text);
            when ARM_Contents.Informative_Annex =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Clause_Number); -- Note: Clause_Number includes "Annex"
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   "(informative)");
                Ada.Text_IO.New_Line (Output_Object.Output_File);
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Header_Text);
            when ARM_Contents.Section =>
                case Top_Level_Subdivision_Name is
                    when ARM_Output.Chapter =>
                        Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                              "Chapter " & Clause_Number & ": " & Header_Text);
                    when ARM_Output.Section =>
                        Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                              "Section " & Clause_Number & ": " & Header_Text);
                    when ARM_Output.Clause =>
                        Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                              Clause_Number & "   " & Header_Text);
                end case;
            when ARM_Contents.Unnumbered_Section =>
                if Header_Text /= "" then
                    Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                       Header_Text);
                end if;
            when ARM_Contents.Clause | ARM_Contents.Subclause |
                 ARM_Contents.Subsubclause =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                      Clause_Number & ' ' & Header_Text);
            when ARM_Contents.Dead_Clause =>
                raise Program_Error; -- No headers for dead clauses.
        end case;
        Ada.Text_IO.New_Line (Output_Object.Output_File, 2);
        Output_Object.Char_Count := 0;
        Output_Object.Out_Char_Count := 0;
        -- We don't have any page breaks here to suppress.
    end Clause_Header;


    procedure Revised_Clause_Header
                            (Output_Object     : in out Corr_Output_Type;
                             New_Header_Text   : in String;
                             Old_Header_Text   : in String;
                             Level             : in ARM_Contents.Level_Type;
                             Clause_Number     : in String;
                             Version           : in ARM_Contents.Change_Version_Type;
                             Old_Version       : in ARM_Contents.Change_Version_Type;
                             Top_Level_Subdivision_Name : in ARM_Output.Top_Level_Subdivision_Name_Kind;
                             No_Page_Break     : in Boolean := False) is
        -- Output a revised clause header. Both the original and new text will
        -- be output. The level of the header is specified in Level. The Clause
        -- Number is as specified; the top-level (and other) subdivision names
        -- are as specified. These should appear in the table of contents.
        -- For hyperlinked formats, this should generate a link target.
        -- Version is the insertion version of the new text; Old_Version is
        -- the insertion version of the old text.
        -- If No_Page_Break is True, suppress any page breaks.
        -- Raises Not_Valid_Error if in a paragraph.
        function Header_Text return String is
            -- Note: Version and Old_Version are not used.
        begin
            return '{' & New_Header_Text & "} [" & Old_Header_Text & ']';
        end Header_Text;
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Header in paragraph");
        end if;
        Ada.Text_IO.New_Line (Output_Object.Output_File);

        Output_Object.Clause_Len := Clause_Number'Length;
        Output_Object.Clause_Num(1..Output_Object.Clause_Len) :=
            Clause_Number;
        -- Special for table of contents:
        if Clause_Number = "" and then
                (Header_Text = "Table of Contents" or else -- Ada 95 format
                 Header_Text = "Contents") then -- ISO 2004 format.
            Ada.Text_IO.Put (Output_Object.Output_File,
                             "!clause ");
            Ada.Text_IO.Put_Line (Output_Object.Output_File,
                               Header_Text);
            Ada.Text_IO.New_Line (Output_Object.Output_File, 2);
            Output_Object.Char_Count := 0;
            Output_Object.Out_Char_Count := 0;
            return;
        end if;

        Ada.Text_IO.Put (Output_Object.Output_File,
                         "!clause ");
        case Level is
            when ARM_Contents.Plain_Annex =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Clause_Number); -- Note: Clause_Number includes "Annex"
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Header_Text);
            when ARM_Contents.Normative_Annex =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Clause_Number); -- Note: Clause_Number includes "Annex"
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   "(normative)");
                Ada.Text_IO.New_Line (Output_Object.Output_File);
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Header_Text);
            when ARM_Contents.Informative_Annex =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Clause_Number); -- Note: Clause_Number includes "Annex"
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   "(informative)");
                Ada.Text_IO.New_Line (Output_Object.Output_File);
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                   Header_Text);
            when ARM_Contents.Section =>
                case Top_Level_Subdivision_Name is
                    when ARM_Output.Chapter =>
                        Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                              "Chapter " & Clause_Number & ": " & Header_Text);
                    when ARM_Output.Section =>
                        Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                              "Section " & Clause_Number & ": " & Header_Text);
                    when ARM_Output.Clause =>
                        Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                              Clause_Number & "   " & Header_Text);
                end case;

            when ARM_Contents.Unnumbered_Section =>
                if Header_Text /= "" then
                    Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                       Header_Text);
                end if;
            when ARM_Contents.Clause | ARM_Contents.Subclause |
                 ARM_Contents.Subsubclause =>
                Ada.Text_IO.Put_Line (Output_Object.Output_File,
                                      Clause_Number & ' ' & Header_Text);
            when ARM_Contents.Dead_Clause =>
                raise Program_Error; -- No headers for dead clauses.
        end case;
        Ada.Text_IO.New_Line (Output_Object.Output_File, 2);
        Output_Object.Char_Count := 0;
        Output_Object.Out_Char_Count := 0;
        -- We don't have any page breaks here to suppress.
    end Revised_Clause_Header;


    procedure TOC_Marker (Output_Object : in out Corr_Output_Type;
                          For_Start : in Boolean) is
        -- Mark the start (if For_Start is True) or end (if For_Start is
        -- False) of the table of contents data. Output objects that
        -- auto-generate the table of contents can use this to do needed
        -- actions.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        null; -- We don't care about this.
    end TOC_Marker;


    procedure New_Page (Output_Object : in out Corr_Output_Type;
                        Kind : ARM_Output.Page_Kind_Type := ARM_Output.Any_Page) is
        -- Output a page break.
        -- Note that this has no effect on non-printing formats.
        -- Any_Page breaks to the top of the next page (whatever it is);
        -- Odd_Page_Only breaks to the top of the odd-numbered page;
        -- Soft_Page allows a page break but does not force one (use in
        -- "No_Breaks" paragraphs.)
        -- Raises Not_Valid_Error if in a paragraph if Kind = Any_Page or
        -- Odd_Page, and if not in a paragraph if Kind = Soft_Page.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        case Kind is
            when ARM_Output.Any_Page | ARM_Output.Odd_Page_Only =>
                if Output_Object.Is_In_Paragraph then
                    Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                        "Page in paragraph");
                end if;
                Ada.Text_IO.New_Line (Output_Object.Output_File, 2);
            when ARM_Output.Soft_Page =>
                if not Output_Object.Is_In_Paragraph then
                    Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                        "Soft page not in paragraph");
                end if;
                null; -- No page breaks.
                Spill (Output_Object);
        end case;
    end New_Page;


    procedure New_Column (Output_Object : in out Corr_Output_Type) is
        -- Output a column break.
        -- Raises Not_Valid_Error if in a paragraph, or if the number of
        -- columns is 1.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "New column in paragraph");
        end if;
        -- No columns in text format.
        Ada.Text_IO.New_Line (Output_Object.Output_File);
    end New_Column;


    procedure Start_Table (Output_Object : in out Corr_Output_Type;
                           Columns : in ARM_Output.Column_Count;
                           First_Column_Width : in ARM_Output.Column_Count;
                           Last_Column_Width : in ARM_Output.Column_Count;
                           Alignment : in ARM_Output.Column_Text_Alignment;
                           No_Page_Break : in Boolean;
                           Has_Border : in Boolean;
                           Small_Text_Size : in Boolean;
                           Header_Kind : in ARM_Output.Header_Kind_Type) is
        -- Starts a table. The number of columns is Columns; the first
        -- column has First_Column_Width times the normal column width, and
        -- the last column has Last_Column_Width times the normal column width.
        -- Alignment is the horizontal text alignment within the columns.
        -- No_Page_Break should be True to keep the table intact on a single
        -- page; False to allow it to be split across pages.
        -- Has_Border should be true if a border is desired, false otherwise.
        -- Small_Text_Size means that the contents will have the AARM size;
        -- otherwise it will have the normal size.
        -- Header_Kind determines whether the table has headers.
        -- This command starts a paragraph; the entire table is a single
        -- paragraph. Text will be considered part of the caption until the
        -- next table marker call.
        -- Raises Not_Valid_Error if in a paragraph.
    begin
        -- Alignment, No_Page_Break, Border, Small_Text_Size, and Header_Kind
        -- not used here.
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Table in paragraph");
        end if;

        Output_Object.Tab_Stops.Number := Columns;
        declare
             Column_Units : constant ARM_Output.Column_Count :=
                Columns+First_Column_Width+Last_Column_Width-2;
             Width : Natural :=
                (72/(Column_Units));
        begin
            if Column_Units <= 3 then -- Keep it from getting too wide.
                Width := 22;
            end if;
            for I in 1 .. Columns loop
                Output_Object.Tab_Stops.Stops(I) := (Kind => ARM_Output.Left_Fixed,
                                                     Stop => Width*(I+First_Column_Width-1)+10);
            end loop;
        end;

        Output_Object.Indent_Amount := 10;
        Ada.Text_IO.Put (Output_Object.Output_File, "          ");
        Output_Object.Char_Count := 10;
        Output_Object.Out_Char_Count := 10;

        Output_Object.Is_In_Paragraph := True;
        Output_Object.Is_In_Table := True;
    end Start_Table;


    procedure Table_Marker (Output_Object : in out Corr_Output_Type;
                            Marker : in ARM_Output.Table_Marker_Type) is
        -- Marks the end of an entity in a table.
        -- If Marker is End_Caption, the table caption ends and the
        --      future text is part of the table header.
        -- If Marker is End_Header, the table header ends and the
        --      future text is part of the table body.
        -- If Marker is End_Row, a row in the table is completed, and another
        --      row started.
        -- If Marker is End_Row_Next_Is_Last, a row in the table is completed,
        --      and another row started. That row is the last row in the table.
        -- If Marker is End_Item, an item in the table header or body is ended,
        --      and another started.
        -- If Marker is End_Table, the entire table is finished.
        -- Raises Not_Valid_Error if not in a table.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if (not Output_Object.Is_In_Paragraph) or (not Output_Object.Is_In_Table) then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Table marker not in table");
        end if;
        case Marker is
            when ARM_Output.End_Item =>
                -- Just tab over one row:
                Spill (Output_Object);
                Ada.Text_IO.Put_Line (Output_Object.Output_File, " ");
                Output_Object.Char_Count := Output_Object.Char_Count + 1;
                Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + 1;
                for I in 1 .. Output_Object.Tab_Stops.Number loop
                    if Output_Object.Tab_Stops.Stops(I).Stop > Output_Object.Char_Count then
                        for J in Output_Object.Char_Count+1 .. Output_Object.Tab_Stops.Stops(I).Stop-1 loop
                            Ada.Text_IO.Put_Line (Output_Object.Output_File, " ");
                            Output_Object.Char_Count := Output_Object.Char_Count + 1;
                            Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + 1;
                        end loop;
                    end if;
                end loop;

            when ARM_Output.End_Caption =>
                Spill (Output_Object);
                Ada.Text_IO.New_Line (Output_Object.Output_File, 2);
                Ada.Text_IO.Put (Output_Object.Output_File, "          ");
                Output_Object.Char_Count := 10;
                Output_Object.Out_Char_Count := 10;
            when ARM_Output.End_Header =>
                Spill (Output_Object);
                Ada.Text_IO.New_Line (Output_Object.Output_File, 2);
                Ada.Text_IO.Put (Output_Object.Output_File, "          ");
                Output_Object.Char_Count := 10;
                Output_Object.Out_Char_Count := 10;
            when ARM_Output.End_Row | ARM_Output.End_Row_Next_Is_Last =>
                Spill (Output_Object);
                Ada.Text_IO.New_Line (Output_Object.Output_File, 1);
                Ada.Text_IO.Put (Output_Object.Output_File, "          ");
                Output_Object.Char_Count := 10;
                Output_Object.Out_Char_Count := 10;
            when ARM_Output.End_Table =>
                Spill (Output_Object);
                Output_Object.Is_In_Paragraph := False;
                Output_Object.Is_In_Table := False;
                Ada.Text_IO.New_Line (Output_Object.Output_File);
                Output_Object.Tab_Stops := ARM_Output.NO_TABS;
        end case;
    end Table_Marker;


    procedure Separator_Line (Output_Object : in out Corr_Output_Type;
                              Is_Thin : Boolean := True) is
        -- Output a separator line. It is thin if "Is_Thin" is true.
        -- Raises Not_Valid_Error if in a paragraph.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Separator in paragraph");
        end if;
        Ada.Text_IO.New_Line (Output_Object.Output_File);
        if Is_Thin then
            Ada.Text_IO.Put_Line (Output_Object.Output_File, "---------------------------------------------------------------------");
        else
            Ada.Text_IO.Put_Line (Output_Object.Output_File, "=====================================================================");
        end if;
        Ada.Text_IO.New_Line (Output_Object.Output_File);
    end Separator_Line;


    -- Text output: These are only allowed after a Start_Paragraph and
    -- before any End_Paragraph. Raises Not_Valid_Error if not allowed.

    procedure Ordinary_Text (Output_Object : in out Corr_Output_Type;
                             Text : in String) is
        -- Output ordinary text.
        -- The text must end at a word break, never in the middle of a word.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
--Ada.Text_IO.Put_Line ("Ordinary_Text: Cnt=" & Natural'Image(Output_Object.Char_Count) &
--" Buffer=" & Natural'Image(Output_Object.Output_Buffer_Len));
        if Output_Object.Char_Count + Text'Length >= LINE_LENGTH - 2 and then
           Output_Object.Out_Char_Count > Output_Object.Indent_Amount then
            -- We want a line break here if the line is too long and something was output:
            Ada.Text_IO.New_Line (Output_Object.Output_File);
            Make_Indent (Output_Object);
            --Output_Object.Output_Buffer_Space_Before := False;
                -- Start of line, this is done by Make_Indent.
            Spill (Output_Object);
        else
            Spill (Output_Object);
        end if;
        if Ada.Strings.Fixed.Count (Text, Special_Set) = 0 then
            Ada.Text_IO.Put (Output_Object.Output_File, Text);
            Output_Object.Char_Count := Output_Object.Char_Count + Text'Length;
            Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + Text'Length;
        else
            for I in Text'Range loop
                if Text(I) = '>' then
                    Ada.Text_IO.Put (Output_Object.Output_File, "@>");
                    Output_Object.Char_Count := Output_Object.Char_Count + 2;
                    Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + 2;
                elsif Text(I) = '@' then
                    Ada.Text_IO.Put (Output_Object.Output_File, "@@");
                    Output_Object.Char_Count := Output_Object.Char_Count + 2;
                    Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + 2;
                else
                    Ada.Text_IO.Put (Output_Object.Output_File, Text(I));
                    Output_Object.Char_Count := Output_Object.Char_Count + 1;
                    Output_Object.Out_Char_Count := Output_Object.Out_Char_Count + 1;
                end if;
            end loop;
        end if;
        Output_Object.Output_Buffer_Space_Before := False; -- No space between
                                                           -- this and any following text.
    end Ordinary_Text;


    procedure Ordinary_Character (Output_Object : in out Corr_Output_Type;
                                  Char : in Character) is
        -- Output an ordinary character.
        -- Spaces will be used to break lines as needed.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;

        if Output_Object.Char_Count >= LINE_LENGTH and then
           Output_Object.Out_Char_Count > Output_Object.Indent_Amount then
            -- Insert a break here if anything has been output (but don't
            -- Spill the buffer):
--Ada.Text_IO.Put_Line ("Ordinary_Char [Break, no spill]: Cnt=" & Natural'Image(Output_Object.Char_Count));
            Ada.Text_IO.New_Line (Output_Object.Output_File);
            Make_Indent (Output_Object);
            --Output_Object.Output_Buffer_Space_Before := False;
                -- Start of line, this is done by Make_Indent.
                -- Note that this may make the space disappear.
            -- Add the contents of the buffer to the character count for this line:
            Output_Object.Char_Count := Output_Object.Char_Count +
                Output_Object.Output_Buffer_Len;
            if Char = '>' then
                Buffer (Output_Object, "@>");
            elsif Char = '@' then
                Buffer (Output_Object, "@@");
            elsif Char /= ' ' then
                Buffer (Output_Object, Char);
            else -- Break character, spill on the new line:
                if Output_Object.Output_Buffer_Len /= 0 then
                    Spill (Output_Object); -- Output the buffer up to the space.
                    Output_Object.Output_Buffer_Space_Before := True; -- Mid-line now.
                -- else nothing in buffer, so nothing to output; just skip it.
                end if;
            end if;
        elsif Char = ' ' then
            -- Break character, and it fits on this line:
            if Output_Object.Output_Buffer_Len /= 0 then
--Ada.Text_IO.Put_Line ("Ordinary_Char [Space spill]: Cnt=" & Natural'Image(Output_Object.Char_Count));
                Spill (Output_Object); -- Output the buffer up to the space.
                Output_Object.Output_Buffer_Space_Before := True; -- Mid-line now.
            else -- nothing in buffer.
                -- nothing to output. But make sure we display a space before
                -- the next item.
                Output_Object.Output_Buffer_Space_Before := True; -- Mid-line now.
            end if;
        elsif Char = '>' then
            Buffer (Output_Object, "@>");
        elsif Char = '@' then
            Buffer (Output_Object, "@@");
        else
            Buffer (Output_Object, Char);
        end if;
    end Ordinary_Character;


    procedure Hard_Space (Output_Object : in out Corr_Output_Type) is
        -- Output a hard space. No line break should happen at a hard space.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
        if Output_Object.Is_Fixed_Format then
            -- In this format, all spaces are hard spaces.
            Buffer (Output_Object, ' ');
        else -- A hard space command.
            Buffer (Output_Object, "@ ");
        end if;
    end Hard_Space;


    procedure Line_Break (Output_Object : in out Corr_Output_Type) is
        -- Output a line break. This does not start a new paragraph.
        -- This corresponds to a "<BR>" in HTML.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
--Ada.Text_Io.Put_Line ("Line_Break");
        if Output_Object.Is_Fixed_Format then
            -- In this format, all line breaks are significant.
            null;
        else -- A hard space command.
            Buffer (Output_Object, "@hr");
        end if;
        if Output_Object.Output_Buffer_Len /= 0 then
            Spill (Output_Object);
        end if;
        Ada.Text_IO.New_Line (Output_Object.Output_File);
        Make_Indent (Output_Object);
    end Line_Break;


    procedure Index_Line_Break (Output_Object : in out Corr_Output_Type;
                                Clear_Keep_with_Next : in Boolean) is
        -- Output a line break for the index. This does not start a new
        -- paragraph in terms of spacing. This corresponds to a "<BR>"
        -- in HTML. If Clear_Keep_with_Next is true, insure that the next
        -- line does not require the following line to stay with it.
        -- Raises Not_Valid_Error if the paragraph is not in the index format.
    begin
        Line_Break (Output_Object);
    end Index_Line_Break;


    procedure Soft_Line_Break (Output_Object : in out Corr_Output_Type) is
        -- Output a soft line break. This is a place (in the middle of a
        -- "word") that we allow a line break. It is usually used after
        -- underscores in long non-terminals.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
--      if Output_Object.Char_Count >= LINE_LENGTH - 10 then
--          if Output_Object.Output_Buffer_Len /= 0 then
--              Spill (Output_Object);
--          end if;
--          Ada.Text_IO.New_Line (Output_Object.Output_File);
--            Make_Indent (Output_Object);
--      -- else we don't need a line break.
--      end if;
        null; -- Ignore this, there is no counterpart in Corrigendum formatting.
    end Soft_Line_Break;


    procedure Soft_Hyphen_Break (Output_Object : in out Corr_Output_Type) is
        -- Output a soft line break, with a hyphen. This is a place (in the middle of
        -- a "word") that we allow a line break. If the line break is used,
        -- a hyphen will be added to the text.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
--      if Output_Object.Char_Count >= LINE_LENGTH - 8 then
--          Spill (Output_Object);
--          Ada.Text_IO.Put_Line (Output_Object.Output_File, "-"); -- Add the hyphen and break.
--            Make_Indent (Output_Object);
--      -- else we don't need a line break.
--      end if;
        null; -- Ignore this, there is no counterpart in Corrigendum formatting.
    end Soft_Hyphen_Break;


    procedure Tab (Output_Object : in out Corr_Output_Type) is
        -- Output a tab, inserting space up to the next tab stop.
        -- Raises Not_Valid_Error if the paragraph was created with
        -- Tab_Stops = ARM_Output.NO_TABS.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
        if ARM_Output."="(Output_Object.Tab_Stops, ARM_Output.NO_TABS) then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Tab, but none set");
        end if;
        -- We use the tab stops as characters here, and fixed and proportional
        -- stops are treated identically.
        -- Find the first stop greater than the current character count. (After
        -- writing a space).
--Ada.Text_IO.Put_Line ("Tab");
        Buffer (Output_Object, "@tab");
        Output_Object.Output_Buffer_Space_Before := False; -- Spaces needed were output.
    end Tab;


    procedure Special_Character (Output_Object : in out Corr_Output_Type;
                                 Char : in ARM_Output.Special_Character_Type) is
        -- Output an special character.
    begin
        --** Could use Latin1 and Unicode equivalents for most of these.
        case Char is
            when ARM_Output.EM_Dash =>
                Buffer (Output_Object, "@emdash");
            when ARM_Output.EN_Dash =>
                Buffer (Output_Object, "@endash");
            when ARM_Output.GEQ =>
                Ordinary_Text (Output_Object, ">="); -- Not available in Corrigendum, use the Ada one.
            when ARM_Output.LEQ =>
                Ordinary_Text (Output_Object, "<="); -- Not available in Corrigendum, use the Ada one.
            when ARM_Output.NEQ =>
                Ordinary_Text (Output_Object, "/="); -- Not available in Corrigendum, use the Ada one.
            when ARM_Output.PI =>
                Buffer (Output_Object, "@pi");
            when ARM_Output.Left_Ceiling =>
                Ordinary_Text (Output_Object, "Ceiling("); -- Not available in Corrigendum.
            when ARM_Output.Right_Ceiling =>
                Ordinary_Text (Output_Object, ")"); -- Not available in Corrigendum.
            when ARM_Output.Left_Floor =>
                Ordinary_Text (Output_Object, "Floor("); -- Not available in Corrigendum.
            when ARM_Output.Right_Floor =>
                Ordinary_Text (Output_Object, ")"); -- Not available in Corrigendum.
            when ARM_Output.Thin_Space =>
                Ordinary_Text (Output_Object, " "); -- Not available in Corrigendum.
            when ARM_Output.Left_Quote =>
                Buffer (Output_Object, "@lquote");
            when ARM_Output.Right_Quote =>
                Buffer (Output_Object, "@rquote");
            when ARM_Output.Left_Double_Quote =>
                Ordinary_Text (Output_Object, """"); -- Not available in Corrigendum, use double quote.
            when ARM_Output.Right_Double_Quote =>
                Ordinary_Text (Output_Object, """"); -- Not available in Corrigendum, use double quote.
            when ARM_Output.Small_Dotless_I =>
                Ordinary_Text (Output_Object, "i"); -- Not available in Corrigendum, use the nearest text.
            when ARM_Output.Capital_Dotted_I =>
                Ordinary_Text (Output_Object, "I"); -- Not available in Corrigendum, use the nearest text.
        end case;
    end Special_Character;


    procedure Unicode_Character (Output_Object : in out Corr_Output_Type;
                                 Char : in ARM_Output.Unicode_Type) is
        -- Output a Unicode character, with code position Char.
        Char_Code : constant String := ARM_Output.Unicode_Type'Image(Char);
    begin
        -- We don't check, but we assume this is not a normal character.
        Buffer (Output_Object, "@unicode<" & Char_Code(2..Char_Code'Last) & ">");
    end Unicode_Character;


    procedure End_Hang_Item (Output_Object : in out Corr_Output_Type) is
        -- Marks the end of a hanging item. Call only once per paragraph.
        -- Raises Not_Valid_Error if the paragraph style is not in
        -- Text_Prefixed_Style_Subtype, or if this has already been
        -- called for the current paragraph, or if the paragraph was started
        -- with No_Prefix = True.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
        if not Output_Object.Is_Hanging then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not a hanging paragraph");
        end if;
        if Output_Object.Saw_Hang_End then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Already saw the end of the hanging part");
        end if;
        Output_Object.Saw_Hang_End := True;

        Buffer (Output_Object, ">"); -- Close @Xterm<
    end End_Hang_Item;


    procedure Text_Format (Output_Object : in out Corr_Output_Type;
                           Format : in ARM_Output.Format_Type) is
        -- Change the text format so that all of the properties are as specified.
        -- Note: Changes to these properties ought be stack-like; that is,
        -- Bold on, Italic on, Italic off, Bold off is OK; Bold on, Italic on,
        -- Bold off, Italic off should be avoided (as separate commands).
        use type ARM_Output.Change_Type;
        use type ARM_Output.Location_Type;
        use type ARM_Output.Size_Type;
        -- Note: We ignore colors here, no colors in !Corrigendum markup.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;

        if not Format.Bold and Output_Object.Is_Bold then
            Buffer (Output_Object, '>');
            Output_Object.Is_Bold := False;
        end if;

        if not Format.Italic and Output_Object.Is_Italic then
            Buffer (Output_Object, '>');
            Output_Object.Is_Italic := False;
        end if;

        if Format.Size /= Output_Object.Size then
            if Output_Object.Size /= 0 then
                Buffer (Output_Object, '>');
            end if;
        end if;

        --  if Format.Location /= Output_Object.Location then
        --      if Output_Object.Location /= ARM_Output.Normal then
        --          --Buffer (Output_Object, '>');
        --      null; -- Corrigendum doesn't support this.
        --      end if;
        --  end if;

        if ARM_Output."/=" (Format.Font, Output_Object.Font) then
            case Output_Object.Font is
                when ARM_Output.Default => null;
                when ARM_Output.Fixed =>
                    Buffer (Output_Object, '>');
                when ARM_Output.Roman =>
                    Buffer (Output_Object, '>');
                when ARM_Output.Swiss =>
                    Buffer (Output_Object, '>');
            end case;
        end if;

        -- For the intended purpose, there should be no Change commands.
        if Format.Change /= Output_Object.Change then
            if Format.Change = ARM_Output.Both then
                -- Open only the one(s) needed:
                case Output_Object.Change is
                    -- Note: Version is not used.
                    when ARM_Output.Insertion =>
                        -- Open the deletion:
                        Buffer(Output_Object, '[');
                    when ARM_Output.Deletion =>
                        -- Open the insertion:
                        Buffer(Output_Object, '{');
                    when ARM_Output.None =>
                        Buffer(Output_Object, '{');
                        Buffer(Output_Object, '[');
                    when ARM_Output.Both =>
                        null;
                end case;
            elsif Output_Object.Change = ARM_Output.Both then
                -- Close only the one(s) needed:
                case Format.Change is
                    -- Note: Version is not used.
                    when ARM_Output.Insertion =>
                        -- Close the deletion:
                        Buffer(Output_Object, ']');
                    when ARM_Output.Deletion =>
                        -- Close the insertion:
                        Buffer(Output_Object, '}');
                    when ARM_Output.None =>
                        Buffer(Output_Object, ']');
                        Buffer(Output_Object, '}');
                    when ARM_Output.Both =>
                        null;
                end case;
            else -- Both can't get here.
                case Output_Object.Change is
                    when ARM_Output.Insertion =>
                        Buffer(Output_Object, '}');
                    when ARM_Output.Deletion =>
                        Buffer(Output_Object, ']');
                    when ARM_Output.None =>
                        null;
                    when ARM_Output.Both =>
                        Buffer(Output_Object, ']');
                        Buffer(Output_Object, '}');
                end case;
                case Format.Change is
                    -- Note: Version is not used.
                    when ARM_Output.Insertion =>
                        Buffer(Output_Object, '{');
                    when ARM_Output.Deletion =>
                        Buffer(Output_Object, '[');
                    when ARM_Output.None =>
                        null;
                    when ARM_Output.Both =>
                        Buffer(Output_Object, '{');
                        Buffer(Output_Object, '[');
                end case;
            end if;
            Output_Object.Change := Format.Change;
        end if;
        if ARM_Output."/=" (Format.Font, Output_Object.Font) then
            case Format.Font is
                when ARM_Output.Default => null;
                when ARM_Output.Fixed =>
                    Buffer (Output_Object, "@fc<");
                when ARM_Output.Roman =>
                    Buffer (Output_Object, "@ft<");
                when ARM_Output.Swiss =>
                    Buffer (Output_Object, "@fa<");
            end case;
            Output_Object.Font := Format.Font;
        end if;

        if Format.Location /= Output_Object.Location then
            case Format.Location is
                when ARM_Output.Superscript =>
                    --Buffer (Output_Object, "@+<");
                    null; -- Corrigendum doesn't support this.
                when ARM_Output.Subscript =>
                    --Buffer (Output_Object, "@+<");
                    null; -- Corrigendum doesn't support this.
                when ARM_Output.Normal =>
                    null;
            end case;
            Output_Object.Location := Format.Location;
        end if;

        if Format.Size /= Output_Object.Size then
            if Format.Size < 0 then
                Buffer (Output_Object, "@s" & Character'Val(10+Format.Size+Character'Pos('0')) & '<');
            else
                Buffer (Output_Object, "@s1" & Character'Val(Format.Size+Character'Pos('0')) & '<');
            end if;
            Output_Object.Size := Format.Size;
        end if;

        if Format.Italic and (not Output_Object.Is_Italic) then
            Buffer (Output_Object, "@i<");
            Output_Object.Is_Italic := True;
        end if;
        if Format.Bold and (not Output_Object.Is_Bold) then
            Buffer (Output_Object, "@b<");
            Output_Object.Is_Bold := True;
        end if;

    end Text_Format;


    procedure Clause_Reference (Output_Object : in out Corr_Output_Type;
                                Text : in String;
                                Clause_Number : in String) is
        -- Generate a reference to a clause in the standard. The text of
        -- the reference is "Text", and the number of the clause is
        -- Clause_Number. For hyperlinked formats, this should generate
        -- a link; for other formats, the text alone is generated.
    begin
        Ordinary_Text (Output_Object, Text); -- Nothing special in this format.
    end Clause_Reference;


    procedure Index_Target (Output_Object : in out Corr_Output_Type;
                            Index_Key : in Natural) is
        -- Generate a index target. This marks the location where an index
        -- reference occurs. Index_Key names the index item involved.
        -- For hyperlinked formats, this should generate a link target;
        -- for other formats, nothing is generated.
    begin
        if not Output_Object.Is_Valid then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not valid object");
        end if;
        if not Output_Object.Is_In_Paragraph then
            Ada.Exceptions.Raise_Exception (ARM_Output.Not_Valid_Error'Identity,
                "Not in paragraph");
        end if;
        null; -- Nothing to do for plain text.
    end Index_Target;


    procedure Index_Reference (Output_Object : in out Corr_Output_Type;
                               Text : in String;
                               Index_Key : in Natural;
                               Clause_Number : in String) is
        -- Generate a reference to an index target in the standard. The text
        -- of the reference is "Text", and Index_Key and Clause_Number denotes
        -- the target. For hyperlinked formats, this should generate
        -- a link; for other formats, the text alone is generated.
    begin
        Ordinary_Text (Output_Object, Text); -- Nothing special in this format.
    end Index_Reference;


    procedure DR_Reference (Output_Object : in out Corr_Output_Type;
                            Text : in String;
                            DR_Number : in String) is
        -- Generate a reference to an DR from the standard. The text
        -- of the reference is "Text", and DR_Number denotes
        -- the target. For hyperlinked formats, this should generate
        -- a link; for other formats, the text alone is generated.
    begin
        Ordinary_Text (Output_Object, Text); -- Nothing special in this format.
    end DR_Reference;


    procedure AI_Reference (Output_Object : in out Corr_Output_Type;
                            Text : in String;
                            AI_Number : in String) is
        -- Generate a reference to an AI from the standard. The text
        -- of the reference is "Text", and AI_Number denotes
        -- the target (in unfolded format). For hyperlinked formats, this
        -- should generate a link; for other formats, the text alone is
        -- generated.
    begin
        Ordinary_Text (Output_Object, Text); -- Nothing special in this format.
    end AI_Reference;


    procedure Local_Target (Output_Object : in out Corr_Output_Type;
                            Text : in String;
                            Target : in String) is
        -- Generate a local target. This marks the potential target of local
        -- links identified by "Target". Text is the text of the target.
        -- For hyperlinked formats, this should generate a link target;
        -- for other formats, only the text is generated.
    begin
        Ordinary_Text (Output_Object, Text); -- Nothing special in this format.
    end Local_Target;


    procedure Local_Link (Output_Object : in out Corr_Output_Type;
                          Text : in String;
                          Target : in String;
                          Clause_Number : in String) is
        -- Generate a local link to the target and clause given.
        -- Text is the text of the link.
        -- For hyperlinked formats, this should generate a link;
        -- for other formats, only the text is generated.
    begin
        Ordinary_Text (Output_Object, Text); -- Nothing special in this format.
    end Local_Link;


    procedure Local_Link_Start (Output_Object : in out Corr_Output_Type;
                                Target : in String;
                                Clause_Number : in String) is
        -- Generate a local link to the target and clause given.
        -- The link will surround text until Local_Link_End is called.
        -- Local_Link_End must be called before this routine can be used again.
        -- For hyperlinked formats, this should generate a link;
        -- for other formats, only the text is generated.
    begin
        null; -- No link, nothing to do.
    end Local_Link_Start;


    procedure Local_Link_End (Output_Object : in out Corr_Output_Type;
                              Target : in String;
                              Clause_Number : in String) is
        -- End a local link for the target and clause given.
        -- This must be in the same paragraph as the Local_Link_Start.
        -- For hyperlinked formats, this should generate a link;
        -- for other formats, only the text is generated.
    begin
        null; -- No link, nothing to do.
    end Local_Link_End;


    procedure URL_Link (Output_Object : in out Corr_Output_Type;
                        Text : in String;
                        URL : in String) is
        -- Generate a link to the URL given.
        -- Text is the text of the link.
        -- For hyperlinked formats, this should generate a link;
        -- for other formats, only the text is generated.
    begin
        Ordinary_Text (Output_Object, Text); -- Nothing special in this format.
    end URL_Link;


    procedure Picture  (Output_Object : in out Corr_Output_Type;
                        Name  : in String;
                        Descr : in String;
                        Alignment : in ARM_Output.Picture_Alignment;
                        Height, Width : in Natural;
                        Border : in ARM_Output.Border_Kind) is
        -- Generate a picture.
        -- Name is the (simple) file name of the picture; Descr is a
        -- descriptive name for the picture (it will appear in some web
        -- browsers).
        -- We assume that it is a .GIF or .JPG and that it will be present
        -- in the same directory as the input files and the same directory as
        -- the .HTML output files.
        -- Alignment specifies the picture alignment.
        -- Height and Width specify the picture size in pixels.
        -- Border specifies the kind of border.
    begin
        Ordinary_Text (Output_Object, "[Picture: " & Name &
          " - " & Descr & "]");
    end Picture;

end ARM_Corr;
