--===========================================================================
---------------------------- PROCEDURE PARSER -------------------------------
--===========================================================================
-- PARSER parses a LINE and returns the number of tokens in that LINE
-- and the first token as COMMAND (converted to lower-case) with the
-- rest of the tokens in ARGS (a linked list of argument LINEs)
 
with LINE_DEFINITION;
use  LINE_DEFINITION;
procedure PARSER(INLINE  : in LINE_DEFINITION.LINE;
		 NARGS   : out NATURAL;
		 COMMAND : out LINE_DEFINITION.LINE;
		 ARGS    : in out LINE_DEFINITION.LINE_LIST) is
 
    ROVER    : NATURAL;
    LROVER   : LINE_DEFINITION.LINE_LIST := null;
    LFIRST   : LINE_DEFINITION.LINE_LIST := null;
    LCOMMAND : LINE_DEFINITION.LINE;
    LTEMP    : LINE_DEFINITION.LINE;
    LARGS    : NATURAL                   := 0;
 
    procedure SKIP_SPACES is
    begin
	while INLINE.CONTENT(ROVER) <= ' ' and ROVER <= INLINE.LAST loop
	    ROVER := ROVER + 1;
	end loop;
    end SKIP_SPACES;
 
    procedure EXTRACT(ITEM : out LINE_DEFINITION.LINE) is
	EXTRACT_ROVER : NATURAL := 0;
    begin
	while INLINE.CONTENT(ROVER) > ' ' and ROVER <= INLINE.LAST loop
	    EXTRACT_ROVER := EXTRACT_ROVER + 1;
	    ITEM.CONTENT(EXTRACT_ROVER) := INLINE.CONTENT(ROVER);
	    ROVER := ROVER + 1;
	end loop;
	ITEM.LAST := EXTRACT_ROVER;
    end EXTRACT;
 
begin
    COMMAND.LAST := 0;
    ROVER := INLINE.CONTENT'FIRST;
    SKIP_SPACES;
    if ROVER <= INLINE.LAST then
	EXTRACT(LCOMMAND);
	LCOMMAND.LAST := LCOMMAND.LAST + 1;
	LCOMMAND.CONTENT(LCOMMAND.LAST) := ' ';
	COMMAND := LINE_DEFINITION.TOLOWER(LCOMMAND);
	LARGS := 1;
        LROVER := ARGS;
	while ROVER <= INLINE.LAST loop
	    SKIP_SPACES;
	    if ROVER <= INLINE.LAST then
		EXTRACT(LTEMP);
		if ARGS = null then
		    ARGS := new LINE_DEFINITION.LINE_LIST_ELEMENT;
		    LROVER := ARGS;
		    LROVER.NEXT := null;
		end if;
		LROVER.CONTENT := LTEMP;
		LARGS := LARGS + 1;
                if LROVER.NEXT = null then
                    LROVER.NEXT := new LINE_DEFINITION.LINE_LIST_ELEMENT;
                end if;
                LROVER := LROVER.NEXT;
	    end if;
	end loop;
    end if;
    NARGS := LARGS;
end PARSER;
 
--===========================================================================
---------------------------- PACKAGE PAGED_FILE -----------------------------
--===========================================================================
with LINE_DEFINITION;
package PAGED_FILE is

    procedure COMPUTE_CHECKSUM (NARGS   : in NATURAL;
                                ARGLIST : in LINE_DEFINITION.LINE_LIST);
    -- Compute the checksum of a paged file

    procedure MAKE_INCLUDE_FILE (NARGS   : in NATURAL;
                                 ARGLIST : in LINE_DEFINITION.LINE_LIST);
    -- Create an include file which names the elements of a paged file

    procedure LIST (NARGS   : in NATURAL;
                    ARGLIST : in LINE_DEFINITION.LINE_LIST);
    -- List the names of the elements of a paged file

    procedure CREATE (NARGS   : in NATURAL;
                      ARGLIST : in LINE_DEFINITION.LINE_LIST);
    -- Create a paged file

    procedure UNPAGE (NARGS   : in NATURAL;
                      ARGLIST : in LINE_DEFINITION.LINE_LIST);
    -- Extract the elements of a paged file

end PAGED_FILE;

