::::::::::
pager.dis
::::::::::
--
-- Distribution files for PAGER
--    PAGER_COMPILE.DIS gives the source files in
--      compilation order
--    PAGER_DOCUMENTATION.DIS gives the documentation files
--
pager.pro
@pager_compile.dis
@pager_documentation.dis
::::::::::
pager.pro
::::::::::

-------- SIMTEL20 Ada Software Repository Prologue ------------
--                                                           -*
-- Unit name    : PAGER
-- Version      : 1.6
-- Author       : Richard Conn
--              : TI Ada Technology Branch
--              : PO Box 801, MS 8007
--              : McKinney, TX  75069
-- DDN Address  : RCONN at SIMTEL20
-- Copyright    : (c) 1985 by Richard Conn
-- Date created : 8 Apr 85
-- Release date : 8 Apr 85
-- Last update  : 30 Oct 85
-- Machine/System Compiled/Run on : DG MV10000, ROLM ADE
--                                  DEC VAX 11/785, DEC Ada
--                                                           -*
---------------------------------------------------------------
--                                                           -*
-- Keywords     : PAGED FILES, LIBRARY, REPOSITORY, PAGER, UNPAGE
----------------:
--
-- Abstract     : PAGER is a tool which creates, extracts from,
-- and scans paged files, where a paged file is a file composed
-- of one or more files prefixed by banners.  PAGER is based in
-- concept on the UNPAGE tool submitted to the Ada Repository on
-- SIMTEL20 by Mitre Corporation.
--
--      Paged files are convenient mechanisms for storing related files.
-- They reduce cluttering in the directories and simplify the file
-- transfer process (to and from the Ada Repository, for example) by
-- requiring the user to transfer only one file in order to obtain all
-- files pertinent to a particular project or tool.  Additionally, paged
-- files are text files which can be handled more readily than the 8-bit
-- binary images associated with other file grouping mechanisms.  Paged
-- files may be manipulated by a text editor if necessary.
--                                                           -*
------------------ Revision history ---------------------------
--                                                           -*
-- DATE         VERSION AUTHOR                  HISTORY
-- 4/8/1985       1.4   Richard Conn            Initial Release
-- 5/6/1985       1.5   Richard Conn            Numeric Error Trap Added
-- 10/30/1985	  1.6	Richard Conn		LIST Command Added
--                                                           -*
------------------ Distribution and Copyright -----------------
--                                                           -*
-- This prologue must be included in all copies of this software.
--
-- This software is copyright by the author.
--
-- This software is released to the Ada community.
-- This software is released to the Public Domain (note:
--   software released to the Public Domain is not subject
--   to copyright protection).
-- Restrictions on use or distribution:  NONE
--                                                           -*
------------------ Disclaimer ---------------------------------
--                                                           -*
-- This software and its documentation are provided "AS IS" and
-- without any expressed or implied warranties whatsoever.
-- No warranties as to performance, merchantability, or fitness
-- for a particular purpose exist.
--
-- Because of the diversity of conditions and hardware under
-- which this software may be used, no warranty of fitness for
-- a particular purpose is offered.  The user is advised to
-- test the software thoroughly before relying on it.  The user
-- must assume the entire risk and liability of using this
-- software.
--
-- In no event shall any person or organization of people be
-- held responsible for any direct, indirect, consequential
-- or inconsequential damages or lost profits.
--                                                           -*
-------------------END-PROLOGUE--------------------------------
::::::::::
pager_compile.dis
::::::::::
--
-- Compilation order for all files required to create the
--  PAGER program
--
character_set.ada
cas3.ada
pager_support.ada
pager.ada
::::::::::
character_set.ada
::::::::::
--
-- Components Package CHARACTER_SET
-- by Richard Conn, TI Ada Technology Branch
-- Version 1.1, Date 25 Feb 85
-- Version 1.0, Date 13 Feb 85
--
package CHARACTER_SET is

--
-- These routines test for the following subsets of ASCII
--
-- Routine              Subset tested for
-- =======              =================
-- ALPHA                'a'..'z' | 'A'..'Z'
-- ALPHA_NUMERIC        ALPHA | '0'..'9'
-- CONTROL              < ' ' | DEL
-- DIGIT                '0'..'9'
-- GRAPHIC              ' ' < ch < DEL (does not include space)
-- HEXADECIMAL          DIGIT | 'A'..'F' | 'a'..'f'
-- LOWER                'a'..'z'
-- PRINTABLE            GRAPHIC | ' '
-- PUNCTUATION          GRAPHIC and not ALPHA_NUMERIC
-- SPACE                HT | LF | VT | FF | CR | ' '
-- UPPER                'A'..'Z'
--
    function IS_ALPHA         (CH : CHARACTER) return BOOLEAN;
    function IS_ALPHA_NUMERIC (CH : CHARACTER) return BOOLEAN;
    function IS_CONTROL       (CH : CHARACTER) return BOOLEAN;
    function IS_DIGIT         (CH : CHARACTER) return BOOLEAN;
    function IS_GRAPHIC       (CH : CHARACTER) return BOOLEAN;
    function IS_HEXADECIMAL   (CH : CHARACTER) return BOOLEAN;
    function IS_LOWER         (CH : CHARACTER) return BOOLEAN;
    function IS_PRINTABLE     (CH : CHARACTER) return BOOLEAN;
    function IS_PUNCTUATION   (CH : CHARACTER) return BOOLEAN;
    function IS_SPACE         (CH : CHARACTER) return BOOLEAN;
    function IS_UPPER         (CH : CHARACTER) return BOOLEAN;

--
-- These routines convert characters and strings to upper- or lower-case
--
    function  TO_LOWER (CH : CHARACTER) return CHARACTER;
    procedure TO_LOWER (CH : in out CHARACTER);
    procedure TO_LOWER (STR : in out STRING);
    function  TO_UPPER (CH : CHARACTER) return CHARACTER;
    procedure TO_UPPER (CH : in out CHARACTER);
    procedure TO_UPPER (STR : in out STRING);

--
-- These routines return the names of the control characters
--
    subtype CONTROL_CHARACTER_NAME_2 is STRING (1 .. 2);
    subtype CONTROL_CHARACTER_NAME_3 is STRING (1 .. 3);
--
    function CC_NAME_2 (CH : CHARACTER) return CONTROL_CHARACTER_NAME_2;
    function CC_NAME_3 (CH : CHARACTER) return CONTROL_CHARACTER_NAME_3;


end CHARACTER_SET;

