::::::::::
INTRO.TXT
::::::::::

Here are 2 implementations of a system dependent interface to terminals.
The implementations run on DEC VAX/VMS Ada and Data General AOS/VS ADE.
These packages were developed for a Virtual Terminal developed for NOSC
through WIS tools contract.

The following functionality is supported:
* open the physical terminal with no echo and in binary mode, XON/XOFF 
  supported,
* close the physical terminal and reset it back to what it was before,
* put strings to the physical terminal with no translation,
* get strings form the physical terminal, again, no translation,
* get terminal capabilities file (TCF) name,
  this may be of limited use for other applications,
* get the terminal's name,
  this may be of limited use for other applications,
* check the validity of a particular character,
  call this one to see what characters can be used and which cannot be
  used.

Notes:
* The calls to read DO NOT block the entire process, only the calling
  task.
* The DG implementation will return only a single character at a time when
  'get' is called.
* The VAX version may return many characters when 'get' is called.
* The VAX version was developed using the Beta site compiler,  It may change
  with the formal release (they claim that starlet, condition_handling, and
  tasking_services may change with the formal release ).

There are five files here.

decada_sysdep_vt_spec.ada
decada_sysdep_vt_body.ada
decada_termsup.mar              This is the macro code to support
                                setting and resetting the terminal
                                characteristics.

dgade_sysdep_vt_spec.ada
dgade_sysdep_vt_body.ada


There is a sysdep_process package in the same vein being developed here
at Texas Instruments.  It will be distributed it as soon as it is ready.
It allows for process creation/deletion/communication through IPC channels.

-Stewart French
french%ti-eg@csnet-relay.arpa
Texas Instruments