with INCLUDE_FILE, INPUT_FILE, OUTPUT_FILE, PARSER;
with TEXT_IO;
package body PAGED_FILE is

    INLINE          : LINE_DEFINITION.LINE;
 
    --=======================================================================
    -- PAGED_FILE, Support Utilities
    --=======================================================================
 
    use  LINE_DEFINITION;

    -- Determine if ITEM contains a BANNER or COMMENT_BANNER
    function IS_BANNER(ITEM : in LINE_DEFINITION.LINE) return BOOLEAN is
	RESULT : BOOLEAN;
    begin
	if ITEM.LAST >= LINE_DEFINITION.BANNER'LENGTH and then
	  ITEM.CONTENT(1 .. LINE_DEFINITION.BANNER'LENGTH) =
	  LINE_DEFINITION.BANNER then
	    RESULT := TRUE;
	elsif ITEM.LAST >= LINE_DEFINITION.COMMENT_BANNER'LENGTH and then
	  ITEM.CONTENT(1 .. LINE_DEFINITION.COMMENT_BANNER'LENGTH) =
	  LINE_DEFINITION.COMMENT_BANNER then
	    RESULT := TRUE;
	else
	    RESULT := FALSE;
	end if;
	return RESULT;
    end IS_BANNER;
 
    -- Package to handle line counting
    package COUNTER is
 
        -- Reset the Counter
	procedure SET;
 
        -- Increment the Counter
	procedure INCREMENT;
 
        -- Print the counter
	procedure PRINT;
 
    end COUNTER;
 
    package body COUNTER is
 
	type LINE_COUNT is range 0 .. 10001;
	package LINE_COUNT_IO is new TEXT_IO.INTEGER_IO(LINE_COUNT);
 
	LCOUNT : LINE_COUNT;
 
        -- Reset the LCOUNT variable
	procedure SET is
	begin
	    LCOUNT := 0;
	end SET;
 
        -- Increment the LCOUNT variable
	procedure INCREMENT is
	begin
	    if LCOUNT < LINE_COUNT'LAST then
		LCOUNT := LCOUNT + 1;
	    end if;
	end INCREMENT;
 
        -- Print a count of the number of lines and reset the LCOUNT variable
	procedure PRINT is
	begin
	    TEXT_IO.PUT(" -- ");
	    if LCOUNT = LINE_COUNT'LAST then
		TEXT_IO.PUT("More Than" & LINE_COUNT'IMAGE(LINE_COUNT'LAST -
		  1));
	    else
		LINE_COUNT_IO.PUT(LCOUNT, 1);
	    end if;
	    TEXT_IO.PUT_LINE(" Lines");
	    LCOUNT := 0;
	end PRINT;
 
    end COUNTER;
 
    --=======================================================================
    -- PAGED_FILE, COMPUTE_CHECKSUM Command
    --=======================================================================
    procedure COMPUTE_CHECKSUM (NARGS   : in NATURAL;
                                ARGLIST : in LINE_DEFINITION.LINE_LIST) is
	CHECKSUM : INTEGER;
	package VALUE_IO is new TEXT_IO.INTEGER_IO(INTEGER);
    begin
	if NARGS = 1 then
	    TEXT_IO.PUT_LINE(" CHECK Command requires the name of a file");
	    TEXT_IO.PUT_LINE("   Syntax: list file_name");
	else
 
            -- Step 1: Open the input file
	    INPUT_FILE.OPEN(ARGLIST.CONTENT);
 
            -- Step 2: Compute the Hash (Checksum)
	    CHECKSUM := 0;
	    while not INPUT_FILE.END_OF_FILE loop
		INPUT_FILE.READ(INLINE);
		for I in 1 .. INLINE.LAST loop
		    if INLINE.CONTENT(I) > ' ' then
			CHECKSUM := CHECKSUM +
			  CHARACTER'POS(INLINE.CONTENT(I));
			if CHECKSUM >= 128 then
			    CHECKSUM := CHECKSUM - 128;
			end if;
		    end if;
		end loop;
	    end loop;
	    INPUT_FILE.CLOSE;
 
            -- Step 3: Print the result
	    TEXT_IO.PUT(" Pager Checksum (Hash) of " &
	      LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) & " is ");
	    VALUE_IO.PUT(CHECKSUM, 1);
	    TEXT_IO.NEW_LINE;
 
	end if;
 
    exception
	when INPUT_FILE.FILE_NOT_FOUND =>
            TEXT_IO.PUT(" CHECK:");
	    TEXT_IO.PUT_LINE(" File " &
              LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) &
	      " not Found");
	when INPUT_FILE.READ_PAST_END_OF_FILE =>
            TEXT_IO.PUT(" CHECK:");
	    TEXT_IO.PUT_LINE(" Premature EOF on " &
	      LINE_DEFINITION.CONVERT(ARGLIST.CONTENT));
	    INPUT_FILE.CLOSE;
	when others =>
            TEXT_IO.PUT(" CHECK:");
	    TEXT_IO.PUT_LINE(" Unexpected Error");
	    INPUT_FILE.CLOSE;
 
    end COMPUTE_CHECKSUM;
 
    --=======================================================================
    -- PAGED_FILE, MAKE_INCLUDE_FILE Command
    --=======================================================================
    procedure MAKE_INCLUDE_FILE (NARGS   : in NATURAL;
                                 ARGLIST : in LINE_DEFINITION.LINE_LIST) is
	IN_FILE   : BOOLEAN;
        ARG_ROVER : LINE_DEFINITION.LINE_LIST;
    begin
	if NARGS < 3 then
	    TEXT_IO.PUT_LINE
              (" INCLUDE Command requires the name of a paged file");
	    TEXT_IO.PUT_LINE
              ("   Syntax: include paged_file_name output_include_file");
	else
 
            -- Step 1: Open the input and output files
	    COUNTER.SET;
	    ARG_ROVER := ARGLIST.NEXT;
	    INPUT_FILE.OPEN(ARGLIST.CONTENT);
	    OUTPUT_FILE.OPEN(ARG_ROVER.CONTENT);
	    OUTPUT_FILE.WRITE("-- Include file for " &
	      LINE_DEFINITION.CONVERT(ARGLIST.CONTENT));
 
            -- Step 2: Look for the first banner in the paged file
	    IN_FILE := TRUE;
	    while not INPUT_FILE.END_OF_FILE loop
		INPUT_FILE.READ(INLINE);
		if IS_BANNER(INLINE) then
		    IN_FILE := FALSE;
		    exit;
		end if;
	    end loop;
 
            -- Step 3: If first banner not found, issue error message,
            --         else process component files
	    if IN_FILE then
		TEXT_IO.PUT_LINE
                  (" File " & LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) &
		  " does not contain any components");
	    else
 
                -- Loop until the end of the input paged file
		while not INPUT_FILE.END_OF_FILE loop
 
                    -- Read the next line from the input paged file
		    INPUT_FILE.READ(INLINE);
 
                    -- If we are not in the text of the file, the line just
                    -- read contains the name of a new file, else it contains
                    -- a line of the current component file
		    if not IN_FILE then
 
                    -- Remove leading comment character if any and print the
                    -- name of the component file
			if INLINE.CONTENT(1 .. 2) = "--" then
			    TEXT_IO.PUT(" " &
			      INLINE.CONTENT(3 .. INLINE.LAST));
			    OUTPUT_FILE.WRITE
                              (INLINE.CONTENT(3 .. INLINE.LAST));
			else
			    TEXT_IO.PUT(" " &
			      INLINE.CONTENT(1 .. INLINE.LAST));
			    OUTPUT_FILE.WRITE
                              (INLINE.CONTENT(1 .. INLINE.LAST));
			end if;
 
                        -- Flush the trailing banner line and note that we are
                        -- now within the text of a component file
			INPUT_FILE.READ(INLINE);
			COUNTER.SET;
			IN_FILE := TRUE;
 
		    else
 
                    -- We are within the text of a component file, so check
                    -- for a banner in order to determine if we are at the end
                    -- of the component file
			if IS_BANNER(INLINE) then
			    IN_FILE := FALSE;
			    COUNTER.PRINT;
			else
			    COUNTER.INCREMENT;
			end if;
 
		    end if;
 
		end loop;
 
	    end if;
 
	    COUNTER.PRINT;
	    INPUT_FILE.CLOSE;
	    OUTPUT_FILE.CLOSE;
 
	end if;
 
    exception
	when OUTPUT_FILE.CANNOT_CREATE_FILE =>
            TEXT_IO.PUT(" INCLUDE:");
	    TEXT_IO.PUT_LINE(" Cannot create " &
	      LINE_DEFINITION.CONVERT(ARG_ROVER.CONTENT));
	when INPUT_FILE.FILE_NOT_FOUND =>
            TEXT_IO.PUT(" INCLUDE:");
	    TEXT_IO.PUT_LINE
              (" File " & LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) &
	      " not Found");
	when INPUT_FILE.READ_PAST_END_OF_FILE =>
            TEXT_IO.PUT(" INCLUDE:");
	    TEXT_IO.PUT_LINE(" Premature EOF on " &
	      LINE_DEFINITION.CONVERT(ARGLIST.CONTENT));
	    INPUT_FILE.CLOSE;
	when others =>
            TEXT_IO.PUT(" INCLUDE:");
	    TEXT_IO.PUT_LINE(" Unexpected Error");
	    INPUT_FILE.CLOSE;
 
    end MAKE_INCLUDE_FILE;
 
    --=======================================================================
    -- PAGED_FILE, LIST Command
    --=======================================================================
    procedure LIST (NARGS   : in NATURAL;
                    ARGLIST : in LINE_DEFINITION.LINE_LIST) is
	IN_FILE : BOOLEAN;
    begin
	if NARGS = 1 then
	    TEXT_IO.PUT_LINE
              (" LIST Command requires the name of a paged file");
	    TEXT_IO.PUT_LINE
              ("   Syntax: list paged_file_name");
	else
 
            -- Step 1: Open the input file
	    COUNTER.SET;
	    INPUT_FILE.OPEN(ARGLIST.CONTENT);
 
            -- Step 2: Look for the first banner in the paged file
	    IN_FILE := TRUE;
	    while not INPUT_FILE.END_OF_FILE loop
		INPUT_FILE.READ(INLINE);
		if IS_BANNER(INLINE) then
		    IN_FILE := FALSE;
		    exit;
		end if;
	    end loop;
 
            -- Step 3: If first banner not found, issue error message,
            --         else process component files
	    if IN_FILE then
		TEXT_IO.PUT_LINE
                  (" File " & LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) &
		  " does not contain any components");
	    else
 
                -- Loop until the end of the input paged file
		while not INPUT_FILE.END_OF_FILE loop
 
                    -- Read the next line from the input paged file
		    INPUT_FILE.READ(INLINE);
 
                    -- If we are not in the text of the file, the line just
                    -- read contains the name of a new file, else it contains
                    -- a line of the current component file
		    if not IN_FILE then
 
                        -- Remove leading comment character if any and print
                        -- the name of the component file
			if INLINE.CONTENT(1 .. 2) = "--" then
			    TEXT_IO.PUT(" " &
			      INLINE.CONTENT(3 .. INLINE.LAST));
			else
			    TEXT_IO.PUT(" " &
			      INLINE.CONTENT(1 .. INLINE.LAST));
			end if;
 
                        -- Flush the trailing banner line and note that we are
                        -- now within the text of a component file
			INPUT_FILE.READ(INLINE);
			COUNTER.SET;
			IN_FILE := TRUE;
 
		    else
 
                        -- We are within the text of a component file, so
                        -- check for a banner in order to determine if we
                        -- are at the end of the component file
			if IS_BANNER(INLINE) then
			    IN_FILE := FALSE;
			    COUNTER.PRINT;
			else
			    COUNTER.INCREMENT;
			end if;
 
		    end if;
 
		end loop;
 
	    end if;
 
	    COUNTER.PRINT;
	    INPUT_FILE.CLOSE;
 
	end if;
 
    exception
	when INPUT_FILE.FILE_NOT_FOUND =>
            TEXT_IO.PUT(" LIST:");
	    TEXT_IO.PUT_LINE
              (" File " & LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) &
	      " not Found");
	when INPUT_FILE.READ_PAST_END_OF_FILE =>
            TEXT_IO.PUT(" LIST:");
	    TEXT_IO.PUT_LINE(" Premature EOF on " &
	      LINE_DEFINITION.CONVERT(ARGLIST.CONTENT));
	    INPUT_FILE.CLOSE;
	when others =>
            TEXT_IO.PUT(" LIST:");
	    TEXT_IO.PUT_LINE(" Unexpected Error");
	    INPUT_FILE.CLOSE;
 
    end LIST;
 
    --=======================================================================
    -- PAGED_FILE, CREATE Command
    --=======================================================================
    procedure CREATE (NARGS   : in NATURAL;
                      ARGLIST : in LINE_DEFINITION.LINE_LIST) is
	COMPONENT_FILE_NAME : LINE_DEFINITION.LINE;
	OUTPUT_FILE_NAME    : LINE_DEFINITION.LINE;
        ARG_ROVER           : LINE_DEFINITION.LINE_LIST;
    begin
	if NARGS < 3 then
	    TEXT_IO.PUT_LINE
              (" PAGE Command requires the name of the paged file and include file");
	    TEXT_IO.PUT_LINE
              ("   Syntax: page [@include_file_name|file_name]+ paged_file_name");
	else
	    ARG_ROVER := ARGLIST;
            for I in 1 .. NARGS-2 loop
		ARG_ROVER := ARG_ROVER.NEXT;
	    end loop;
	    OUTPUT_FILE_NAME := ARG_ROVER.CONTENT;
	    OUTPUT_FILE.OPEN(OUTPUT_FILE_NAME);
	    ARG_ROVER := ARGLIST;
	    for I in 1 .. NARGS-2 loop
		if ARG_ROVER.CONTENT.CONTENT(1) =
		  INCLUDE_FILE.INCLUDE_CHARACTER then
		    INCLUDE_FILE.OPEN
                      (LINE_DEFINITION.CONVERT(ARG_ROVER.CONTENT));
		    begin
			loop
			    INCLUDE_FILE.READ(COMPONENT_FILE_NAME);
			    INPUT_FILE.OPEN(COMPONENT_FILE_NAME);
			    OUTPUT_FILE.WRITE(LINE_DEFINITION.COMMENT_BANNER);
			    OUTPUT_FILE.WRITE("--" &
			      LINE_DEFINITION.CONVERT(COMPONENT_FILE_NAME));
			    OUTPUT_FILE.WRITE(LINE_DEFINITION.COMMENT_BANNER);
			    TEXT_IO.PUT(" Adding " &
			      LINE_DEFINITION.CONVERT(COMPONENT_FILE_NAME));
			    COUNTER.SET;
			    while not INPUT_FILE.END_OF_FILE loop
				INPUT_FILE.READ(INLINE);
				OUTPUT_FILE.WRITE(INLINE);
				COUNTER.INCREMENT;
			    end loop;
			    COUNTER.PRINT;
			    INPUT_FILE.CLOSE;
			end loop;
		    exception
			when INCLUDE_FILE.READ_PAST_END_OF_FILE |
			  INCLUDE_FILE.INCLUDE_FILE_EMPTY |
                          INCLUDE_FILE.NESTING_LEVEL_EXCEEDED =>
                            INCLUDE_FILE.STOP;
			when INPUT_FILE.FILE_NOT_FOUND =>
			    TEXT_IO.PUT_LINE(" File " &
			      LINE_DEFINITION.CONVERT(COMPONENT_FILE_NAME) &
			      " not Found");
			    INCLUDE_FILE.STOP;
			when others =>
			    TEXT_IO.PUT_LINE
                              (" Unexpected Error During Processing " &
                              "of Component File " &
			      LINE_DEFINITION.CONVERT(COMPONENT_FILE_NAME));
			    INCLUDE_FILE.STOP;
		    end;
		else
		    INPUT_FILE.OPEN(ARG_ROVER.CONTENT);
		    OUTPUT_FILE.WRITE(LINE_DEFINITION.COMMENT_BANNER);
		    OUTPUT_FILE.WRITE("--" &
		      LINE_DEFINITION.CONVERT(ARG_ROVER.CONTENT));
		    OUTPUT_FILE.WRITE(LINE_DEFINITION.COMMENT_BANNER);
		    TEXT_IO.PUT(" Adding " &
		      LINE_DEFINITION.CONVERT(ARG_ROVER.CONTENT));
		    COUNTER.SET;
		    while not INPUT_FILE.END_OF_FILE loop
			INPUT_FILE.READ(INLINE);
			OUTPUT_FILE.WRITE(INLINE);
			COUNTER.INCREMENT;
		    end loop;
		    COUNTER.PRINT;
		    INPUT_FILE.CLOSE;
		end if;
                ARG_ROVER := ARG_ROVER.NEXT;
	    end loop;
            OUTPUT_FILE.CLOSE;
	end if;
 
    exception
	when OUTPUT_FILE.CANNOT_CREATE_FILE =>
            TEXT_IO.PUT(" PAGE:");
	    TEXT_IO.PUT_LINE(" Cannot create " &
	      LINE_DEFINITION.CONVERT(OUTPUT_FILE_NAME));
	when INCLUDE_FILE.FILE_NOT_FOUND =>
            TEXT_IO.PUT(" PAGE:");
	    TEXT_IO.PUT_LINE(" Cannot open include file");
	when others =>
            TEXT_IO.PUT(" PAGE:");
	    TEXT_IO.PUT_LINE(" Unexpected Error");
	    INPUT_FILE.CLOSE;
 
    end CREATE;
 
    --=======================================================================
    -- PAGED_FILE, UNPAGE Command
    --=======================================================================
    procedure UNPAGE (NARGS   : in NATURAL;
                      ARGLIST : in LINE_DEFINITION.LINE_LIST) is
	IN_FILE          : BOOLEAN;
	OUTPUT_FILE_NAME : LINE_DEFINITION.LINE;
    begin
	if NARGS = 1 then
	    TEXT_IO.PUT_LINE
              (" UNPAGE Command requires the name of a paged file");
	    TEXT_IO.PUT_LINE("   Syntax: unpage paged_file_name");
	else
 
            -- Step 1: Open the input file
	    COUNTER.SET;
	    INPUT_FILE.OPEN(ARGLIST.CONTENT);
 
            -- Step 2: Look for the first banner in the paged file
	    IN_FILE := TRUE;
	    while not INPUT_FILE.END_OF_FILE loop
		INPUT_FILE.READ(INLINE);
		if IS_BANNER(INLINE) then
		    IN_FILE := FALSE;
		    exit;
		end if;
	    end loop;
 
            -- Step 3: If first banner not found, issue error message,
            --         else process component files
	    if IN_FILE then
		TEXT_IO.PUT_LINE(" File " &
                  LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) &
		  " does not contain any components");
	    else
 
                -- Loop until the end of the input paged file
		while not INPUT_FILE.END_OF_FILE loop
 
                    -- Read the next line from the input paged file
		    INPUT_FILE.READ(INLINE);
 
                    -- If we are not in the text of the file, the line just
                    -- read contains the name of a new file, else it contains
                    -- a line of the current component file
		    if not IN_FILE then
 
                        -- Remove leading comment character if any and
                        -- store the name of the component file
			if INLINE.CONTENT(1 .. 2) = "--" then
			    OUTPUT_FILE_NAME :=
			      LINE_DEFINITION.CONVERT
                                (INLINE.CONTENT(3 .. INLINE.LAST));
			else
			    OUTPUT_FILE_NAME :=
			      LINE_DEFINITION.CONVERT
                                (INLINE.CONTENT(1 .. INLINE.LAST));
			end if;
 
                        -- Open the new component file
			OUTPUT_FILE.OPEN(OUTPUT_FILE_NAME);
			TEXT_IO.PUT(" Extracting " &
			  LINE_DEFINITION.CONVERT(OUTPUT_FILE_NAME));
 
                        -- Flush the trailing banner line and note that we are
                        -- now within the text of a component file
			INPUT_FILE.READ(INLINE);
			IN_FILE := TRUE;
			COUNTER.SET;
 
		    else
 
                        -- We are within the text of a component file, so
                        -- check for a banner in order to determine if we
                        -- are at the end of the component file
			if IS_BANNER(INLINE) then
			    OUTPUT_FILE.CLOSE;
			    IN_FILE := FALSE;
			    COUNTER.PRINT;
			else
			    OUTPUT_FILE.WRITE(INLINE);
			    COUNTER.INCREMENT;
			end if;
 
		    end if;
 
		end loop;
 
		OUTPUT_FILE.CLOSE;
 
	    end if;
 
	    COUNTER.PRINT;
	    INPUT_FILE.CLOSE;
 
	end if;
 
    exception
	when OUTPUT_FILE.CANNOT_CREATE_FILE =>
            TEXT_IO.PUT(" UNPAGE:");
	    TEXT_IO.PUT_LINE(" Cannot create " &
	      LINE_DEFINITION.CONVERT(OUTPUT_FILE_NAME));
	when INPUT_FILE.FILE_NOT_FOUND =>
            TEXT_IO.PUT(" UNPAGE:");
	    TEXT_IO.PUT_LINE(" File " &
              LINE_DEFINITION.CONVERT(ARGLIST.CONTENT) &
	      " not Found");
	when INPUT_FILE.READ_PAST_END_OF_FILE =>
            TEXT_IO.PUT(" UNPAGE:");
	    TEXT_IO.PUT_LINE(" Premature EOF on " &
	      LINE_DEFINITION.CONVERT(ARGLIST.CONTENT));
	    INPUT_FILE.CLOSE;
	when others =>
            TEXT_IO.PUT(" UNPAGE:");
	    TEXT_IO.PUT_LINE(" Unexpected Error");
	    INPUT_FILE.CLOSE;
 
    end UNPAGE;
 