package body CHARACTER_SET is

    function IS_ALPHA (CH : CHARACTER) return BOOLEAN is
    begin
        case CH is
            when 'a' .. 'z' =>
                return TRUE;
            when 'A' .. 'Z' =>
                return TRUE;
            when others =>
                return FALSE;
        end case;
    end IS_ALPHA;

    function IS_ALPHA_NUMERIC (CH : CHARACTER) return BOOLEAN is
    begin
        case CH is
            when 'a' .. 'z' =>
                return TRUE;
            when 'A' .. 'Z' =>
                return TRUE;
            when '0' .. '9' =>
                return TRUE;
            when others =>
                return FALSE;
        end case;
    end IS_ALPHA_NUMERIC;

    function IS_CONTROL (CH : CHARACTER) return BOOLEAN is
    begin
        if CH < ' ' or CH = ASCII.DEL then
            return TRUE;
        else
            return FALSE;
        end if;
    end IS_CONTROL;

    function IS_DIGIT (CH : CHARACTER) return BOOLEAN is
    begin
        if CH in '0' .. '9' then
            return TRUE;
        else
            return FALSE;
        end if;
    end IS_DIGIT;

    function IS_GRAPHIC (CH : CHARACTER) return BOOLEAN is
    begin
        if CH > ' ' and CH < ASCII.DEL then
            return TRUE;
        else
            return FALSE;
        end if;
    end IS_GRAPHIC;

    function IS_HEXADECIMAL (CH : CHARACTER) return BOOLEAN is
    begin
        case CH is
            when '0' .. '9' =>
                return TRUE;
            when 'A' .. 'F' | 'a' .. 'f' =>
                return TRUE;
            when others =>
                return FALSE;
        end case;
    end IS_HEXADECIMAL;

    function IS_LOWER (CH : CHARACTER) return BOOLEAN is
    begin
        if CH in 'a' .. 'z' then
            return TRUE;
        else
            return FALSE;
        end if;
    end IS_LOWER;

    function IS_PRINTABLE (CH : CHARACTER) return BOOLEAN is
    begin
        if CH >= ' ' and CH < ASCII.DEL then
            return TRUE;
        else
            return FALSE;
        end if;
    end IS_PRINTABLE;

    function IS_PUNCTUATION (CH : CHARACTER) return BOOLEAN is
    begin
        if (CH > ' ') and (CH < ASCII.DEL) and (not IS_ALPHA_NUMERIC (CH)) then
            return TRUE;
        else
            return FALSE;
        end if;
    end IS_PUNCTUATION;

    function IS_SPACE (CH : CHARACTER) return BOOLEAN is
    begin
        case CH is
            when ASCII.HT =>
                return TRUE;
            when ASCII.LF =>
                return TRUE;
            when ASCII.VT =>
                return TRUE;
            when ASCII.FF =>
                return TRUE;
            when ASCII.CR =>
                return TRUE;
            when ' ' =>
                return TRUE;
            when others =>
                return FALSE;
        end case;
    end IS_SPACE;

    function IS_UPPER (CH : CHARACTER) return BOOLEAN is
    begin
        if CH in 'A' .. 'Z' then
            return TRUE;
        else
            return FALSE;
        end if;
    end IS_UPPER;

    function TO_LOWER (CH : CHARACTER) return CHARACTER is
    begin
        if IS_UPPER (CH) then
            return CHARACTER'VAL
                     (CHARACTER'POS (CH) - CHARACTER'POS ('A') +
                      CHARACTER'POS ('a'));
        else
            return CH;
        end if;
    end TO_LOWER;

    procedure TO_LOWER (CH : in out CHARACTER) is
    begin
        if IS_UPPER (CH) then
            CH := TO_LOWER (CH);
        end if;
    end TO_LOWER;

    procedure TO_LOWER (STR : in out STRING) is
    begin
        for I in STR'FIRST .. STR'LAST loop
            STR (I) := TO_LOWER (STR (I));
        end loop;
    end TO_LOWER;

    function TO_UPPER (CH : CHARACTER) return CHARACTER is
    begin
        if IS_LOWER (CH) then
            return CHARACTER'VAL
                     (CHARACTER'POS (CH) - CHARACTER'POS ('a') +
                      CHARACTER'POS ('A'));
        else
            return CH;
        end if;
    end TO_UPPER;

    procedure TO_UPPER (CH : in out CHARACTER) is
    begin
        if IS_LOWER (CH) then
            CH := TO_UPPER (CH);
        end if;
    end TO_UPPER;

    procedure TO_UPPER (STR : in out STRING) is
    begin
        for I in STR'FIRST .. STR'LAST loop
            STR (I) := TO_UPPER (STR (I));
        end loop;
    end TO_UPPER;

    function CC_NAME_2 (CH : CHARACTER) return CONTROL_CHARACTER_NAME_2 is
        NAME : CONTROL_CHARACTER_NAME_2;
    begin
        case CH is
            when ASCII.NUL =>  NAME := "^@";
            when ASCII.SOH =>  NAME := "^A";
            when ASCII.STX =>  NAME := "^B";
            when ASCII.ETX =>  NAME := "^C";
            when ASCII.EOT =>  NAME := "^D";
            when ASCII.ENQ =>  NAME := "^E";
            when ASCII.ACK =>  NAME := "^F";
            when ASCII.BEL =>  NAME := "^G";
            when ASCII.BS =>  NAME := "^H";
            when ASCII.HT =>  NAME := "^I";
            when ASCII.LF =>  NAME := "^J";
            when ASCII.VT =>  NAME := "^K";
            when ASCII.FF =>  NAME := "^L";
            when ASCII.CR =>  NAME := "^M";
            when ASCII.SO =>  NAME := "^N";
            when ASCII.SI =>  NAME := "^O";
            when ASCII.DLE =>  NAME := "^P";
            when ASCII.DC1 =>  NAME := "^Q";
            when ASCII.DC2 =>  NAME := "^R";
            when ASCII.DC3 =>  NAME := "^S";
            when ASCII.DC4 =>  NAME := "^T";
            when ASCII.NAK =>  NAME := "^U";
            when ASCII.SYN =>  NAME := "^V";
            when ASCII.ETB =>  NAME := "^W";
            when ASCII.CAN =>  NAME := "^X";
            when ASCII.EM =>  NAME := "^Y";
            when ASCII.SUB =>  NAME := "^Z";
            when ASCII.ESC =>  NAME := "^[";
            when ASCII.FS =>  NAME := "^\";
            when ASCII.GS =>  NAME := "^]";
            when ASCII.RS =>  NAME := "^^";
            when ASCII.US =>  NAME := "^_";
            when ASCII.DEL =>  NAME := "^`";
            when others =>
                NAME := "  ";
                NAME (2) := CH;
        end case;
        return NAME;
    end CC_NAME_2;

    function CC_NAME_3 (CH : CHARACTER) return CONTROL_CHARACTER_NAME_3 is
        NAME : CONTROL_CHARACTER_NAME_3;
    begin
        case CH is
            when ASCII.NUL =>  NAME := "NUL";
            when ASCII.SOH =>  NAME := "SOH";
            when ASCII.STX =>  NAME := "STX";
            when ASCII.ETX =>  NAME := "ETX";
            when ASCII.EOT =>  NAME := "EOT";
            when ASCII.ENQ =>  NAME := "ENQ";
            when ASCII.ACK =>  NAME := "ACK";
            when ASCII.BEL =>  NAME := "BEL";
            when ASCII.BS =>  NAME := "BS ";
            when ASCII.HT =>  NAME := "HT ";
            when ASCII.LF =>  NAME := "LF ";
            when ASCII.VT =>  NAME := "VT ";
            when ASCII.FF =>  NAME := "FF ";
            when ASCII.CR =>  NAME := "CR ";
            when ASCII.SO =>  NAME := "SO ";
            when ASCII.SI =>  NAME := "SI ";
            when ASCII.DLE =>  NAME := "DLE";
            when ASCII.DC1 =>  NAME := "DC1";
            when ASCII.DC2 =>  NAME := "DC2";
            when ASCII.DC3 =>  NAME := "DC3";
            when ASCII.DC4 =>  NAME := "DC4";
            when ASCII.NAK =>  NAME := "NAK";
            when ASCII.SYN =>  NAME := "SYN";
            when ASCII.ETB =>  NAME := "ETB";
            when ASCII.CAN =>  NAME := "CAN";
            when ASCII.EM =>  NAME := "EM ";
            when ASCII.SUB =>  NAME := "SUB";
            when ASCII.ESC =>  NAME := "ESC";
            when ASCII.FS =>  NAME := "FS ";
            when ASCII.GS =>  NAME := "GS ";
            when ASCII.RS =>  NAME := "RS ";
            when ASCII.US =>  NAME := "US ";
            when ASCII.DEL =>  NAME := "DEL";
            when others =>
                NAME := "   ";
                NAME (2) := CH;
        end case;
        return NAME;
    end CC_NAME_3;

end CHARACTER_SET;
::::::::::
cas3.ada
::::::::::

-------- SIMTEL20 Ada Software Repository Prologue ------------
-- 
-- Unit name    : COUNT_OF_ADA_STATEMENTS_3
-- Version      : 1.2
-- Author       : Richard Conn
--              : TI Ada Technology Branch
--              : Box 801, MS 8007
--              : McKinney, TX  75069
-- DDN Address  : RCONN at SIMTEL20
-- Derivation   : COUNT_OF_ADA_STATEMENTS_2 by Richard Conn
-- Derivation   : COUNT_OF_ADA_STATEMENTS by Bill Whitaker
-- Date created : 4 Apr 85
-- Release date : 4 Apr 85
-- Last update  : 24 June 85
-- 
---------------------------------------------------------------
-- 
-- Keywords     :  Source analysis, Quantity, Statements
-- 
----------------:
-- 
-- Abstract     :
--  This procedure calculates the "STATEMENTS" of a valid Ada fragment
--  specified by a FILE_NAME string parameter.  It need not be a complete
--  compilation unit, but it should have closed all open parens and
--  strings.
-- 
--  The Ada statement is defined by a semicolon terminator
--  outside of comments, parentheses, or string or character literals.
--  This definition is insensitive to formatting or layout of the source.
-- 
--  There are exotic cases for which this will misestimate the count
--  but we have never encountered one in real code.
-- 
--  This procedure is derived from Bill Whitaker's original
--  COUNT_OF_ADA_STATEMENTS, and it does not change his original algorithm.
--  It adds a line count and a character-checksum hash (sum of POS values of
--  all non-space characters in the file mod 256).  It also adds a count
--  of the comment lines (over CAS2, which does not).
-- 
------------------ Revision history ---------------------------
-- 
-- DATE         VERSION         AUTHOR          HISTORY
-- 19850215     1.0             R Conn          Initial Release
-- 19850506     1.1             R Conn          Overflow Traps Added
-- 19850624     1.2             R Conn          Bug in Single-Quote Proc Fixed
-- 
------------------ Distribution and Copyright -----------------
-- 
-- This software is released to the Public Domain (note:
--   software released to the Public Domain is not subject
--   to copyright protection).
-- 
------------------ Disclaimer ---------------------------------
-- 
-- This software and its documentation are provided "AS IS" and
-- without any expressed or implied warranties whatsoever.
-- No warranties as to performance, merchantability, or fitness
-- for a particular purpose exist.
-- 
-- In no event shall any person or organization of people be
-- held responsible for any direct, indirect, consequential
-- or inconsequential damages or lost profits.
-- 
-------------------END-PROLOGUE--------------------------------

with TEXT_IO,
     CHARACTER_SET;
procedure COUNT_OF_ADA_STATEMENTS (FILE_NAME  : STRING;
                                   STATEMENTS : in out NATURAL;
                                   LINE_COUNT : in out NATURAL;
                                   COMMENTS   : in out NATURAL;
                                   HASH       : in out NATURAL) is
-- 
--  Returned values:
--     STATEMENTS    Number of Ada code statements
--     LINE_COUNT    Number of lines of text
--     COMMENTS      Number of comments in the file
--     HASH          Checksum (Mod 256 sum) of all non-space
--                    (a space character as defined by character_set)
--                    characters
-- 
    INPUT        : TEXT_IO.FILE_TYPE;
    CURRENT_LINE : STRING (1 .. 256); --  arbitrarily large
    NEXT_CHAR    : NATURAL := 1;
    LAST_CHAR    : NATURAL := 0;
    C            : CHARACTER;
    LEVEL        : INTEGER := 0;
    CH_PENDING   : BOOLEAN := FALSE;
    PENDING_CH   : CHARACTER;

    procedure UNGET (CH : CHARACTER) is
    begin
        CH_PENDING := TRUE;
        PENDING_CH := CH;
    end UNGET;

    procedure GET (CH : in out CHARACTER) is
    begin
        if CH_PENDING then
            CH_PENDING := FALSE;
            CH := PENDING_CH;
        else
            if NEXT_CHAR > LAST_CHAR then
                loop
                    TEXT_IO.GET_LINE (INPUT, CURRENT_LINE, LAST_CHAR);
                    begin
                        LINE_COUNT := LINE_COUNT + 1;
                    exception
                        when others =>  null; -- trap overflow
                    end;
                    NEXT_CHAR := 1;
                    exit when NEXT_CHAR <= LAST_CHAR;
                end loop;
            end if;
            CH := CURRENT_LINE (NEXT_CHAR);
            if not CHARACTER_SET.IS_SPACE (CH) then
                HASH := (HASH + CHARACTER'POS (CH)) mod 256;
            end if;
            NEXT_CHAR := NEXT_CHAR + 1;
        end if;
    end GET;

begin

    TEXT_IO.OPEN (INPUT, TEXT_IO.IN_FILE, FILE_NAME);
    STATEMENTS := 0;
    LINE_COUNT := 0;
    COMMENTS := 0;
    HASH := 0;

    loop
        GET (C);

        --  Check for comment on the line
        if C = '-' then
            GET (C);
            --  Which is signaled by the '-' following a '-'
            if C = '-' then
                --  Then just skip the rest of the line and go to the next
                NEXT_CHAR := LAST_CHAR + 1;
                begin
                    COMMENTS := COMMENTS + 1;
                exception
                    when others =>  null; -- trap overflow
                end;
            end if;
        end if;

        --  Check for one of the characters which introduce code constructs
        --  like string or character literal or formal parameter list
        --  within which a ';' does not terminate a "line of code"
        if C = '(' or C = '"' or C = '%' or C = ''' then

--  Check for opening parentheses
--  Every ';' within is in a formal parameter list
            if C = '(' then
                --  Count the number of levels of parentheses
                LEVEL := LEVEL + 1;
                --  Read ahead until the whole construct is closed, LEVEL = 0
                while LEVEL > 0 loop
                    GET (C);
                    if C = '(' then
                        --  Increase the level if another '(' is found
                        LEVEL := LEVEL + 1;
                    elsif C = ')' then
                        --  Decrease the level if a ')' is found
                        LEVEL := LEVEL - 1;
                    end if;
                end loop;

                --  Now check for string brackets of either kind, " or %
            elsif C = '"' or C = '%' then
--  Treat them in parallel, one must lead off
                if C = '"' then
                    loop
                        GET (C);
                        --  Loop until the close comes
                        --  If there is a doubled character it starts again
                        exit when C = '"';
                    end loop;
                    --  The '%' is handled exactly the same way as '"'
                elsif C = '%' then
                    loop
                        GET (C);
                        exit when C = '%';
                    end loop;
                end if;

                --  Character literals are just three characters long
                --  including '
            elsif C = ''' then
                GET (C);
                GET (C);
                if C /= ''' then
                    UNGET (C);
                end if;
            end if;

            --  Any ';' that can be found at this point after all
            --  exclusions must be a valid "line of code" terminator
        elsif C = ';' then
            begin
                STATEMENTS := STATEMENTS + 1;
            exception
                when others =>  null; -- trap overflow
            end;

        end if;

    end loop;

exception
    when TEXT_IO.END_ERROR => 
        TEXT_IO.CLOSE (INPUT); --  close input file
    when TEXT_IO.NAME_ERROR => 
        TEXT_IO.NEW_LINE;
        TEXT_IO.PUT ("Error in File Name ");
        TEXT_IO.PUT (FILE_NAME);
        TEXT_IO.NEW_LINE;
        raise TEXT_IO.NAME_ERROR;
    when others => 
        raise;
end COUNT_OF_ADA_STATEMENTS;
::::::::::
pager_support.ada
::::::::::


--
-- PAGER_SUPPORT by Richard Conn, TI Ada Technology Branch
--
package PAGER_SUPPORT is 

  FILE_NAME_LENGTH         : constant := 80; 
  INPUT_FILE_NAME          : STRING(1 .. FILE_NAME_LENGTH); 
  INPUT_FILE_NAME_LENGTH   : NATURAL; 
  COMMENT_PREFIX           : BOOLEAN := FALSE; 
  INCLUDE_FILE_PREFIX      : BOOLEAN := TRUE; 
  INCLUDE_FILE_PREFIX_CHAR : constant CHARACTER := '@'; 
  VERBOSE                  : BOOLEAN := TRUE; 
  LIST_PREFIX              : constant STRING := "$$ "; 
  --
  -- INPUT_FILE_NAME and INPUT_FILE_NAME_LENGTH are set by the
  --  function COMMAND
  --
  -- COMMENT_PREFIX is available to be set externally if desired;
  --  if COMMENT_PREFIX is TRUE, all files created by PAGE will
  --  present file indicators as comments; else, file indicators
  --  will be presented in the UNIX standard form:
  --      ::::::::::
  --      filename
  --      ::::::::::
  --
  -- INCLUDE_FILE_PREFIX is available to be set externally if desired;
  --  if INCLUDE_FILE_PREFIX is TRUE, all include files referenced during
  --  the PAGE command will be included as a prefix to their contents;
  --  if FALSE, only the contents of the include files and not the include
  --  files themselves will be included
  -- INCLUDE_FILE_PREFIX_CHAR is the character prefixed to a file name to
  --  designate it as an include file
  -- LIST_PREFIX is the prefix to be placed before file names in the output
  --  file generated by the list file names command.  This output file can
  --  later be edited, and this prefix can be replaced via global substitution
  --  with something else, such as "$ ada " to prefix each file name with a
  --  DEC Ada compiler command (for example).
  --

  procedure PAGE(OUTPUT_FILE_NAME : in STRING); 
  --
  -- PAGE prompts the user for the names of files and creates a paged
  --  output file containing the indicated files
  --

  procedure UNPAGE(INPUT_FILE_NAME : in STRING); 
  --
  -- UNPAGE extracts the files from a paged file
  --

  procedure LIST_NAMES(INPUT_FILE_NAME : in STRING); 
  -- 
  -- LIST_NAMES lists the names of the files in a paged file out to a text
  --  file.
  -- 

  procedure ADA_CHECK(INPUT_FILE_NAME : in STRING); 
  --
  -- ADA_CHECK computes and displays the number of Ada statements, Ada
  --  comments, text lines, and a checksum hash code for the indicated file
  --

  procedure SCANPAGE(INPUT_FILE_NAME : in STRING); 
  --
  -- SCANPAGE lists the names of the files in a paged file
  --

  function COMMAND return CHARACTER; 
  --
  -- COMMAND inputs a command line from the user and returns the first
  --  character in this line as a command letter.  It returns this character
  --  in upper-case.  It also does a simple parse of the command line
  --  and fills the INPUT_FILE_NAME and INPUT_FILE_NAME_LENGTH values, where
  --  the command line may be of the following two forms:
  --
  --     command_text
  --     command_text file_name
  --

end PAGER_SUPPORT; 

-- ====================================================================

with TEXT_IO, CHARACTER_SET, COUNT_OF_ADA_STATEMENTS; 
package body PAGER_SUPPORT is 

--
-- Common variables and exceptions
--
  MAX_STRING : constant := 1024; 
  NEW_FILE   : TEXT_IO.FILE_TYPE; 
  PAGED_FILE : TEXT_IO.FILE_TYPE; 
  LAST       : NATURAL; 
  LINE       : STRING(1 .. MAX_STRING); 

  type FILE_NAME_STRING is 
    record
      NAME   : STRING(1 .. FILE_NAME_LENGTH); 
      LENGTH : NATURAL; 
    end record; 

  FILE_CREATE_ERROR : exception; 
  FILE_OPEN_ERROR   : exception; 

  -- ==============================================================

  package FN_LIST is 
  --
  -- This package provides simple manipulation for a singly-linked list
  --   of objects of type FILE_NAME_STRING
  --

    procedure INITIALIZE_LIST; 
    --
    -- Initialize the list
    --

    procedure APPEND_ELEMENT(ELEMENT : in FILE_NAME_STRING); 
    --
    -- Add element onto the end of the list
    --

    procedure SET_FIRST; 
    --
    -- Goto the front of the list
    --

    function RETURN_CURRENT_ELEMENT return FILE_NAME_STRING; 
    --
    -- Return the current element in the list
    --

    function CURRENT_NEXT return BOOLEAN; 
    --
    -- Advance to next element in the list; return TRUE if done
    --

  end FN_LIST; 

  package body FN_LIST is 

    type FILE_NAME_ELEMENT; 
    type ELEMENT_POINTER is access FILE_NAME_ELEMENT; 
    type FILE_NAME_ELEMENT is 
      record
        DATA : FILE_NAME_STRING; 
        NEXT : ELEMENT_POINTER; 
      end record; 

    FIRST_ELEMENT   : ELEMENT_POINTER; 
    CURRENT_ELEMENT : ELEMENT_POINTER; 

    procedure INITIALIZE_LIST is 
    begin
      FIRST_ELEMENT := null; 
    end INITIALIZE_LIST; 

    procedure APPEND_ELEMENT(ELEMENT : in FILE_NAME_STRING) is 
    begin
      if FIRST_ELEMENT = null then 
        FIRST_ELEMENT := new FILE_NAME_ELEMENT; 
        CURRENT_ELEMENT := FIRST_ELEMENT; 
        CURRENT_ELEMENT.NEXT := null; 
        CURRENT_ELEMENT.DATA := ELEMENT; 
      else 
        CURRENT_ELEMENT.NEXT := new FILE_NAME_ELEMENT; 
        CURRENT_ELEMENT := CURRENT_ELEMENT.NEXT; 
        CURRENT_ELEMENT.NEXT := null; 
        CURRENT_ELEMENT.DATA := ELEMENT; 
      end if; 
    end APPEND_ELEMENT; 

    procedure SET_FIRST is 
    begin
      CURRENT_ELEMENT := FIRST_ELEMENT; 
    end SET_FIRST; 

    function RETURN_CURRENT_ELEMENT return FILE_NAME_STRING is 
    begin
      return CURRENT_ELEMENT.DATA; 
    end RETURN_CURRENT_ELEMENT; 

    function CURRENT_NEXT return BOOLEAN is 
    begin
      if CURRENT_ELEMENT = null then 
        return FALSE; 
      elsif CURRENT_ELEMENT.NEXT = null then 
        return FALSE; 
      else 
        CURRENT_ELEMENT := CURRENT_ELEMENT.NEXT; 
        return TRUE; 
      end if; 
    end CURRENT_NEXT; 

  end FN_LIST; 

  -- ==============================================================
  package NAT_IO is 
    new TEXT_IO.INTEGER_IO(NATURAL); 

  --
  -- Open the input file
  --
  procedure OPEN_INPUT(INPUT_FILE_NAME : in STRING) is 
  begin
    TEXT_IO.OPEN(PAGED_FILE, TEXT_IO.IN_FILE, INPUT_FILE_NAME); 
  exception
    when others => 
      raise FILE_OPEN_ERROR; 
  end OPEN_INPUT; 

  --
  -- Create the paged output file
  --
  procedure CREATE_FILE(OUTPUT_FILE_NAME : in STRING) is 
  begin
    TEXT_IO.CREATE(PAGED_FILE, TEXT_IO.OUT_FILE, OUTPUT_FILE_NAME); 
  exception
    when others => 
      raise FILE_CREATE_ERROR; 
  end CREATE_FILE; 

  --
  -- Close the paged file if it is open
  --
  procedure CLOSE_PAGED_FILE is 
  begin
    if TEXT_IO.IS_OPEN(PAGED_FILE) then 
      TEXT_IO.CLOSE(PAGED_FILE); 
    end if; 
  end CLOSE_PAGED_FILE; 

  --
  -- Test to see if current line denotes another file
  --
  function FILE_NAME_LINE return BOOLEAN is 
  begin
    if LAST >= 10 and then (LINE(1 .. 10) = "::::::::::" or LINE(1 .. 10) = 
      "--::::::::") then 
      return TRUE; 
    else 
      return FALSE; 
    end if; 
  end FILE_NAME_LINE; 

  --
  --  PAGE accepts a number of file names and generates a paged file
  --  containing each of the indicated files prefixed by the form:
  --     ::::::::::
  --     filename
  --     ::::::::::
  --
  procedure PAGE(OUTPUT_FILE_NAME : in STRING) is 

    --
    --  Variables for PAGE
    --
    FILE_NAME_ENTRY : FILE_NAME_STRING; 
    FILE_NAME       : STRING(1 .. FILE_NAME_LENGTH); 
    LENGTH          : NATURAL; 

    --
    -- Append indicated file to end of output file
    --
    procedure APPEND_FILE(FILE_NAME : in STRING) is 
      INPUT_FILE : TEXT_IO.FILE_TYPE; 
      INLINE     : STRING(1 .. MAX_STRING); 
      LENGTH     : NATURAL; 
      LINE_COUNT : NATURAL := 0; 
    begin
      TEXT_IO.OPEN(INPUT_FILE, TEXT_IO.IN_FILE, FILE_NAME); 
      if COMMENT_PREFIX then 
        TEXT_IO.PUT(PAGED_FILE, "--"); 
      end if; 
      TEXT_IO.PUT_LINE(PAGED_FILE, "::::::::::"); 
      if COMMENT_PREFIX then 
        TEXT_IO.PUT(PAGED_FILE, "--"); 
      end if; 
      TEXT_IO.PUT_LINE(PAGED_FILE, FILE_NAME); 
      if COMMENT_PREFIX then 
        TEXT_IO.PUT(PAGED_FILE, "--"); 
      end if; 
      TEXT_IO.PUT_LINE(PAGED_FILE, "::::::::::"); 
      while not TEXT_IO.END_OF_FILE(INPUT_FILE) loop
        TEXT_IO.GET_LINE(INPUT_FILE, INLINE, LENGTH); 
        TEXT_IO.PUT_LINE(PAGED_FILE, INLINE(1 .. LENGTH)); 
        begin
          LINE_COUNT := LINE_COUNT + 1; 
        exception
          when others => 
            null; 

        -- trap overflow
        end; 
      end loop; 
      TEXT_IO.CLOSE(INPUT_FILE); 
      if VERBOSE then 
        TEXT_IO.PUT("      "); 
        NAT_IO.PUT(LINE_COUNT, 8); 
        TEXT_IO.PUT_LINE(" Lines"); 
      end if; 
    exception
      when TEXT_IO.NAME_ERROR => 
        TEXT_IO.PUT_LINE("      File Name Error"); 
        TEXT_IO.CLOSE(INPUT_FILE); 
        raise FILE_OPEN_ERROR; 
      when others => 
        TEXT_IO.CLOSE(INPUT_FILE); 
        raise FILE_OPEN_ERROR; 
    end APPEND_FILE; 

    --
    -- Process the indicated file as an include file; ie, this file
    --  contains a list of files to be included
    --
    procedure INCLUDE_FILE(FILE_NAME : in STRING) is 
      IFILE      : TEXT_IO.FILE_TYPE; 
      IFILE_NAME : STRING(1 .. FILE_NAME_LENGTH); 
      LENGTH     : NATURAL; 

      procedure NAME_INCLUDE_FILE is 
      begin
        if VERBOSE then 
          TEXT_IO.PUT("      "); 
          TEXT_IO.PUT_LINE(FILE_NAME_ENTRY.NAME(1 .. FILE_NAME_ENTRY.LENGTH)); 
        end if; 
      end NAME_INCLUDE_FILE; 

    begin
      if VERBOSE then 
        TEXT_IO.PUT("    Include File: "); 
        TEXT_IO.PUT_LINE(FILE_NAME); 
      end if; 

      --
      -- Try to open include file
      --
      TEXT_IO.OPEN(IFILE, TEXT_IO.IN_FILE, FILE_NAME); 

      --
      -- If INCLUDE_FILE_PREFIX is true, add the include file itself
      --
      if INCLUDE_FILE_PREFIX then 
        FILE_NAME_ENTRY.NAME(1 .. FILE_NAME'LENGTH) := FILE_NAME; 
        FILE_NAME_ENTRY.LENGTH := FILE_NAME'LENGTH; 
        FN_LIST.APPEND_ELEMENT(FILE_NAME_ENTRY); 
        NAME_INCLUDE_FILE; 
      end if; 

      --
      -- Add each file in the include file; omit blank lines and
      --  lines beginning with - (comment lines)
      --
      loop
        begin
          TEXT_IO.GET_LINE(IFILE, IFILE_NAME, LENGTH); 
          if LENGTH /= 0 and IFILE_NAME(1) /= '-' then 
          --
          -- Allow for include file nesting
          --
            if IFILE_NAME(1) = INCLUDE_FILE_PREFIX_CHAR then 
              INCLUDE_FILE(IFILE_NAME(2 .. LENGTH)); 
              --
              -- Include a conventional file
              --
            else 
              FILE_NAME_ENTRY.NAME := IFILE_NAME; 
              FILE_NAME_ENTRY.LENGTH := LENGTH; 
              FN_LIST.APPEND_ELEMENT(FILE_NAME_ENTRY); 
              NAME_INCLUDE_FILE; 
            end if; 
          end if; 
        exception
          when TEXT_IO.END_ERROR => 
            TEXT_IO.CLOSE(IFILE); 
            if VERBOSE then 
              TEXT_IO.PUT("    End of Include File "); 
              TEXT_IO.PUT_LINE(FILE_NAME); 
            end if; 
            exit; 
          when TEXT_IO.NAME_ERROR => 
            TEXT_IO.CLOSE(IFILE); 
            TEXT_IO.PUT_LINE("      File Name Error"); 
          when others => 
            TEXT_IO.CLOSE(IFILE); 
            raise; 
        end; 
      end loop; 
    exception
      when TEXT_IO.END_ERROR => 
        TEXT_IO.PUT_LINE("    Include File "); 
        TEXT_IO.PUT(FILE_NAME); 
        TEXT_IO.PUT_LINE(" NOT Found"); 
      when others => 
        raise; 
    end INCLUDE_FILE; 

  --
  --  Mainline of PAGE
  --
  begin
    CREATE_FILE(OUTPUT_FILE_NAME); 
    FN_LIST.INITIALIZE_LIST; 
    TEXT_IO.PUT_LINE("Enter Names of Files (RETURN when done)"); 
    loop
      TEXT_IO.PUT("  Input File Name > "); 
      TEXT_IO.GET_LINE(FILE_NAME, LENGTH); 
      exit when LENGTH = 0; 
      if FILE_NAME(1) = INCLUDE_FILE_PREFIX_CHAR then 
        INCLUDE_FILE(FILE_NAME(2 .. LENGTH)); 
      else 
        FILE_NAME_ENTRY.NAME := FILE_NAME; 
        FILE_NAME_ENTRY.LENGTH := LENGTH; 
        FN_LIST.APPEND_ELEMENT(FILE_NAME_ENTRY); 
      end if; 
    end loop; 
    TEXT_IO.NEW_LINE; 
    TEXT_IO.PUT_LINE("  Component Files --"); 
    FN_LIST.SET_FIRST; 
    loop
      begin
        FILE_NAME_ENTRY := FN_LIST.RETURN_CURRENT_ELEMENT; 
        TEXT_IO.PUT("    "); 
        TEXT_IO.PUT_LINE(FILE_NAME_ENTRY.NAME(1 .. FILE_NAME_ENTRY.LENGTH)); 
        APPEND_FILE(FILE_NAME_ENTRY.NAME(1 .. FILE_NAME_ENTRY.LENGTH)); 
        exit when not FN_LIST.CURRENT_NEXT; 
      exception
        when FILE_OPEN_ERROR => 
          TEXT_IO.PUT(" -- File NOT Found"); 
          exit when not FN_LIST.CURRENT_NEXT; 
        when others => 
          raise; 
      end; 
    end loop; 
    CLOSE_PAGED_FILE; 
  exception
    when FILE_CREATE_ERROR => 
      TEXT_IO.PUT("    Error in creating output file "); 
      TEXT_IO.PUT_LINE(OUTPUT_FILE_NAME); 
      CLOSE_PAGED_FILE; 
    when FILE_OPEN_ERROR => 
      TEXT_IO.PUT("    Error in opening input file "); 
      TEXT_IO.PUT_LINE(FILE_NAME_ENTRY.NAME(1 .. FILE_NAME_ENTRY.LENGTH)); 
      CLOSE_PAGED_FILE; 
    when others => 
      CLOSE_PAGED_FILE; 
  end PAGE; 


  --
  -- UNPAGE extracts the component files from a paged file and writes them
  --  out to their respective files
  --
  procedure UNPAGE(INPUT_FILE_NAME : in STRING) is 

    LINE_COUNT : NATURAL; 

    --
    -- Open new file for output
    --
    procedure OPEN_NEW_FILE is 
      NAME_START : INTEGER; 
    begin
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
      TEXT_IO.PUT("     "); 
      TEXT_IO.PUT_LINE(LINE(1 .. LAST)); 

      if LINE(1 .. 2) = "--" then 
        NAME_START := 3; 
      else 
        NAME_START := 1; 
      end if; 
      loop
        begin
          TEXT_IO.CREATE(NEW_FILE, TEXT_IO.OUT_FILE, LINE(NAME_START .. LAST)); 
          exit; 
        exception
          when TEXT_IO.NAME_ERROR => 
            TEXT_IO.NEW_LINE; 
            TEXT_IO.PUT("  Invalid File Name ("); 
            TEXT_IO.PUT(LINE(NAME_START .. LAST)); 
            TEXT_IO.PUT_LINE(")"); 
            TEXT_IO.PUT("    Enter Valid File Name > "); 
            TEXT_IO.GET_LINE(LINE, LAST); 
            NAME_START := 1; 
          when others => 
            raise; 
        end; 
      end loop; 

      --Skip over the trailing ":::::::::::::" line
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
    exception
      when others => 
        raise FILE_CREATE_ERROR; 
    end OPEN_NEW_FILE; 

  --
  -- Mainline of UNPAGE
  --
  begin

    OPEN_INPUT(INPUT_FILE_NAME); 

    --
    -- Search for first component in paged file
    --
    loop
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
      exit when FILE_NAME_LINE; 
    end loop; 
    --
    -- Process each component in paged file
    --
    OPEN_NEW_FILE; 
    LINE_COUNT := 0; 
    loop
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
      if FILE_NAME_LINE then 
        TEXT_IO.CLOSE(NEW_FILE); 
        if VERBOSE then 
          TEXT_IO.PUT("      "); 
          NAT_IO.PUT(LINE_COUNT, 8); 
          TEXT_IO.PUT_LINE(" Lines"); 
        end if; 
        LINE_COUNT := 0; 
        OPEN_NEW_FILE; 
      else 
        begin
          LINE_COUNT := LINE_COUNT + 1; 
        exception
          when others => 
            null; 

        -- trap overflow
        end; 
        TEXT_IO.PUT_LINE(NEW_FILE, LINE(1 .. LAST)); 
      end if; 
    end loop; 

  exception
    when FILE_CREATE_ERROR => 
      TEXT_IO.PUT_LINE("    Error in creating output file"); 
      CLOSE_PAGED_FILE; 
    when FILE_OPEN_ERROR => 
      TEXT_IO.PUT_LINE("    Error in opening input file"); 
      CLOSE_PAGED_FILE; 
    when TEXT_IO.END_ERROR => 
      if TEXT_IO.IS_OPEN(NEW_FILE) then 
        TEXT_IO.CLOSE(NEW_FILE); 
        if VERBOSE then 
          TEXT_IO.PUT("      "); 
          NAT_IO.PUT(LINE_COUNT, 8); 
          TEXT_IO.PUT_LINE(" Lines"); 
        end if; 
      end if; 
      CLOSE_PAGED_FILE; 
    when others => 
      CLOSE_PAGED_FILE; 
  end UNPAGE; 

  -- 
  -- LIST_NAMES lists the names of the files in a paged file out to a text file
  -- 
  procedure LIST_NAMES(INPUT_FILE_NAME : in STRING) is 
    LIST_FILE : TEXT_IO.FILE_TYPE; 

    -- 
    -- List name of component file
    -- 
    procedure LIST_COMPONENT_NAME is 
      NAME_START : INTEGER; 
    begin
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
      if LINE(1 .. 2) = "--" then 
        NAME_START := 3; 
      else 
        NAME_START := 1; 
      end if; 
      TEXT_IO.PUT_LINE(LIST_FILE, LIST_PREFIX & LINE(NAME_START .. LAST)); 
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
    end LIST_COMPONENT_NAME; 

    -- 
    -- Close listing file
    -- 
    procedure CLOSE_LISTING_FILE is 
    begin
      if TEXT_IO.IS_OPEN(LIST_FILE) then 
        TEXT_IO.CLOSE(LIST_FILE); 
      end if; 
    end CLOSE_LISTING_FILE; 

    -- 
    -- Mainline of LIST_NAMES
    -- 
  begin
    OPEN_INPUT(INPUT_FILE_NAME); 
    TEXT_IO.PUT("  Name of Output File (<RETURN> to Abort)? "); 
    TEXT_IO.GET_LINE(LINE, LAST); 
    if LAST = 0 then 
      TEXT_IO.PUT_LINE("     User Abort"); 
      CLOSE_PAGED_FILE; 
      return; 
    end if; 
    begin
      TEXT_IO.CREATE(LIST_FILE, TEXT_IO.OUT_FILE, LINE(1 .. LAST)); 
    exception
      when others => 
        raise FILE_CREATE_ERROR; 
    end; 
    loop
    -- 
    -- Look for file name prefix
    -- 
      loop
        TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
        exit when FILE_NAME_LINE; 
      end loop; 
      LIST_COMPONENT_NAME; 
    end loop; 
  exception
    when FILE_CREATE_ERROR => 
      TEXT_IO.PUT_LINE("     Error in creating listing file"); 
      CLOSE_PAGED_FILE; 
    when FILE_OPEN_ERROR => 
      TEXT_IO.PUT_LINE("     Error in opening input file"); 
    when TEXT_IO.END_ERROR => 
      CLOSE_LISTING_FILE; 
      CLOSE_PAGED_FILE; 
      TEXT_IO.PUT_LINE("     Listing Done"); 
    when others => 
      CLOSE_LISTING_FILE; 
      CLOSE_PAGED_FILE; 
  end LIST_NAMES; 

  --
  -- ADA_CHECK computes and displays the number of Ada statements, Ada
  --  comments, text lines, and a checksum hash code for the indicated file
  --
  procedure ADA_CHECK(INPUT_FILE_NAME : in STRING) is 
    STATEMENTS : NATURAL; 
    LINES      : NATURAL; 
    COMMENTS   : NATURAL; 
    HASH       : NATURAL; 
  begin
    COUNT_OF_ADA_STATEMENTS(INPUT_FILE_NAME, STATEMENTS, LINES, COMMENTS, HASH)
      ; 
    TEXT_IO.PUT("Input File: "); 
    TEXT_IO.PUT_LINE(INPUT_FILE_NAME); 
    TEXT_IO.PUT("  Ada Statements: "); 
    NAT_IO.PUT(STATEMENTS, 6); 
    TEXT_IO.NEW_LINE; 
    TEXT_IO.PUT("  Ada Comments:   "); 
    NAT_IO.PUT(COMMENTS, 6); 
    TEXT_IO.NEW_LINE; 
    TEXT_IO.PUT("  Text Lines:     "); 
    NAT_IO.PUT(LINES, 6); 
    TEXT_IO.NEW_LINE; 
    TEXT_IO.PUT("  Checksum:       "); 
    NAT_IO.PUT(HASH, 6); 
    TEXT_IO.NEW_LINE; 
  end ADA_CHECK; 

  --
  -- SCANPAGE scans a paged file and prints out the names of the files
  --  contained therein
  --
  procedure SCANPAGE(INPUT_FILE_NAME : in STRING) is 

    --
    -- Variables et al
    --
    LINE_COUNT : NATURAL; 

    --
    -- Advance to a new file
    --
    procedure NEW_FILE is 
      NAME_START : NATURAL; 
    begin
    -- Get file name
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 

      -- Print file name
      if LINE(1 .. 2) = "--" then 
        NAME_START := 3; 
      else 
        NAME_START := 1; 
      end if; 
      TEXT_IO.PUT("    "); 
      TEXT_IO.PUT(LINE(NAME_START .. LAST)); 
      LINE_COUNT := 0; 

      -- Skip over the trailing ":::::::::::::" line
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 

    end NEW_FILE; 

    --
    -- Print value of LINE_COUNT
    --
    procedure PRINT_LINE_COUNT is 
    begin
      TEXT_IO.NEW_LINE; 
      if VERBOSE then 
        TEXT_IO.PUT("      "); 
        NAT_IO.PUT(LINE_COUNT, 8); 
        TEXT_IO.PUT_LINE(" Lines"); 
      end if; 
    end PRINT_LINE_COUNT; 

  --
  --  Mainline of SCANPAGE
  --
  begin

    ADA_CHECK(INPUT_FILE_NAME); 
    OPEN_INPUT(INPUT_FILE_NAME); 

    --
    -- Search for first component in paged file
    --
    loop
      TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
      exit when FILE_NAME_LINE; 
    end loop; 
    TEXT_IO.PUT_LINE("  Component Files -- "); 
    --
    -- Process each component in paged file
    --
    NEW_FILE; 
    loop
      begin
        TEXT_IO.GET_LINE(PAGED_FILE, LINE, LAST); 
        begin
          LINE_COUNT := LINE_COUNT + 1; 
        exception
          when others => 
            null;  -- trap overflow
        end; 
        if FILE_NAME_LINE then 
          begin
            LINE_COUNT := LINE_COUNT - 1; 
          exception
            when others => 
              null; 

          -- trap overflow
          end; 
          PRINT_LINE_COUNT; 
          NEW_FILE; 
        end if; 
      exception
        when TEXT_IO.END_ERROR => 
          PRINT_LINE_COUNT; 
          exit; 
        when others => 
          raise; 
      end; 
    end loop; 

    CLOSE_PAGED_FILE; 

  exception
    when FILE_CREATE_ERROR => 
      TEXT_IO.PUT_LINE("    Error in creating output file"); 
      CLOSE_PAGED_FILE; 
    when FILE_OPEN_ERROR => 
      TEXT_IO.PUT_LINE("    Error in opening input file"); 
      CLOSE_PAGED_FILE; 
    when TEXT_IO.END_ERROR => 
      CLOSE_PAGED_FILE; 
    when others => 
      CLOSE_PAGED_FILE; 
  end SCANPAGE; 

  --
  -- COMMAND inputs and does a simple parse of the command line
  --
  function COMMAND return CHARACTER is 
    INDEX             : NATURAL; 
    FN_INDEX          : NATURAL; 
    COMMAND_LINE      : STRING(1 .. 256); 
    COMMAND_LENGTH    : NATURAL; 
    COMMAND_CHARACTER : CHARACTER; 
  begin
    loop
      TEXT_IO.GET_LINE(COMMAND_LINE, COMMAND_LENGTH); 
      COMMAND_LINE(COMMAND_LENGTH + 1) := ASCII.NUL; 
      if COMMAND_LENGTH > 0 then 
        COMMAND_CHARACTER := COMMAND_LINE(1); 
        INDEX := 1; 

        -- Skip over command name
        loop
          exit when CHARACTER_SET.IS_SPACE(COMMAND_LINE(INDEX)) or COMMAND_LINE(
            INDEX) = ASCII.NUL; 
          INDEX := INDEX + 1; 
        end loop; 

        -- Skip over space chars
        loop
          exit when (not CHARACTER_SET.IS_SPACE(COMMAND_LINE(INDEX))) or 
            COMMAND_LINE(INDEX) = ASCII.NUL; 
          INDEX := INDEX + 1; 
        end loop; 

        -- Save file name
        FN_INDEX := 1; 
        loop
          exit when COMMAND_LINE(INDEX) = ASCII.NUL; 
          INPUT_FILE_NAME(FN_INDEX) := COMMAND_LINE(INDEX); 
          INDEX := INDEX + 1; 
          FN_INDEX := FN_INDEX + 1; 
        end loop; 
        INPUT_FILE_NAME(FN_INDEX) := ASCII.NUL; 
        INPUT_FILE_NAME_LENGTH := FN_INDEX - 1; 
        exit; 
      end if; 
    end loop; 
    return CHARACTER_SET.TO_UPPER(COMMAND_CHARACTER); 
  end COMMAND; 

end PAGER_SUPPORT; 
::::::::::
pager.ada
::::::::::

--
-- PAGER by Richard Conn, TI Ada Technology Branch
-- Version 1.0, 10 Mar 85
-- Version 1.1, 13 Mar 85
-- Version 1.2, 14 Mar 85
-- Version 1.3, 4 Apr 85
-- Version 1.4, 8 Apr 85
-- Version 1.5, 6 May 85
-- Version 1.6, 30 Oct 85
--


--|MODULE: PAGER
--|AUTHOR: CONN
--|LOCATION: PDL-TOOLS
--|LOCATION: TOOLS
--|REQUIRES: CHARACTER_SET
--|REQUIRES: CAS3
--|IEEE_PDL: SUPPORT_MODULE
--|DESIGN_STATUS         : DONE
--|IMPLEMENTATION_STATUS : DONE
--|DOCUMENTATION_STATUS  : DONE
--|DATE_RELEASED         : 10 Mar 85
--|DATE_LAST_MODIFIED    : 30 Oct 85
--|ABSTRACT:
--|  PAGER manipulates text files as a library which takes the
--| form of a larger text files.  It creates the larger text file,
--| extracts its components, and analyzes it, giving information
--| on its content.  PAGER is a convenient tool for the collection
--| of related files.  This collection, then, can be copied and
--| archived, but, when the work is done on these files again,
--| the paged file can be copied out to a work area, torn apart
--| (unpaged), and the related files can be worked on independently.
--|

with TEXT_IO, PAGER_SUPPORT; 
procedure PAGER is 

  VERSION                  : constant STRING := "PAGER, Version 1.6"; 
  CURRENT_FILE_NAME        : STRING(1 .. PAGER_SUPPORT.FILE_NAME_LENGTH) := (
    others => ASCII.NUL); 
  CURRENT_FILE_NAME_LENGTH : NATURAL := 0; 

  NO_FILE_NAME             : exception; 

  procedure COMMENT_MESSAGE is 
  begin
    TEXT_IO.PUT("  Comment Prefix is "); 
    if PAGER_SUPPORT.COMMENT_PREFIX then 
      TEXT_IO.PUT_LINE("Enabled"); 
    else 
      TEXT_IO.PUT_LINE("Disabled"); 
    end if; 
  end COMMENT_MESSAGE; 

  procedure INCLUDE_MESSAGE is 
  begin
    TEXT_IO.PUT("  Include File Prefix is "); 
    if PAGER_SUPPORT.INCLUDE_FILE_PREFIX then 
      TEXT_IO.PUT_LINE("Enabled"); 
    else 
      TEXT_IO.PUT_LINE("Disabled"); 
    end if; 
  end INCLUDE_MESSAGE; 

  procedure VERBOSE_MESSAGE is 
  begin
    TEXT_IO.PUT("  Verbose Mode is "); 
    if PAGER_SUPPORT.VERBOSE then 
      TEXT_IO.PUT_LINE("Enabled"); 
    else 
      TEXT_IO.PUT_LINE("Disabled"); 
    end if; 
  end VERBOSE_MESSAGE; 

begin
  TEXT_IO.PUT_LINE(VERSION); 
  TEXT_IO.PUT_LINE("Type HELP for Help"); 
  loop
    begin
      TEXT_IO.PUT("PAGER> "); 
      case PAGER_SUPPORT.COMMAND is 
        when '-' => 
          null; 
        when 'C' => 
          if PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH > 0 then 
            CURRENT_FILE_NAME := PAGER_SUPPORT.INPUT_FILE_NAME; 
            CURRENT_FILE_NAME_LENGTH := PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH; 
          else 
            raise NO_FILE_NAME; 
          end if; 
          PAGER_SUPPORT.ADA_CHECK(CURRENT_FILE_NAME(1 .. 
            CURRENT_FILE_NAME_LENGTH)); 
        when 'H' => 
          TEXT_IO.PUT_LINE("PAGER Commands:"); 
          TEXT_IO.PUT_LINE(" CHECK filename  --  Ada Check on File"); 
          TEXT_IO.PUT_LINE(" LIST filename   --  List Names of Component Files")
            ; 
          TEXT_IO.PUT_LINE(" PAGE filename   --  Create Paged File"); 
          TEXT_IO.PUT_LINE(" SCAN filename   --  List Files in Paged File"); 
          TEXT_IO.PUT_LINE(" TOGGLE          --  Indicate Flag Settings"); 
          TEXT_IO.PUT_LINE(" TOGGLE flag     --  Toggle Indicated Flag:"); 
          TEXT_IO.PUT_LINE("                     Comment, Include File, or"); 
          TEXT_IO.PUT_LINE("                     Verbose"); 
          TEXT_IO.PUT_LINE(" UNPAGE filename --  Extract from Paged File"); 
          TEXT_IO.PUT_LINE(" X (Exit)        --  Exit PAGER"); 
        when 'L' => 
          if PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH > 0 then 
            CURRENT_FILE_NAME := PAGER_SUPPORT.INPUT_FILE_NAME; 
            CURRENT_FILE_NAME_LENGTH := PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH; 
          else 
            raise NO_FILE_NAME; 
          end if; 
          PAGER_SUPPORT.LIST_NAMES(CURRENT_FILE_NAME(1 .. 
            CURRENT_FILE_NAME_LENGTH)); 
        when 'P' => 
          if PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH > 0 then 
            CURRENT_FILE_NAME := PAGER_SUPPORT.INPUT_FILE_NAME; 
            CURRENT_FILE_NAME_LENGTH := PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH; 
          else 
            raise NO_FILE_NAME; 
          end if; 
          PAGER_SUPPORT.PAGE(CURRENT_FILE_NAME(1 .. CURRENT_FILE_NAME_LENGTH)); 
        when 'S' => 
          if PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH > 0 then 
            CURRENT_FILE_NAME := PAGER_SUPPORT.INPUT_FILE_NAME; 
            CURRENT_FILE_NAME_LENGTH := PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH; 
          else 
            raise NO_FILE_NAME; 
          end if; 
          PAGER_SUPPORT.SCANPAGE(CURRENT_FILE_NAME(1 .. CURRENT_FILE_NAME_LENGTH
            )); 
        when 'T' => 
          if PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH > 0 then 
            case PAGER_SUPPORT.INPUT_FILE_NAME(1) is 
              when 'c' | 'C' => 
                PAGER_SUPPORT.COMMENT_PREFIX := not PAGER_SUPPORT.COMMENT_PREFIX
                  ; 
                COMMENT_MESSAGE; 
              when 'i' | 'I' => 
                PAGER_SUPPORT.INCLUDE_FILE_PREFIX := not PAGER_SUPPORT.
                  INCLUDE_FILE_PREFIX; 
                INCLUDE_MESSAGE; 
              when 'v' | 'V' => 
                PAGER_SUPPORT.VERBOSE := not PAGER_SUPPORT.VERBOSE; 
                VERBOSE_MESSAGE; 
              when others => 
                TEXT_IO.PUT_LINE("    Invalid Toggle Option"); 
            end case; 
          else 
            COMMENT_MESSAGE; 
            INCLUDE_MESSAGE; 
            VERBOSE_MESSAGE; 
          end if; 
        when 'U' => 
          if PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH > 0 then 
            CURRENT_FILE_NAME := PAGER_SUPPORT.INPUT_FILE_NAME; 
            CURRENT_FILE_NAME_LENGTH := PAGER_SUPPORT.INPUT_FILE_NAME_LENGTH; 
          else 
            raise NO_FILE_NAME; 
          end if; 
          PAGER_SUPPORT.UNPAGE(CURRENT_FILE_NAME(1 .. CURRENT_FILE_NAME_LENGTH))
            ; 
        when 'X' => 
          exit; 
        when others => 
          TEXT_IO.PUT_LINE("    Invalid Command - Use HELP Command"); 
      end case; 
    exception
      when NO_FILE_NAME => 
        TEXT_IO.PUT_LINE("    File Name Missing from Command"); 
      when others => 
        null; 
    end; 
  end loop; 
end PAGER; 
::::::::::
pager_documentation.dis
::::::::::
--
-- The following files comprise the documentation on
-- PAGER.  PAGER.DOC is the formatted document, PAGER.RNO
-- is the source from which formatting was done.
--
pager.doc
pager.rno
::::::::::
pager.doc
::::::::::














                          PAGER, Version 1.6





              by Richard Conn, TI Ada Technology Branch











     PAGER is a tool for creating, extracting from, and scanning paged

files,  where  a  paged  file  is a file composed of one or more files

prefixed by banners.  PAGER is based in concept  on  the  UNPAGE  tool

submitted to the Ada Repository on SIMTEL20 by Mitre Corporation.



     Paged files are convenient mechanisms for storing related  files.

They  reduce  cluttering  in  the  directories  and  simplify the file

transfer process (to and from the  Ada  Repository,  for  example)  by

requiring  the  user  to transfer only one file in order to obtain all

files pertinent to a particular project or tool.  Additionally,  paged

files  are text files which can be handled more readily than the 8-bit

binary images associated with other file grouping mechanisms (see  the

file   LBR.DOC   in  the  directory  MICRO:<ADA.GENERAL>  in  the  Ada

Repository).  Paged files may be  manipulated  by  a  text  editor  if

necessary.



     For these reasons, paged files have been adopted  as  a  standard

for  file  storage in the Ada Repository.  The file type of SRC (as in

MYFILE.SRC) is designated to indicate that a file is paged.



     PAGER 1.5 is an operational improvement over PAGER 1.4.   It  has

been discovered that the limitation (range) of the type NATURAL cannot

be assumed to be "large" for all  Ada  compilers.   The  Telesoft  Ada

compiler, version 2.1, uses 16 bits for objects of type NATURAL.  This

proved to be restrictive.  Consequently, PAGER 1.5  provides  numerous

constraint error traps whenever counts are made.

                                                                Page 2





1  PAGED FILE FORMAT



     A paged file is a file composed of one or more files prefixed  by

banners of the form



                ::::::::::

                filename

                ::::::::::



or



                --::::::::::

                --filename

                --::::::::::





     The first banner conforms to the PAGE standard employed on  UNIX.

The  second  banner is an adaptation of the first form which resembles

Ada comments.  The second banner is convenient  when  the  paged  file

contains  several  files  associated with a particular Ada program and

they are placed in the paged file in compilation order.  The resulting

paged file may then be compiled without being disassembled first.



     A paged file is of the following general form



        Section                         Example

        =======                         =======

                                        ::::::::::

        banner                          firstfile.txt

                                        ::::::::::

                                         body

        first file                        of

                                         first file

                                        ::::::::::

        banner                          secondfile.txt

                                        ::::::::::

                                         body

        second file                       of

                                         second file



                                                                Page 3





2  FUNCTIONS OF PAGER



     PAGER performs the following functions:



      *  CHECK - Count the number of Ada statements, Ada comments, and

         text lines in the indicated file (the indicated file does not

         have to be a paged file); CHECK also computes a  checksum  of

         all the printable characters in this file



      *  LIST - Create  a  text  file  containing  the  names  of  the

         component  files  of  a  paged  file.  One name is stored per

         line, and each name is prefixed with  "$$  "  to  allow  easy

         editing  for inserting compile commands before the file names

         in the preparation of batch command files.



      *  PAGE - Create a paged file from one or more  existing  files;

         the  component  files  may  be  specified  individually or by

         include files



      *  SCAN - Perform a CHECK and then report on the name and number

         of  text  lines in each component file of the indicated paged

         file; if the file is not a paged file, SCAN presents the same

         information as CHECK



      *  TOGGLE - Display and toggle options



      *  UNPAGE - Extract the component files from the indicated paged

         file; the paged file is left intact





     There are several options available under  PAGER,  and  they  are

toggled and displayed by the TOGGLE command.  These options are:



      *  TOGGLE COMMENT - Select the comment banner



      *  TOGGLE INCLUDE - Place include files in paged files



      *  TOGGLE VERBOSE - Enable verbose mode





     More discussion  of  these  options  will  be  presented  in  the

discussions of the functions of PAGER which follow.



     Only the first letter of each command and  each  option  for  the

TOGGLE  command  is  significant.   All  other letters in a command or

option  are  ignored.   Only  with  file  names  are  all  letters  of

significance.  Hence,



        PAGE filename

and

        P filename





are equivalent, as are



                                                                Page 4







        TOGGLE INCLUDE

and

        T I





     Any PAGER command beginning with a dash (-) is a comment line  to

PAGER and is not processed in any way.







2.1  CHECK Function



     CHECK counts the number of Ada statements, Ada comments, and text

lines  in  the indicated file.  It also computes a checksum of all the

printable characters in this file.  The indicated file does  not  have

to be a paged file.  The syntax of the CHECK command is:



                CHECK filename





     CHECK is useful in providing a validity check of a file transfer.

By running CHECK on a file residing on a source computer, transferring

the file from the source computer to a destination computer, and  then

running  CHECK  on  the file as transferred to a destination computer,

the user can verify the transfer.   If  the  checksums  match,  it  is

likely  that  the  transfer  was  successful.   Since  the checksum is

computed on the printable characters (which  do  not  include  spaces,

tabs,  carriage  returns,  or line feeds), this check does not reflect

any differences caused by tab expansion (expanding tab characters into

spaces) and the like which may be caused by the transfer mechanism.







2.2  HELP Function



     The HELP command displays a brief help text  to  the  user.   The

syntax of this command is:



                HELP



                                                                Page 5





2.3  LIST Function



     The LIST function is used to create a text  file  containing  the

names  of  the component files within a paged file.  The syntax of the

LIST command is:



                LIST paged_file_name





     Upon execution, this command will prompt the user for the name of

the  output file.  If he strikes just the RETURN key, PAGER aborts the

LIST function and does not generate an output file.



     The output file has the following general format:

        $$ file_name_1

        $$ file_name_2

        ...



     A text editor can be used to make a global  substitution  of  the

"$$  "  characters.   For  instance, if the component files were to be

compiled in the order they were stored in the paged file, substituting

"$  ada  "  for  "$$  " in this listing file creates a DEC submit file

which compiles all files named.  Likewise, a substitution of "$  print

" would print all files named.







2.4  PAGE Function



     The PAGE function is used to created a paged  file  from  one  or

more component files.  The syntax of the PAGE command is:



                PAGE filename





     When the PAGE command is issued, the user  is  prompted  for  the

name of a file.  He may then type the name of a component file, strike

return, and he will be prompted again.  This process  continues  until

the  user  strikes  only a return in response to the file name prompt.

At this point, PAGE will create the  paged  file  from  the  component

files named by the user.



     If the user prefixes the name of a component file with an  atsign

character (@), the indicated file is processed as an include file.  An

include file is a file which  contains  the  names  of  zero  or  more

component  files,  one  name  per  line  starting in the first column.

Other include files may  be  referenced  within  an  include  file  by

prefixing  their  names  with  the  atsign character.  Comments may be

placed within an include file by placing two dashes in the  first  two

columns of a line.  The following is an example of an include file:

                                                                Page 6







         Example                      Comments

         =======                      ========

--

-- This is an include file for        Comment at the beginning

--  my favorite tool

--

                                      Blank lines are allowed

--

-- The following include file

--  contains the names of the         Another comment

--  Ada source files in compilation

--  order

--

@mytool.cmp

--

-- The following are the documentation

--  files

--

mytool.ref

mytool.doc

mytool.idx





     The following toggled options are applicable to the PAGE command:



      *  TOGGLE COMMENT - If the COMMENT option is ON, the Ada comment

         banner  (--::::::::::) is used; if the COMMENT option is OFF,

         the standard banner (::::::::::) is used.



      *  TOGGLE INCLUDE - If the INCLUDE option  is  ON,  any  include

         file  referenced  is  placed in the paged file as a component

         file; if the INCLUDE option is OFF,  include  files  are  not

         placed  in  the  paged  file  unless  explicitly  named.  For

         example, if @MYTOOL.DIS is specified with INCLUDE  off,  only

         the files named in MYTOOL.DIS are included; if INCLUDE is on,

         MYTOOL.DIS is included as well as the files named within it.



      *  TOGGLE  VERBOSE  -  If  the  VERBOSE  option  is   ON,   more

         information  is  displayed  during  the execution of the PAGE

         command; if the VERBOSE option is OFF,  less  information  is

         displayed



                                                                Page 7





2.5  SCAN Function



     The SCAN function is similar to the CHECK function, but  it  also

lists  the  names and number of text lines in the component files in a

paged file.  If SCAN is run on a file which is not a paged  file,  the

output is identical to CHECK.  The syntax of SCAN is:



                SCAN filename





     The VERBOSE toggle causes SCAN to present the count of text lines

to the user as well as the file names of the component files.







2.6  TOGGLE Function



     The TOGGLE command displays and toggles  the  options  of  PAGER.

TOGGLE  with  no  argument displays the options.  TOGGLE followed by a

valid option toggles the state (ON/OFF) of that option.



     The options to the TOGGLE command are:



      *  COMMENT - Comment banner (PAGE command only)



      *  INCLUDE - Include file (PAGE command only)



      *  VERBOSE - Verbose mode









2.7  UNPAGE Function



     The UNPAGE command extracts the  components  from  the  indicated

paged  file,  leaving  the  original paged file intact.  The syntax of

UNPAGE is:



                UNPAGE filename





     The VERBOSE toggle causes UNPAGE to present  the  count  of  text

lines to the user as each component file is extracted.

                                                                Page 8





2.8  X Function



     The X command exits PAGER.  Its syntax is:



                X









3  SAMPLE SESSION



     The following is a sample PAGER session.  It was  run  on  a  VAX

11/785 running VMS 4.0.





$ dir



Directory USER4:[CONN.ADA]



CAS3.ADA;1               15  (RWE,RWED,RE,RE)

CHARACTER_SET.ADA;1

                         21  (RWE,RWED,RE,RE)

LIB.DIR;1                 3  (RE,RWE,RE,RE)

PAGER.ADA;2              13  (RWE,RWED,RE,RE)

PAGER_COMPILE.DIS;1

                          1  (RWE,RWED,RE,RE)

PAGER_SUPPORT.ADA;1

                         47  (RWE,RWED,RE,RE)



Total of 6 files, 100 blocks.



$ type pager_compile.dis



--

-- Compilation order for all files required to create the

--  PAGER program

--

character_set.ada

cas3.ada

pager_support.ada

pager.ada



$ pager

PAGER, Version 1.6

Type HELP for Help

PAGER> h

PAGER Commands:

 CHECK filename  --  Ada Check on File

 LIST filename   --  List Names of Component Files

 PAGE filename   --  Create Paged File

 SCAN filename   --  List Files in Paged File

 TOGGLE          --  Indicate Flag Settings

 TOGGLE flag     --  Toggle Indicated Flag:

                     Comment, Include File, or

                     Verbose

                                                                Page 9





 UNPAGE filename --  Extract from Paged File

 X (Exit)        --  Exit PAGER

PAGER> t

  Comment Prefix is Disabled

  Include File Prefix is Enabled

  Verbose Mode is Enabled

PAGER> -- I will now create PAGER.SRC, which is

PAGER> -- composed of PAGER_SUPPORT.ADA and PAGER.ADA

PAGER> page pager.src

Enter Names of Files (RETURN when done)

  Input File Name > pager_support.ada

  Input File Name > pager.ada

  Input File Name > 



  Component Files --

    pager_support.ada

           714 Lines

    pager.ada

           150 Lines

PAGER> -- PAGER_FULL.SRC contains all files required to compile

PAGER> -- PAGER.ADA.  The file PAGER_COMPILE.DIS contains those

PAGER> -- file names in compilation order.

PAGER> toggle comment

  Comment Prefix is Enabled

PAGER> t

  Comment Prefix is Enabled

  Include File Prefix is Enabled

  Verbose Mode is Enabled

PAGER> page pager_full.src

Enter Names of Files (RETURN when done)

  Input File Name > @pager_compile.dis

    Include File: pager_compile.dis

      pager_compile.dis

      character_set.ada

      cas3.ada

      pager_support.ada

      pager.ada

    End of Include File pager_compile.dis

  Input File Name > 



  Component Files --

    pager_compile.dis

             8 Lines

    character_set.ada

           321 Lines

    cas3.ada

           194 Lines

    pager_support.ada

           714 Lines

    pager.ada

           150 Lines

PAGER> x





$ cd upload r

                                                               Page 10





  USER4:[CONN.UPLOAD]

$ pager

PAGER, Version 1.6

Type HELP for Help

PAGER> -- Demo of CHECK

PAGER> check [conn.ada]pager_full.src

Input File: [conn.ada]pager_full.src

  Ada Statements:    628

  Ada Comments:      309

  Text Lines:       1402

  Checksum:           91

PAGER> -- Demo of SCAN

PAGER> scan [conn.ada]pager_full.src

Input File: [conn.ada]pager_full.src

  Ada Statements:    628

  Ada Comments:      309

  Text Lines:       1402

  Checksum:           91

  Component Files -- 

    pager_compile.dis

             8 Lines

    character_set.ada

           321 Lines

    cas3.ada

           194 Lines

    pager_support.ada

           714 Lines

    pager.ada

           150 Lines

PAGER> -- Demo of UNPAGE

PAGER> unpage [conn.ada]pager_full.src

     pager_compile.dis

             8 Lines

     character_set.ada

           321 Lines

     cas3.ada

           194 Lines

     pager_support.ada

           714 Lines

     pager.ada

           150 Lines

PAGER> -- Check/Scan on a "normal" file

PAGER> check pager_support.ada

Input File: pager_support.ada

  Ada Statements:    324

  Ada Comments:      172

  Text Lines:        714

  Checksum:           22

PAGER> scan pager_support.ada

Input File: pager_support.ada

  Ada Statements:    324

  Ada Comments:      172

  Text Lines:        714

  Checksum:           22

PAGER> check pager.ada

                                                               Page 11





Input File: pager.ada

  Ada Statements:     74

  Ada Comments:        8

  Text Lines:        150

  Checksum:           61

PAGER> x

$



::::::::::
pager.rno
::::::::::
.figure 4
.CENTER;  PAGER, Version 1.6
.figure 2
.CENTER;  by Richard Conn, TI Ada Technology Branch
.figure 4

.ap

	PAGER is a tool for creating, extracting from, and scanning paged
files, where a paged file is a file composed of one or more files prefixed
by banners.  PAGER is based in concept
on the UNPAGE tool submitted to the Ada Repository
on SIMTEL20 by Mitre Corporation.

	Paged files are convenient mechanisms for storing related files.
They reduce cluttering in the directories and simplify the file transfer
process (to and from the Ada Repository, for example) by requiring the user
to transfer only one file in order to obtain all files pertinent to a
particular project or tool.  Additionally, paged files are text files
which can be handled more readily than the 8-bit binary images associated
with other file grouping mechanisms (see the file LBR.DOC in the
directory MICRO:<ADA.GENERAL> in the Ada Repository).
Paged files may be manipulated by a text editor if necessary.

	For these reasons, paged files have been adopted as a standard
for file storage in the Ada Repository.  The file type of SRC (as in
MYFILE.SRC) is designated to indicate that a file is paged.

	PAGER 1.5 is an operational improvement over PAGER 1.4.  It
has been discovered that the limitation (range) of the type NATURAL
cannot be assumed to be "large" for all Ada compilers.  The
Telesoft Ada compiler, version 2.1, uses 16 bits for objects of
type NATURAL.  This proved to be restrictive.  Consequently,
PAGER 1.5 provides numerous constraint error traps whenever
counts are made.

.tp 20
.HEADER LEVEL 1 Paged File Format

	A paged file is a file composed of one or more files prefixed by
banners of the form

.tp 15
.literal

		::::::::::
		filename
		::::::::::

or

		--::::::::::
		--filename
		--::::::::::

.end literal

	The first banner conforms to the PAGE standard employed on UNIX.
The second banner is an adaptation of the first form which resembles Ada
comments.  The second banner is convenient when the paged file contains
several files associated with a particular Ada program and they are placed
in the paged file in compilation order.  The resulting paged file may
then be compiled without being disassembled first.

	A paged file is of the following general form

.tp 20
.literal

        Section                         Example
        =======                         =======
                                        ::::::::::
        banner                          firstfile.txt
                                        ::::::::::
                                         body
        first file                        of
                                         first file
                                        ::::::::::
        banner                          secondfile.txt
                                        ::::::::::
                                         body
        second file                       of
                                         second file

.end literal

.tp 20
.HEADER LEVEL 1 Functions of PAGER

	PAGER performs the following functions:

.no autoparagraph
.list "*"
.LIST ELEMENT; CHECK - Count the number of Ada statements, Ada comments,
and text lines in the indicated file (the indicated file does not have to
be a paged file); CHECK also computes a checksum of all the printable
characters in this file
.LIST ELEMENT; LIST - Create a text file containing the names of the component
files of a paged file.  One name is stored per line, and each name is prefixed
with "$$ " to allow easy editing for inserting compile commands before the
file names in the preparation of batch command files.
.LIST ELEMENT; PAGE - Create a paged file from one or more existing files;
the component files may be specified individually or by include files
.LIST ELEMENT; SCAN - Perform a CHECK and then report on the name and
number of text lines in each component file of the indicated paged file;
if the file is not a paged file, SCAN presents the same information as CHECK
.LIST ELEMENT; TOGGLE - Display and toggle options
.LIST ELEMENT; UNPAGE - Extract the component files from the indicated
paged file; the paged file is left intact
.end list
.ap

	There are several options available under PAGER, and they are
toggled and displayed by the TOGGLE command.
These options are:

.tp 15
.no autoparagraph
.list "*"
.LIST ELEMENT; TOGGLE COMMENT - Select the comment banner
.LIST ELEMENT; TOGGLE INCLUDE - Place include files in paged files
.LIST ELEMENT; TOGGLE VERBOSE - Enable verbose mode
.end list
.ap

	More discussion of these options
will be presented in the discussions of the functions of PAGER which follow.

	Only the first letter of each command and each option for the TOGGLE
command is significant.  All other letters in a command or option are ignored.
Only with file names are all letters of significance.
Hence,

.literal

	PAGE filename
and
	P filename


are equivalent, as are


	TOGGLE INCLUDE
and
	T I

.end literal

	Any PAGER command beginning with a dash (_-) is a comment line
to PAGER and is not processed in any way.

.tp 10
.HEADER LEVEL 2 CHECK Function

	CHECK counts the number of Ada statements, Ada comments, and text
lines in the indicated file.  It also computes a checksum of all the printable
characters in this file.  The indicated file does not have to be a paged file.
The syntax of the CHECK command is:

.literal

		CHECK filename

.end literal

	CHECK is useful in providing a validity check of a file transfer.
By running CHECK on a file residing on a source computer, transferring the
file from the source computer to a destination computer, and then running
CHECK on the file as transferred to a destination computer, the user can
verify the transfer.  If the checksums match, it is likely that the
transfer was successful.  Since the checksum is computed on the printable
characters (which do not include spaces, tabs, carriage returns, or line
feeds), this check does not reflect any differences caused by tab expansion
(expanding tab characters into spaces) and the like which may be caused by
the transfer mechanism.

.tp 15
.HEADER LEVEL 2 HELP Function

	The HELP command displays a brief help text to the user.  The
syntax of this command is:

.literal

		HELP

.end literal

.tp 15
.HEADER LEVEL 2 LIST Function

	The LIST function is used to create a text file containing the
names of the component files within a paged file.  The syntax of the LIST
command is:

.literal

		LIST paged_file_name

.end literal

	Upon execution, this command will prompt the user for the name of
the output file.  If he strikes just the RETURN key, PAGER aborts the LIST
function and does not generate an output file.
	The output file has the following general format:

.literal
	$$ file_name_1
	$$ file_name_2
	...
.end literal

	A text editor can be used to make a global substitution of the "$$ "
characters.  For instance, if the component files were to be compiled in
the order they were stored in the paged file, substituting "$ ada " for
"$$ " in this listing file creates a DEC submit file which compiles all
files named.  Likewise, a substitution of "$ print " would print all
files named.

.tp 15
.HEADER LEVEL 2 PAGE Function

	The PAGE function is used to created a paged file from one or
more component files.  The syntax of the PAGE command is:

.literal

		PAGE filename

.end literal

	When the PAGE command is issued, the user is prompted for the
name of a file.  He may then type the name of a component file, strike
return, and he will be prompted again.  This process continues until the
user strikes only a return in response to the file name prompt.  At this
point, PAGE will create the paged file from the component files named by
the user.

	If the user prefixes the name of a component file with an atsign
character (_@), the indicated file is processed as an include file.
An include file is a file which contains the names of zero or more component
files, one name per line starting in the first column.  Other
include files may be referenced within an include file by prefixing
their names with the atsign character.  Comments may be placed within
an include file by placing two dashes in the first two columns of a line.
The following is an example of an include file:

.tp 30
.literal

         Example                      Comments
         =======                      ========
--
-- This is an include file for        Comment at the beginning
--  my favorite tool
--
                                      Blank lines are allowed
--
-- The following include file
--  contains the names of the         Another comment
--  Ada source files in compilation
--  order
--
@mytool.cmp
--
-- The following are the documentation
--  files
--
mytool.ref
mytool.doc
mytool.idx

.end literal

	The following toggled options are applicable to the PAGE command:

.no autoparagraph
.list "*"
.LIST ELEMENT; TOGGLE COMMENT - If the COMMENT option is ON, the Ada
comment banner (--::::::::::) is used; if the COMMENT option is OFF, the
standard banner (::::::::::) is used.
.LIST ELEMENT; TOGGLE INCLUDE - If the INCLUDE option is ON, any include
file referenced is placed in the paged file as a component file; if the
INCLUDE option is OFF, include files are not placed in the paged file
unless explicitly named.  For example, if _@MYTOOL.DIS is specified with
INCLUDE off, only the files named in MYTOOL.DIS are included; if INCLUDE
is on, MYTOOL.DIS is included as well as the files named within it.
.LIST ELEMENT; TOGGLE VERBOSE - If the VERBOSE option is ON, more information
is displayed during the execution of the PAGE command; if the VERBOSE option
is OFF, less information is displayed
.end list
.ap

.tp 15
.HEADER LEVEL 2 SCAN Function

	The SCAN function is similar to the CHECK function, but it also
lists the names and number of text lines in
the component files in a paged file.  If SCAN is run on a file which is not
a paged file, the output is identical to CHECK.  The syntax of SCAN is:

.literal

		SCAN filename

.end literal

	The VERBOSE toggle causes SCAN to present the count of text lines
to the user as well as the file names of the component files.

.tp 15
.HEADER LEVEL 2 TOGGLE Function

	The TOGGLE command displays and toggles the options of PAGER.
TOGGLE with no argument displays the options.  TOGGLE followed by a
valid option toggles the state (ON/OFF) of that option.

	The options to the TOGGLE command are:

.no autoparagraph
.list "*"
.LIST ELEMENT; COMMENT - Comment banner (PAGE command only)
.LIST ELEMENT; INCLUDE - Include file (PAGE command only)
.LIST ELEMENT; VERBOSE - Verbose mode
.end list
.ap

.tp 15
.HEADER LEVEL 2 UNPAGE Function

	The UNPAGE command extracts the components from the indicated paged
file, leaving the original paged file intact.  The syntax of UNPAGE is:

.literal

		UNPAGE filename

.end literal

	The VERBOSE toggle causes UNPAGE to present the count of text lines
to the user as each component file is extracted.

.tp 15
.HEADER LEVEL 2 X Function

	The X command exits PAGER.  Its syntax is:

.literal

		X

.end literal


.tp 20
.HEADER LEVEL 1 Sample Session

	The following is a sample PAGER session.  It was run on a VAX 11/785
running VMS 4.0.

.literal


$ dir

Directory USER4:[CONN.ADA]

CAS3.ADA;1               15  (RWE,RWED,RE,RE)
CHARACTER_SET.ADA;1
                         21  (RWE,RWED,RE,RE)
LIB.DIR;1                 3  (RE,RWE,RE,RE)
PAGER.ADA;2              13  (RWE,RWED,RE,RE)
PAGER_COMPILE.DIS;1
                          1  (RWE,RWED,RE,RE)
PAGER_SUPPORT.ADA;1
                         47  (RWE,RWED,RE,RE)

Total of 6 files, 100 blocks.

$ type pager_compile.dis

--
-- Compilation order for all files required to create the
--  PAGER program
--
character_set.ada
cas3.ada
pager_support.ada
pager.ada

$ pager
PAGER, Version 1.6
Type HELP for Help
PAGER> h
PAGER Commands:
 CHECK filename  --  Ada Check on File
 LIST filename   --  List Names of Component Files
 PAGE filename   --  Create Paged File
 SCAN filename   --  List Files in Paged File
 TOGGLE          --  Indicate Flag Settings
 TOGGLE flag     --  Toggle Indicated Flag:
                     Comment, Include File, or
                     Verbose
 UNPAGE filename --  Extract from Paged File
 X (Exit)        --  Exit PAGER
PAGER> t
  Comment Prefix is Disabled
  Include File Prefix is Enabled
  Verbose Mode is Enabled
PAGER> -- I will now create PAGER.SRC, which is
PAGER> -- composed of PAGER_SUPPORT.ADA and PAGER.ADA
PAGER> page pager.src
Enter Names of Files (RETURN when done)
  Input File Name > pager_support.ada
  Input File Name > pager.ada
  Input File Name > 

  Component Files --
    pager_support.ada
           714 Lines
    pager.ada
           150 Lines
PAGER> -- PAGER_FULL.SRC contains all files required to compile
PAGER> -- PAGER.ADA.  The file PAGER_COMPILE.DIS contains those
PAGER> -- file names in compilation order.
PAGER> toggle comment
  Comment Prefix is Enabled
PAGER> t
  Comment Prefix is Enabled
  Include File Prefix is Enabled
  Verbose Mode is Enabled
PAGER> page pager_full.src
Enter Names of Files (RETURN when done)
  Input File Name > @pager_compile.dis
    Include File: pager_compile.dis
      pager_compile.dis
      character_set.ada
      cas3.ada
      pager_support.ada
      pager.ada
    End of Include File pager_compile.dis
  Input File Name > 

  Component Files --
    pager_compile.dis
             8 Lines
    character_set.ada
           321 Lines
    cas3.ada
           194 Lines
    pager_support.ada
           714 Lines
    pager.ada
           150 Lines
PAGER> x


$ cd upload r
  USER4:[CONN.UPLOAD]
$ pager
PAGER, Version 1.6
Type HELP for Help
PAGER> -- Demo of CHECK
PAGER> check [conn.ada]pager_full.src
Input File: [conn.ada]pager_full.src
  Ada Statements:    628
  Ada Comments:      309
  Text Lines:       1402
  Checksum:           91
PAGER> -- Demo of SCAN
PAGER> scan [conn.ada]pager_full.src
Input File: [conn.ada]pager_full.src
  Ada Statements:    628
  Ada Comments:      309
  Text Lines:       1402
  Checksum:           91
  Component Files -- 
    pager_compile.dis
             8 Lines
    character_set.ada
           321 Lines
    cas3.ada
           194 Lines
    pager_support.ada
           714 Lines
    pager.ada
           150 Lines
PAGER> -- Demo of UNPAGE
PAGER> unpage [conn.ada]pager_full.src
     pager_compile.dis
             8 Lines
     character_set.ada
           321 Lines
     cas3.ada
           194 Lines
     pager_support.ada
           714 Lines
     pager.ada
           150 Lines
PAGER> -- Check/Scan on a "normal" file
PAGER> check pager_support.ada
Input File: pager_support.ada
  Ada Statements:    324
  Ada Comments:      172
  Text Lines:        714
  Checksum:           22
PAGER> scan pager_support.ada
Input File: pager_support.ada
  Ada Statements:    324
  Ada Comments:      172
  Text Lines:        714
  Checksum:           22
PAGER> check pager.ada
Input File: pager.ada
  Ada Statements:     74
  Ada Comments:        8
  Text Lines:        150
  Checksum:           61
PAGER> x
$

.end literal