::::::::::
decada_sysdep_vt_spec.ada
::::::::::
-- ---------------------------------------------------------------------------
-- ABSTRACT:  This system dependency package is the only package that
--            needs modifications when rehosting the Virtual Terminal tool
--            to another environment.
--            The supported functions are:
--                * open the physical terminal,
--                * close the physical terminal,
--                * put strings to the physical terminal,
--                * get strings form the physical terminal,
--                * get terminal capabilities file (TCF) name,
--                * get the terminal's name 
--                  (to be subsequently looked up in TCF
--                * check the validity of a particular character.
--
-- ----------------------------------------------------------------------------

PACKAGE sysdep IS

    PROCEDURE open;
    --
    -- Open the console for binary I/O, no echo.
    --

    PROCEDURE close;
    --
    -- Close the console.  Parameters should be reset to original condition.
    --

    PROCEDURE put ( data : IN string );

    --
    -- Put a string to the terminal.  There should be no translation of
    -- the characters. There can be exceptions to this rule (like CTRL-S and
    -- CTRL-Q)  and these exceptions must be identified in valid_character
    -- below.
    --

    PROCEDURE get ( data : OUT string;
                    last : OUT natural );

    --
    -- Get a string from the terminal keyboard.  This ocurrs with no echo
    -- and no translations.
    --

    PROCEDURE tcf_name ( name : OUT string;
                         last : OUT natural );
    --
    -- Returns the name of the terminal capabilities file as a string.
    -- You better pass in a string of sufficient length to handle the name
    -- that is returned or you will get a constraint error.  80 is a good
    -- random number.
    --

    PROCEDURE  terminal_name ( name : OUT string;
                               last : OUT natural );
    --
    -- Returns the name of the terminal.  This name of a string like "tv970".
    -- If the name cannot be determined then last is returned as 0 (zero).
    -- Again,  you better make the name parameter big enough to hold the
    -- value returned.
    --
    -- A DG implementation note:  This procedure looks for a file called
    -- TERM on your searchlist.
    --

    FUNCTION valid_character ( item : IN character ) RETURN boolean;

    --
    -- Returns a boolean value identifying whether the character passed in
    -- is safe to use in the environment.  Suspicious characters include
    -- CTRL-S  CTRL-Q  CTRL-C  CTRL-Y.

END sysdep;
::::::::::
decada_sysdep_vt_body.ada
::::::::::
WITH
    text_io,
    system,
    tasking_services,
    starlet,
    condition_handling;

USE
    text_io,
    system,
    tasking_services,
    starlet,
    condition_handling;

PACKAGE BODY sysdep IS

    TYPE status_enum IS (io_ok, io_not_ok );

    FUNCTION setterminfo (chan : short_integer) RETURN integer;
    PRAGMA interface( MACRO, setterminfo );
    PRAGMA import_function( internal    =>     setterminfo,
                            parameter_types => (short_integer),
                            result_type =>     integer,
                            external =>        "SETTERMINFO" );
    
    FUNCTION resetterminfo (chan : short_integer) RETURN integer;
    PRAGMA interface( MACRO, resetterminfo );
    PRAGMA import_function( internal    =>     resetterminfo,
                            parameter_types => (short_integer),
                            result_type =>     integer,
                            external =>        "RESETTERMINFO" );
 
    PROCEDURE cancel (
	status	: OUT integer;
	chan	: IN  short_integer);
 
    PRAGMA interface (EXTERNAL, cancel);
 
    PRAGMA import_valued_procedure
                         (cancel, "SYS$CANCEL",
                          (integer, short_integer),
                          (value,   value));


    PROCEDURE alloc (
	status	: OUT integer;
	devnam	: IN  string;
	phylen	: OUT integer;
	phybuf	: OUT string;
	acmode	: IN  integer := 0 );

    PRAGMA interface (EXTERNAL, alloc);
 
    PRAGMA import_valued_procedure (alloc, "SYS$ALLOC",
	(integer, string,        integer,   string,        integer),
	(value,   descriptor(s), reference, descriptor(s), value));
 

    PROCEDURE assign (
	status	: OUT integer;
	devnam	: IN  string;
	chan	: OUT short_integer;
	acmode	: IN  integer := 0;
	mbxnam	: IN  string := string'NULL_PARAMETER);
 
    PRAGMA interface (external, assign);
 
    PRAGMA import_valued_procedure (assign, "SYS$ASSIGN",
	(integer, string,        short_integer,   integer, string),
	(value,   descriptor(s), reference,       value,   descriptor(s)));

 
    PROCEDURE dassgn (
	status	: OUT condition_handling.cond_value_type;
	chan	: IN  starlet.channel_type);
 
    PRAGMA interface (external, dassgn);
 
    PRAGMA import_valued_procedure (dassgn, "sys$dassgn",
	(condition_handling.cond_value_type, starlet.channel_type),
	(value, value));

    PROCEDURE trnlog (
	status	: OUT integer;
	lognam	: IN  string;
	rsllen	: OUT short_integer;
	rslbuf	: OUT string;
	table	: IN  integer := 0;
	acmode	: OUT integer;
	dsbmsk	: IN  integer := 0 );

    PRAGMA interface (external, trnlog);
 
    PRAGMA import_valued_procedure (trnlog, "SYS$TRNLOG",
	(integer, string, short_integer, string, integer, integer, integer),
	(value, descriptor(s), reference, descriptor(s), value, reference,
           value));

    TASK TYPE terminal_reader_type IS
    ENTRY go;        
    END terminal_reader_type;
    
    TYPE terminal_reader_pointer IS ACCESS terminal_reader_type;

    TASK TYPE terminal_buffer_type IS
    ENTRY go;
    ENTRY put( data : IN character; io_status : IN status_enum );
    ENTRY get( data : OUT string; data_last : OUT natural );
    END terminal_buffer_type;

    TYPE terminal_buffer_pointer IS ACCESS terminal_buffer_type;

    terminal_reader : terminal_reader_pointer;
    terminal_buffer : terminal_buffer_pointer;
    terminal_in_channel : short_integer;
    terminal_out_channel : short_integer;

    PROCEDURE open IS
    status : integer;
    BEGIN
        assign
	    ( status,
	      "SYS$INPUT:",
              terminal_in_channel );

        IF status /= 1
        THEN
            text_io.put_line
               ( "In open (assign sys$input)  status : " & 
                 integer'image( status ) );
        END IF;

        assign
            ( status,
              "SYS$OUTPUT:",
	      terminal_out_channel );

        IF status /= 1
        THEN
            text_io.put_line
               ( "In open (assign sys$output)  status : " & 
                 integer'image( status ) );
        END IF;

        status := setterminfo( terminal_in_channel );

        IF status /= 1
        THEN
            text_io.put_line
             ( "In open (setterminfo)  status : " & 
                   integer'image( status ) );
        END IF;

        terminal_reader := NEW terminal_reader_type;
        terminal_buffer := NEW terminal_buffer_type;
        terminal_buffer.go;  -- start up the buffer handler.
        terminal_reader.go;  -- start up the terminal reader.
     END open;

    PROCEDURE close IS
    status : integer;
    BEGIN
        cancel( status, terminal_in_channel );

        IF status /= 1
        THEN
            text_io.put_line
               ( "In close (cancel)  status : " & 
                 integer'image( status ) );
        END IF;

        status := resetterminfo( terminal_in_channel );

        IF status /= 1
        THEN
            text_io.put_line
               ( "In close (resetterminfo)  status : " & 
                 integer'image( status ) );
        END IF;

        dassgn( condition_handling.cond_value_type( status ),
                starlet.channel_type(  terminal_in_channel ) );
        dassgn( condition_handling.cond_value_type( status ),
                starlet.channel_type(  terminal_out_channel ) );

    END close;


    PROCEDURE put ( data : IN string ) IS
    status : integer;
    temp_buffer : string( 1..data'LENGTH );
    ios_block : starlet.iosb_type;
    BEGIN

         tasking_services.task_qiow
             ( status => condition_handling.cond_value_type( status ),
               chan => starlet.channel_type( terminal_in_channel ),
               func => starlet.io_writevblk,
               iosb => ios_block,
               p1 => system.to_unsigned_longword( data(data'FIRST)'ADDRESS ),
               p2 => system.unsigned_longword( data'LENGTH )
             );

        IF status /= 1
        THEN
            text_io.put_line
               ( "In put  status : " & 
                 integer'image( status ) );
        END IF;
    END put;

    PROCEDURE low_level_get 
             ( data : OUT character; io_status : OUT status_enum  ) IS
    status : integer;
    length : CONSTANT positive := 1;
    temp_buffer : string( 1..1 );
    ios_block : starlet.iosb_type;
    BEGIN
 
         tasking_services.task_qiow
             ( status => condition_handling.cond_value_type( status ),
               chan => starlet.channel_type( terminal_in_channel ),
               func => ( starlet.io_readvblk OR 
                         starlet.io_m_nofiltr),
               iosb => ios_block,
               p1 => system.to_unsigned_longword( temp_buffer(1)'ADDRESS ),
               p2 => system.unsigned_longword( length )
             );

         IF (status /= 1) OR
            (ios_block.status /= 1)
         THEN
             io_status := io_not_ok;
         ELSE
             io_status := io_ok;
             data := temp_buffer(1);
         END IF;
    END low_level_get;

    TASK BODY terminal_reader_type IS
    buffer : character;
    status : status_enum;
    BEGIN
        ACCEPT go;
        LOOP
            low_level_get( buffer, status );
            terminal_buffer.put( buffer, status );
            IF status /= io_ok
            THEN
                EXIT;
            END IF;
        END LOOP;
    END terminal_reader_type;

    TASK BODY terminal_buffer_type IS
    type_ahead_buffer : string( 1..255 );
    type_ahead_buffer_length : natural := 0;
    keep_going : boolean := true;
    BEGIN
        ACCEPT go;
        WHILE keep_going
        LOOP
            SELECT

            WHEN type_ahead_buffer_length > 0 =>
            ACCEPT get( data : OUT string; data_last : OUT natural ) DO
                data( data'FIRST..data'FIRST+type_ahead_buffer_length-1 ) :=
                  type_ahead_buffer(1..type_ahead_buffer_length);
                data_last := data'FIRST+type_ahead_buffer_length-1;
                type_ahead_buffer_length := 0;
            END get;

            OR

            ACCEPT put( data : IN character;
                        io_status : IN status_enum ) DO
                IF io_status = io_ok
                THEN
                    type_ahead_buffer_length := type_ahead_buffer_length + 1;
                    type_ahead_buffer( type_ahead_buffer_length ) := data;
                ELSE
                    keep_going := false;
                END IF;
            END put;

            OR TERMINATE;

            END SELECT;
        END LOOP;
    END terminal_buffer_type;

    PROCEDURE get ( data : OUT string;
                    last : OUT natural ) IS
    BEGIN
        terminal_buffer.get( data, last );
    END get;

    PROCEDURE tcf_name ( name : OUT string;
                         last : OUT natural ) IS
    status : integer;
    temp_buffer : string( 1..80 ) := string'( 1..80 => ' ' );
    short_temp_length : short_integer;
    integer_temp_length : integer;
    ac_mode : integer;
    BEGIN
        trnlog( status, "TCF", short_temp_length, temp_buffer, 0, ac_mode );
        integer_temp_length := integer( short_temp_length );
        IF status /= 1
        THEN
            last := 0;
        ELSE
            name( name'FIRST..name'FIRST+integer_temp_length-1 ) := 
                   temp_buffer( 1..integer_temp_length );
            last := name'FIRST+integer_temp_length-1;
        END IF;
    END tcf_name;



    PROCEDURE  terminal_name ( name : OUT string;
                               last : OUT natural ) IS
    status : integer;
    temp_buffer : string( 1..80 ) := string'( 1..80 => ' ' );
    short_temp_length : short_integer;
    integer_temp_length : integer;
    ac_mode : integer;
    BEGIN
        trnlog( status, "TERM", short_temp_length, temp_buffer, 0, ac_mode );
        integer_temp_length := integer( short_temp_length );
        IF status /= 1
        THEN
            last := 0;
        ELSE
            name( name'FIRST..name'FIRST+integer_temp_length-1 ) := 
                   temp_buffer( 1..integer_temp_length );
            last := name'FIRST+integer_temp_length-1;
        END IF;
    END terminal_name;

    FUNCTION valid_character ( item : IN character ) RETURN boolean IS
    BEGIN
        CASE item IS
            WHEN ascii.dc3 => RETURN false; -- xon
            WHEN ascii.dc1 => RETURN false; -- xoff
            WHEN OTHERS => RETURN true;
        END CASE;
    END valid_character;

END sysdep;
::::::::::
decada_termsup.mar
::::::::::
         $TTDEF
         $TT2DEF
 ; Data section
 ;
         .PSECT DATA,NOEXE,WRT
 ; data used by Read routine
 ;
 MASK:   .LONG  ^X002000         ; Carriage return is terminator
         .LONG  0
         .QUAD  0
 TERMDESC:
         .LONG  16               ; Length to terminator descriptor
         .LONG  MASK             ; Address of mask
 DESCADD:.LONG  TERMDESC         ; Address of descriptor for terminator
 ;
 ; data used by terminal characteristic routines
 ;
 IOSTAT: .QUAD  0                      ; IO status block
 ;
 ; The terminal charasteristics are saved in the following 3 longwords
 ; we will save these for resetting terminal when we are finished
 ;
 SAVETERM:
         .BLKL  3
 TERMIN: .BLKL  3                      ; terminal information for setmode
 ;
 	.PSECT SETTERMINFO,EXE,NOWRT
 	.ENTRY SETTERMINFO,^M<>
 ;
 ;  From Ada..
 ;
 ;   FUNCTION setterminfo (chan : short_integer) RETURN integer;
 ;   PRAGMA interface( MACRO, setterminfo );
 ;   PRAGMA import_function( internal    =>     setterminfo,
 ;                           parameter_types => (short_integer),
 ;                           result_type =>     integer,
 ;                           external =>        "SETTERMINFO" );
 ; 
 ; This function sets the appropriate characteristics for the terminal
 ; associated with the channel.  If this channel is not connected to a terminal
 ; an error status will be returned.
 ;
         $QIOW_S FUNC=#IO$_SENSEMODE,-; get current characteristics
                 CHAN=@B^4(AP),-      ; channel is input to this routine
                 IOSB=IOSTAT,-        ; return status in IO status block
                 P1=SAVETERM,-        ; terminal characteristics
                 P2=#12               ; size of terminal characteristics block
         BLBS    R0,GOON2             ; check return status
 	JMP	ERR
 GOON2:  MOVZWL  IOSTAT,R0            ; Move return status to R0
 	BLBS	R0,GOON1
 	JMP	ERR
 ;
 GOON1:  MOVQ    SAVETERM,TERMIN      ; copy terminal information into buffer
         MOVL    SAVETERM+8,TERMIN+8  ; for set mode
 ;
 ; If other functions are desired, then find the symbol for them in
 ; the VAX/VMS I/O User's Guide (Volume 1) in the section on terminal
 ; driver.
 ;
         BISL2   #TT$M_NOECHO,TERMIN+4  ; set no echo
         BISL2   #TT$M_HOSTSYNC,TERMIN+4 ; set XON/XOFF
 	BISL2	#TT$M_TTSYNC,TERMIN+4	; 
 	BISL2	#TT$M_MECHFORM,TERMIN+4	; 
 	BISL2	#TT2$M_PASTHRU,TERMIN+8
 ;
 	BICL2	#TT$M_WRAP,TERMIN+4	; no wrap at end of line
         BICL2   #TT2$M_LOCALECHO,TERMIN+8 ; set no local echo
         $QIOW_S FUNC=#IO$_SETMODE,-  ; perform set mode
                 CHAN=@B^4(AP),-      ; channel is input to this routine
                 IOSB=IOSTAT,-        ; return status in IO status block
                 P1=TERMIN,-          ; terminal characteristics
                 P2=#12               ; size of terminal characteristics block
         BLBC    R0,ERR               ; check return status
         MOVZWL  IOSTAT,R0            ; Move return status to R0
         BLBC    R0,ERR               ; check return status
 ERR:	RET
 ; 
 	.PSECT RESETTERMINFO,EXE,NOWRT
 	.ENTRY RESETTERMINFO,^M<>
 ;
 ;  From Ada..
 ;
 ;   FUNCTION resetterminfo (chan : short_integer) RETURN integer;
 ;   PRAGMA interface( MACRO, resetterminfo );
 ;   PRAGMA import_function( internal    =>     resetterminfo,
 ;                           parameter_types => (short_integer),
 ;                           result_type =>     integer,
 ;                           external =>        "RESETTERMINFO" );
 ; 
 ; This function resets the terminal to its original charasteritics.
 ; If SetTermInfo was not called first then this routine will return a
 ; error status. If the channel is not connected to a terminal
 ; an error status will be returned.
 ;
         $QIOW_S FUNC=#IO$_SETMODE,-  ; perform set mode
                 CHAN=@B^4(AP),-      ; channel is input to this routine
                 IOSB=IOSTAT,-        ; return status in IO status block
                 P1=SAVETERM,-        ; terminal characteristics
                 P2=#12               ; size of terminal characteristics block
         BLBC    R0,ERROR             ; check return status
         MOVZWL  IOSTAT,R0            ; Move return status to R0
         BLBC    R0,ERROR             ; check return status
 ERROR:	RET
 
 	.END
::::::::::
dgade_sysdep_vt_spec.ada
::::::::::
PACKAGE sysdep IS

    PROCEDURE open;
    --
    -- Open the console for binary I/O, no echo.
    --

    PROCEDURE close;
    --
    -- Close the console.  Parameters should be reset to original condition.
    --

    PROCEDURE put ( data : IN string );

    --
    -- Put a string to the terminal.  There should be no translation of
    -- the characters. There can be exceptions to this rule (like CTRL-S and
    -- CTRL-Q)  and these exceptions must be identified in valid_character
    -- below.
    --

    PROCEDURE get ( data : OUT string;
                    last : OUT natural );

    --
    -- Get a string from the terminal keyboard.  This ocurrs with no echo
    -- and no translations.
    --

    PROCEDURE tcf_name ( name : OUT string;
                         last : OUT natural );
    --
    -- Returns the name of the terminal capabilities file as a string.
    -- You better pass in a string of sufficient length to handle the name
    -- that is returned or you will get a constraint error.  80 is a good
    -- random number.
    --

    PROCEDURE  terminal_name ( name : OUT string;
                               last : OUT natural );
    --
    -- Returns the name of the terminal.  This name of a string like "tv970".
    -- If the name cannot be determined then last is returned as 0 (zero).
    -- Again,  you better make the name parameter big enough to hold the
    -- value returned.
    --
    -- A DG implementation note:  This procedure looks for a file called
    -- TERM on your searchlist.
    --

    FUNCTION valid_character ( item : IN character ) RETURN boolean;

    --
    -- Returns a boolean value identifying whether the character passed in
    -- is safe to use in the environment.  Suspicious characters include
    -- CTRL-S  CTRL-Q  CTRL-C  CTRL-Y.

END sysdep;
::::::::::
dgade_sysdep_vt_body.ada
::::::::::
WITH tty_io,
     text_io,
     sys_calls,
     file_definitions,
     file_io,
     bit_ops,
     current_exception;

PACKAGE BODY sysdep IS

    buffer_byte_ptr : integer;
    buffer : integer;

    invalid_chars_array : ARRAY( 1..2 ) OF character;

    terminal : file_definitions.channel_number;
    tty : tty_io.file_type;

    previously_opened : boolean := false;

    temp_buffer_last : natural;

    PRAGMA page;
    TASK tty_server IS
        ENTRY go;
        ENTRY start_get;
        ENTRY get( data : OUT string;
                   last : OUT natural );
    END tty_server;

    TASK BODY tty_server IS
        bytes_read : integer;
        error_code : integer;
    BEGIN
        ACCEPT go;
        LOOP
            SELECT

                ACCEPT start_get;
                    file_io.read( terminal,
                                  error_code,
                                  bytes_read,
                                  buffer_byte_ptr,
                                  file_definitions.binary_io,
                                  1 );
                    buffer := bit_ops.logical_right_shift( buffer, 24 );

                ACCEPT get( data : OUT string;
                            last : OUT natural ) DO
                    last := 1;
                    data( 1 ) := character'val( buffer );
                END get;
            OR

                TERMINATE;

            END SELECT;
        END LOOP;

    END tty_server;


    PROCEDURE open IS
    console_characteristics : file_io.device_characteristics;
    error_code : integer;
    ac0, ac1, ac2 : integer;
    name : sys_calls.call_name;
    error_id : sys_calls.error_code;
    BEGIN

      IF NOT previously_opened
      THEN

       tty_io.open( tty, tty_io.inout_file, "@console" );

       -- turn off the keyboard interrupt capabilities

       ac0 := 0;
       ac1 := 0;
       ac2 := 0;
       name := sys_calls.kioff;
       sys_calls.long_sys( name, ac0, ac1, ac2, error_id );

       file_io.open( "@console", terminal, error_code,
                  file_definitions.open_for_input_output +
                  file_definitions.binary_io +
                  file_definitions.variable_length  );

       file_io.get_characteristics( terminal,
                  console_characteristics, error_code );
       console_characteristics.echo := file_io.no_echo;
       console_characteristics.characteristics(
                  file_io.non_ansi_standard_device ) := false;
       file_io.set_characteristics( terminal,
                  console_characteristics, error_code );

       buffer_byte_ptr := integer'val( buffer'address );
       buffer_byte_ptr := bit_ops.left_shift_by_1( buffer_byte_ptr );

       tty_server.go;

       previously_opened := true;
     END IF;

    END open;

    PROCEDURE close IS
    error_code : integer;
    BEGIN
       -- lets not do anything and let AOS clean up after me.
--     file_io.close( terminal, error_code );
       NULL;
    END close;


    PROCEDURE put ( data : IN string ) IS
    BEGIN
       tty_io.put( tty, data );
    END put;

    PROCEDURE get ( data : OUT string;
                    last : OUT natural ) IS
    BEGIN
        tty_server.start_get;
        tty_server.get( data, last );
    END get;


    PROCEDURE tcf_name ( name : OUT string;
                         last : OUT natural ) IS
    BEGIN
       last := name'first+2;
       name( name'first..(name'first)+2 ) := "TCF";
    END tcf_name;


    PROCEDURE  terminal_name ( name : OUT string;
                               last : OUT natural ) IS
       terminal_name_file : text_io.file_type;
       line_buffer : string( 1..80 );
       last_char_on_line : natural;
    BEGIN
       text_io.open( terminal_name_file, text_io.in_file, "TERM" );
       text_io.reset(terminal_name_file);
       text_io.get_line( terminal_name_file, line_buffer, last_char_on_line );
       name( name'first..(name'first)+last_char_on_line-1 ) :=
                                line_buffer( 1..last_char_on_line );
       last := name'first + last_char_on_line - 1;
       text_io.close( terminal_name_file );
    EXCEPTION
       WHEN others => last := 0;
    END terminal_name;


    FUNCTION valid_character ( item : IN character ) RETURN boolean IS
       valid_flag : boolean;
    BEGIN
       valid_flag := true;
       FOR i IN 1..8
       LOOP
          IF invalid_chars_array( i )=item
          THEN valid_flag := false;
          END IF;
       END LOOP;
       RETURN valid_flag;
    END valid_character;

BEGIN

    -- please refer to AOS/VS Programmer's Manual, Volume 1, System Concepts
    -- page 5-20 for a description of these character codes.

    invalid_chars_array( 1 ) := ascii.dc3;  -- CTRL-S
    invalid_chars_array( 2 ) := ascii.dc1;  -- CTRL-Q

END sysdep;