end PAGED_FILE;

--===========================================================================
--------------------------------- MAINLINE ----------------------------------
--===========================================================================
with LINE_DEFINITION, PAGED_FILE, PARSER;
use  LINE_DEFINITION;
with TEXT_IO;
with CLI;
procedure PAGER2 is
 
    TITLE           : constant STRING := "PAGER2, Ada Version 1.1";
 
    INLINE          : LINE_DEFINITION.LINE;
 
    NARGS           : NATURAL;
    COMMAND         : LINE_DEFINITION.LINE;
    ARGLIST         : LINE_DEFINITION.LINE_LIST;
    ARG_ROVER       : LINE_DEFINITION.LINE_LIST;
 
    -- Command Verbs
    HELP_COMMAND    : constant STRING := "help ";
    H_COMMAND       : constant STRING := "h ";
    EXIT_COMMAND    : constant STRING := "exit ";
    X_COMMAND       : constant STRING := "x ";    -- same as exit
    CHECK_COMMAND   : constant STRING := "check ";
    C_COMMAND       : constant STRING := "c ";    -- same as check
    INCLUDE_COMMAND : constant STRING := "include ";
    I_COMMAND       : constant STRING := "i ";    -- same as include
    LIST_COMMAND    : constant STRING := "list ";
    L_COMMAND       : constant STRING := "l ";    -- same as list
    PAGE_COMMAND    : constant STRING := "page ";
    P_COMMAND       : constant STRING := "p ";    -- same as page
    UNPAGE_COMMAND  : constant STRING := "unpage ";
    U_COMMAND       : constant STRING := "u ";    -- same as unpage
 
    --=======================================================================
    -- PAGER2, Support Utilities
    --=======================================================================
 
    -- Determine if COMMAND contains one of the two target command strings
    function IS_COMMAND(TARGET1_COMMAND, TARGET2_COMMAND : in STRING)
			return BOOLEAN is
        START : NATURAL;
    begin
        if COMMAND.CONTENT(1) = '-' then
            START := 2;
        else
            START := 1;
        end if;
	if COMMAND.CONTENT(START .. TARGET1_COMMAND'LENGTH + START - 1)
              = TARGET1_COMMAND or
	  COMMAND.CONTENT(START .. TARGET2_COMMAND'LENGTH + START - 1)
              = TARGET2_COMMAND then
	    return TRUE;
	else
	    return FALSE;
	end if;
    end IS_COMMAND;
 
    --=======================================================================
    -- PAGER2, HELP Command
    --=======================================================================
    procedure HELP is
	procedure SPACER is
	begin
	    TEXT_IO.PUT("                  ");
	end SPACER;
    begin
	TEXT_IO.PUT_LINE(" Command Summary");
	TEXT_IO.PUT_LINE("  help or h   - this summary");
	SPACER;
	TEXT_IO.PUT_LINE("Syntax: help");
	TEXT_IO.PUT_LINE("  exit or x   - exit from program");
	SPACER;
	TEXT_IO.PUT_LINE("Syntax: exit");
	TEXT_IO.PUT_LINE
          ("  include or i- list components into an include file");
	SPACER;
	TEXT_IO.PUT_LINE
          ("Syntax: include paged_file_name output_include_file");
	TEXT_IO.PUT_LINE("  list or l   - list components of paged file");
	SPACER;
	TEXT_IO.PUT_LINE("Syntax: list paged_file_name");
	TEXT_IO.PUT_LINE
          ("  page or p   - create paged file from include file");
	SPACER;
	TEXT_IO.PUT_LINE
          ("Syntax: page [@include_file_name|file_name]+ paged_file_name");
	TEXT_IO.PUT_LINE
          ("  unpage or u - extract components from paged file");
	SPACER;
	TEXT_IO.PUT_LINE("Syntax: unpage paged_file_name");
    end HELP;
 
--=======================================================================
-- PAGER2, Mainline
--=======================================================================
begin
    CLI.INITIALIZE ("PAGER2", "Enter verb and arguments: ");

    -- Interactive mode if no arguments
    if CLI.ARGC = 1 then
	TEXT_IO.PUT_LINE(TITLE);
	TEXT_IO.PUT_LINE("Type 'h' for Help");
	loop
	    begin
		TEXT_IO.PUT("PAGER2> ");
		TEXT_IO.GET_LINE(INLINE.CONTENT, INLINE.LAST);
		PARSER(INLINE, NARGS, COMMAND, ARGLIST);
		if NARGS > 0 then
		    exit when IS_COMMAND(EXIT_COMMAND, X_COMMAND);
		    if IS_COMMAND(HELP_COMMAND, H_COMMAND) then
			HELP;
		    elsif IS_COMMAND(CHECK_COMMAND, C_COMMAND) then
			PAGED_FILE.COMPUTE_CHECKSUM (NARGS, ARGLIST);
		    elsif IS_COMMAND(INCLUDE_COMMAND, I_COMMAND) then
			PAGED_FILE.MAKE_INCLUDE_FILE (NARGS, ARGLIST);
		    elsif IS_COMMAND(LIST_COMMAND, L_COMMAND) then
			PAGED_FILE.LIST (NARGS, ARGLIST);
		    elsif IS_COMMAND(PAGE_COMMAND, P_COMMAND) then
			PAGED_FILE.CREATE (NARGS, ARGLIST);
		    elsif IS_COMMAND(UNPAGE_COMMAND, U_COMMAND) then
			PAGED_FILE.UNPAGE (NARGS, ARGLIST);
		    else
			TEXT_IO.PUT_LINE(" Invalid Command: " &
			  LINE_DEFINITION.CONVERT(COMMAND));
		    end if;
		end if;
	    exception
		when others =>
		    null;
	    end;
	end loop;
    -- Non-interactive mode if one or more arguments
    else
	COMMAND := TOLOWER(LINE_DEFINITION.CONVERT(CLI.ARGV(1) & " "));
	NARGS := CLI.ARGC - 1;
	ARGLIST := null;
	for I in 2 .. CLI.ARGC - 1 loop
	    if I = 2 then
		ARGLIST := new LINE_DEFINITION.LINE_LIST_ELEMENT;
		ARG_ROVER := ARGLIST;
	    else
		ARG_ROVER.NEXT := new LINE_DEFINITION.LINE_LIST_ELEMENT;
		ARG_ROVER := ARG_ROVER.NEXT;
	    end if;
	    ARG_ROVER.NEXT := null;
	    ARG_ROVER.CONTENT := LINE_DEFINITION.CONVERT(CLI.ARGV(I));
	end loop;
	if NARGS > 0 then
	    if IS_COMMAND(HELP_COMMAND, H_COMMAND) then
		HELP;
	    elsif IS_COMMAND(CHECK_COMMAND, C_COMMAND) then
		PAGED_FILE.COMPUTE_CHECKSUM (NARGS, ARGLIST);
	    elsif IS_COMMAND(INCLUDE_COMMAND, I_COMMAND) then
		PAGED_FILE.MAKE_INCLUDE_FILE (NARGS, ARGLIST);
	    elsif IS_COMMAND(LIST_COMMAND, L_COMMAND) then
		PAGED_FILE.LIST (NARGS, ARGLIST);
	    elsif IS_COMMAND(PAGE_COMMAND, P_COMMAND) then
		PAGED_FILE.CREATE (NARGS, ARGLIST);
	    elsif IS_COMMAND(UNPAGE_COMMAND, U_COMMAND) then
		PAGED_FILE.UNPAGE (NARGS, ARGLIST);
	    elsif IS_COMMAND(EXIT_COMMAND, X_COMMAND) then
		null;
	    else
		TEXT_IO.PUT_LINE(" Invalid Command: " &
		  LINE_DEFINITION.CONVERT(COMMAND));
	    end if;
	end if;
    end if;
exception
    when others =>
	null;
end PAGER2;
