Google
 

Trailing-Edge - PDP-10 Archives - BB-FB49A-RM - sources/sntcex.b36
There are no other files named sntcex.b36 in the archive.
%title 'SNT Command Executor'

module SNTCEX (ident = 'Version 1.02') =
begin

! Copyright (c) 1984, 1985 by
! DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts
!
! This software is furnished under a license and may be used and  copied
! only  in  accordance  with  the  terms  of  such  license and with the
! inclusion of the above copyright notice.  This software or  any  other
! copies  thereof may not be provided or otherwise made available to any
! other person.  No title to and ownership of  the  software  is  hereby
! transferred.
!
! The information in this software is subject to change  without  notice
! and  should  not  be  construed  as  a commitment by Digital Equipment
! Corporation.
!
! Digital assumes no responsibility for the use or  reliability  of  its
! software on equipment which is not supplied by Digital.
!++
! FACILITY:	DECnet/SNA TOPS-20 Trace Protocol Utility command executor.
!
! ABSTRACT:	This module provide routines to execute the user commands
!               from the command parser.
!
! ENVIRONMENT:	TOPS-20 Operating Systems, user mode.
!
! AUTHOR:       Dennis Brannon,               CREATION DATE: January 17,1984
!
! MODIFIED BY:
!
! 	D. Brannon, 11-Oct-84 : VERSION 1.00
! 
! 1.01  D. Brannon, 23-Oct-84
!       Set ST[ST_SWITCH] to $FALSE to turn off all switches prior to parsing
!       in CEX$ANALYZE and CEX$TRACE.
!
! 1.02  D. Brannon, 31-Jan-85
!       Make ST[ST_CIRCUIT_ID] into a byte pointer instead of an address.
!--

!
! REQUIRED FILES
!

library 'MONSYM';                       ! Monitor symbols
library 'SNTDEF';                       ! SNT common definitions
library 'SYS:TXTLIB';                   ! Text Processing Library
library 'SNTLIB';                       ! SNT common library
require 'JSYS';                         ! TOPS-20 JSYS declarations

!
! FORWARD REFERENCES
!

forward routine
    CEX$ANALYZE,
    CEX$DDT,
    CEX$DEBUG,
    CEX$EXIT,
    CEX$HELP,
    CEX$PUSH,
    CEX$SERVICE,
    CEX$TAKE,
    CEX$TRACE;

forward routine
    CEX$PARSE_NODESPEC,
    CEX$COMMAND_EXECUTOR,
    CEX$PARSE_COMMAND_FILE,
    CEX$PARSE_COMMAND_LINE,
    CEX$COMMAND_PARSER: novalue;

!
! OWN STORAGE
!

own
    COMMAND_DISPATCH: COMMAND_DISPATCH_ENTRIES;

own
    IB: INITIAL_BLOCK,
    PB: PARSE_BLOCK,
    PROGRAM_NAME: initial (%sixbit 'PARSE'),
    PROMPT_STRING: CH$SEQUENCE (10) initial (%string ('SNT> ', %char(0)));

literal
    PARSE_TTY = 0,
    NO_PROMPT = 0;

macro CH$EXPLODE [] =
    CH$CHTAB (%quote %explode (%remaining)) %;

macro CH$CHTAB [CH] =
    %quote %c CH %;


bind SIXTAB =                           ! SIXBIT to ASCII translation table
    ch$transtable (0, CH$EXPLODE ('!"#$%&'), %c'''',
                   CH$EXPLODE ('()*+,-./0123456789:'),
                   CH$EXPLODE (';<=>?@ABCDEFGHIJKLM'),
                   CH$EXPLODE ('NOPQRSTUVWXYZ[\]^_'));

!
! EXTERNAL REFERENCES
!

external
    ST: SNTBLOCK,
    CONTROL: GLOBAL_CONTROL_BLOCK;

external routine                        ! GALAXY routines
    PB$INI,
    GLXLIB_ROUTINES;

external routine
    FIL$CLOSE_TRACE_FILE,
    FIL$CLOSE_OUTPUT_FILE,
    GAD$DISCONNECT_LINK,
    MEM$GET,
    MEM$RETURN: novalue,
    REX$ANALYZE,
    REX$SERVICE_REQUEST,
    REX$TRACE,
    TXT$WRITE,
    USP$ERROR_MESSAGE: novalue;
%global_routine ('CEX$ANALYZE') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the ANALYZE command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        JFN,
        NAME,
        PARAMETER,
        LENGTH;

    external
        $EB2AS,
        SNATRATBL;

    XERO (ST+4, SNTBLOCK_SIZE-4);       ! Zero out SNTBLOCK
                                        ! leave GATEWAY,USER,PASSWORD,CIRCUIT
                                        ! alone, so that they will default
                                        ! across commands.

    SNATRATBL = $EB2AS;                 ! Default the translation table

    ST[CMD_ANALYZE] = $TRUE;            ! its an ANALYZE command

    ST[ST_SWITCH] = $FALSE;             ! Turn off all switches

    if not P$IFIL (; NAME)              ! Parse analyzed file name
    then return $FALSE
    else begin
         ST[ST_ANALYZE_FILE] = ch$ptr (.NAME+1);  ! Pointer to file name string
         end;

    while P$SWIT (;PARAMETER)           ! Get switches
    do selectone .PARAMETER of
       set
          [KYWID]:                          ! /WIDE
             begin
             ST[SW_WIDE] = TRUE;
             end;
          [KYOUT]:                          ! /OUTPUT filespec
             begin
             if P$OFIL (; NAME)
             then begin                    ! Parse output file name
                  local JFN;
                  NAME = ch$ptr (.NAME+1); ! Pointer to file name string
                  if (JFN = .ST[ST_OUTPUT_JFN])
                  and (.JFN neq 0)         ! Release current JFN before
                  then jsys_rljfn (.JFN);  ! defining another file
                  ST[ST_OUTPUT_FILE] = .NAME;
                  ST[SW_OUTPUT] = TRUE;
                  end;
             end;
           [otherwise]:
              return $FALSE;
           tes;

    if not .ST[SW_OUTPUT]          ! User did not specify output file
    then begin
         NAME = CH$ASCIZ ('TTY:'); ! Default output file name
         ST[ST_OUTPUT_FILE] = .NAME;
         end;
    ST[SW_ANALYZE] = $TRUE;
    if not REX$ANALYZE ()               ! Analyze trace file
    then return $FALSE;

    return $TRUE;
    end;                                ! End of CEX$ANALYZE
%global_routine ('CEX$DDT') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the DDT command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    external routine
        USP$DYNAMIC_DEBUGGING_TOOL;

    ST[CMD_DDT] = $TRUE;      ! DDT command
    USP$DYNAMIC_DEBUGGING_TOOL ();

    return $TRUE;
    end;                                ! End of CEX$DDT
%global_routine ('CEX$DEBUG') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the DEBUG command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin
    ST[CMD_DEBUG] = $TRUE;    ! Debug command
    CONTROL[GCB_DEBUG_CALLS] = $TRUE;

    return $TRUE;
    end;                                ! End of CEX$DEBUG
%global_routine ('CEX$EXIT') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the EXIT command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin
    ST[CMD_EXIT] = $TRUE;
    CONTROL[GCB_EXIT] = $TRUE;

    return $TRUE;
    end;                                ! End of CEX$EXIT
%global_routine ('CEX$HELP') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the HELP command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    literal
        BUFFER_SIZE = $MEMORY_BUFFER_SIZE * 5;

    local
        FILE,
        JFN,
        TXTBUF,
        POINTER,
        LENGTH,
        ERROR,
        STATUS;

    ST[CMD_HELP] = $TRUE;               ! Help command
    FILE = CH$ASCIZ ('HLP:SNT.HLP');
    if not jsys_gtjfn (gj_sht+gj_old, .FILE; JFN)
    then return $FALSE;                 ! Return error if failed to get JFN

    if not jsys_openf (.JFN, of_rd+$$(7,of_bsz))
    then begin                          ! Failed to open file
         jsys_rljfn (.JFN);             ! Release JFN
         return $FALSE;                 ! Return error
         end;

    TXTBUF = MEM$GET (1);               ! Get text buffer
    ERROR = $FALSE;                     ! Assume no error

    while not (jsys_gtsts (.JFN; , STATUS); .STATUS<$(gs_eof)>)
    do begin
       POINTER = ch$ptr (.TXTBUF);
       if jsys_sin (.JFN, .POINTER, BUFFER_SIZE, $LF; ,, LENGTH)
       then begin                       ! Parse one line of command at a time
            LENGTH = BUFFER_SIZE - .LENGTH;

            ! Display the parsed file content
            jsys_sout ($priou, .POINTER, -.LENGTH);
            end;
       end;

    jsys_closf (.JFN);                  ! Close command file
    MEM$RETURN (.TXTBUF);               ! Return text buffer

    return $TRUE;
    end;                                ! End of CEX$HELP
%global_routine ('CEX$PUSH') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the PUSH command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        RE_ENTRY;                       ! Reentrant flag

    ST[CMD_PUSH] = $TRUE;               ! Push command
    if .CONTROL[GCB_EXEC_HANDLE] neq 0
    then RE_ENTRY = $TRUE               ! Re-enter EXEC fork
    else begin                          ! Start a new level of EXEC
         if jsys_cfork (cr_cap; CONTROL[GCB_EXEC_HANDLE])
         then begin
              local PTR, JFN, EXEC: CH$SEQUENCE (40);

              PTR = ch$ptr (EXEC);
              jsys_jfns (.PTR, 1, 0, 0); ! Get file spec of top level EXEC
              jsys_gtjfn (gj_sht+gj_old, .PTR; JFN); ! Get file JFN
              jsys_get ((.CONTROL[GCB_EXEC_HANDLE]^18)+.JFN); ! Map in the EXEC
              RE_ENTRY = $FALSE;        ! Start at primary entry address
              end;
         end;

    jsys_sfrkv (.CONTROL[GCB_EXEC_HANDLE], .RE_ENTRY); ! Fork next level EXEC
    jsys_wfork (.CONTROL[GCB_EXEC_HANDLE]); ! Wait for POP from EXEC

    return $TRUE;
    end;                                ! End of CEX$PUSH
%global_routine ('CEX$SERVICE') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the SERVICE command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    return (REX$SERVICE_REQUEST ());

    end;                                ! End of CEX$SERVICE
%global_routine ('CEX$TAKE') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the TAKE command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        FILE,
        VERBOSE;

    ST[CMD_TAKE] = $TRUE;               ! Take command
    if not P$IFIL (; FILE)              ! Parse file name
    then return $FALSE;
    FILE = ch$ptr (.FILE+1);            ! Get pointer to file name

    if not P$SWIT (; VERBOSE)           ! Parse display keyword
    then VERBOSE = $FALSE;

    CEX$PARSE_COMMAND_FILE (.FILE, .VERBOSE);

    return $TRUE;
    end;                                ! End of CEX$TAKE
%global_routine ('CEX$TRACE') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to execute the TRACE command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin
    local
        ACCESS,
        NODE,
        LEN,
        PTR,
        USER,    
        PASSWORD,
        CIRC,
        GWY,
        NAME,
        NODESPEC,
        PARAMETER;
    external
        SNATRATBL,
        EBAS: REF VECTOR,
        $EB2AS;
    external routine
        TRANX : GALAXY,
        TRC$TRACE;

    XERO (ST+4, SNTBLOCK_SIZE-4);       ! Zero out SNTBLOCK
                                        ! leave GATEWAY,USER,PASSWORD,CIRCUIT
                                        ! alone, so that they will default
                                        ! across commands.

    SNATRATBL = $EB2AS;                 ! Default the translation table

    ST[CMD_TRACE] = $TRUE;              ! Trace command

    ST[ST_SWITCH] = $FALSE;             ! Turn off all switches

    if not P$FLD (; NODE)               ! Get nodespec
    then return $FALSE;
    ST[ST_GATEWAY] = ch$ptr (.NODE+1);

    if P$QSTR (; ACCESS)                   ! Get user-id
    then begin
         ST[ST_USER] = CH$PTR (.ACCESS+1);
         LEN = CH$LEN (.ST[ST_USER]);
         PTR = CH$FIND_CH (.LEN, .ST[ST_USER], %C' ');
         CH$WCHAR_A (0, PTR);
         ST[ST_PASSWORD] = .PTR;
         end;

    P$NEXT();                           ! Skip past the "::"

    if not P$FLD (; CIRC)               ! Get Circuit-id
    then return $FALSE;
    ST[ST_CIRCUIT_ID] = ch$ptr(.CIRC + 1);

    while P$SWIT (; PARAMETER)          ! Get switches
    do selectone .PARAMETER of
        set
        [KYANT]:                        ! /Analyze
            begin
            ST[SW_ANALYZE] = $TRUE;
            end;
        [KYBUF]:                        ! /Buffers:n
            begin
            ST[SW_BUFFERS] = $TRUE;
            if not P$NUM ( ; ST[ST_BUFFERS])
            then ST[ST_BUFFERS] = BUFFERS_DEF_K$SNTCOM;
            end;                              
        [KYCHA]:                        ! /Character_set: filespec
            begin
            ST[SW_CHARACTER_SET] = $TRUE;
            if P$IFIL (; ST[ST_CHARACTER_SET])
            then begin
                 SNATRATBL = EBAS;
                 TRANX(.ST[ST_CHARACTER_SET],EBAS);
                 end;
            end;
        [KYCIR]:                        ! /Circuit
            begin
            ST[SW_CIRCUIT] = $TRUE;
            ST[ST_TYPE] = FCT_CIRCUIT_K$TRAPRO;
            end;
        [KYENT]:                        ! /Entries:n
            begin
            ST[SW_ENTRIES] = $TRUE;
            if not P$NUM ( ; ST[ST_ENTRIES])
               then ST[ST_ENTRIES] = ENTRIES_DEF_K$SNTCOM;
            end;
        [KYTFL]:                        ! /Output:filespec
            begin
            ST[SW_OUTPUT] = $TRUE;
            if P$OFIL (; NAME)
            then begin                    ! Parse output file name
                 local JFN, LENGTH;
                 NAME = ch$ptr (.NAME+1); ! Pointer to file name string
                 if (JFN = .ST[ST_OUTPUT_JFN])
                 and (.JFN neq 0)         ! Release current JFN before
                 then jsys_rljfn (.JFN);  ! defining another file
                 ST[ST_OUTPUT_FILE] = .NAME;
                 end;
            end;
        [KYPAS]:
            begin
            ST[SW_PASSWORD] = $TRUE;
            P$FLD (; PASSWORD);
            ST[ST_PASSWORD] = CH$PTR (.PASSWORD + 1);
            end;
        [KYPUN]:                        ! /Pu
            begin
            ST[SW_PU] = $TRUE;
            ST[ST_TYPE] = FCT_PU_K$TRAPRO;
            end;
        [KYSES]:                        ! /Session:n
            begin
            ST[SW_SESSION] = $TRUE;
            ST[ST_TYPE] = FCT_SESSION_K$TRAPRO;       
            if not P$NUM ( ; ST[ST_SESSION])
               then return $FALSE;
            end;
        [KYSIZ]:                        ! /Size:n
            begin                   
            ST[SW_SIZE] = $TRUE;
            if not P$NUM ( ; ST[ST_SIZE])
               then ST[ST_SIZE] = SIZE_DEF_K$SNTCOM;
            end;
        [KYUSR]:
            begin
            ST[SW_USER] = $TRUE;
            P$FLD (; USER);
            ST[ST_USER] = CH$PTR (.USER + 1);
            end;
        [KYVER]:                        ! /Version_limit:n
            begin
            ST[SW_VERSION_LIMIT] = $TRUE;
            if not P$NUM ( ; ST[ST_MAXFILES])
               then ST[ST_MAXFILES] = MAXFILES_DEF_K$SNTCOM;
            end;
        [KYTWD]:                        ! /Wide
            begin
            ST[SW_WIDE] = $TRUE;
            end;
        [otherwise]:
            return $FALSE;
        tes;

        if .ST[SW_ANALYZE]
        then if .ST[SW_OUTPUT]
             then if .ST[ST_OUTPUT_FILE] eql 0
                  then ST[ST_OUTPUT_FILE] = CH$ASCIZ ('SNT.LST')
                  else ST[ST_OUTPUT_FILE] = .NAME
             else ST[ST_OUTPUT_FILE] = CH$ASCIZ ('TTY:')
        else if .ST[ST_OUTPUT_FILE] eql 0
             then ST[ST_OUTPUT_FILE] = CH$ASCIZ ('SNT.DAT')
             else ST[ST_OUTPUT_FILE] = .NAME;

	return (TRC$TRACE ());

    end;                                ! End of CEX$TRACE
%routine ('CEX$COMMAND_EXECUTOR') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to parse and dispatch command execution routines.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        KEY;

    if P$KEYW (; KEY)                   ! Parse command keyword
    and (.COMMAND_DISPATCH[.KEY,CPD_ROUTINE] neq 0)
    then begin
         bind routine COMEXE = .COMMAND_DISPATCH[.KEY,CPD_ROUTINE];

         if not COMEXE ()               ! Dispatch routine
         then begin                     ! If command failed
              local TXTBUF, POINTER;

              TXTBUF = MEM$GET (1);     ! Get text buffer

              POINTER = ch$ptr (.TXTBUF);
              TXT_WRITE (POINTER,       ! Format message
                         $MEMORY_BUFFER_SIZE * 5,
                         '? Command "%a" failed%/',
                         ch$ptr (.CONTROL[GCB_COMMAND_STRING]));
              jsys_psout (ch$ptr (.TXTBUF));

              MEM$RETURN (.TXTBUF);     ! Return text buffer

              return $FALSE;
              end;
         end;

    return $TRUE;
    end;                                ! End of CEX$COMMAND_EXECUTOR
%routine ('CEX$PARSE_COMMAND_FILE', FILE, DISPLAY) =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to parse and process indirect command file.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    literal
        BUFFER_SIZE = $MEMORY_BUFFER_SIZE * 5;

    local
        JFN,
        TXTBUF,
        POINTER,
        LENGTH,
        ERROR,
        STATUS;

    if not jsys_gtjfn (gj_sht+gj_old, .FILE; JFN)
    then return $FALSE;                 ! Return error if failed to get JFN

    if not jsys_openf (.JFN, of_rd+$$(7,of_bsz))
    then begin                          ! Failed to open file
         jsys_rljfn (.JFN);             ! Release JFN
         return $FALSE;                 ! Return error
         end;

    TXTBUF = MEM$GET (1);               ! Get text buffer
    ERROR = $FALSE;                     ! Assume no error

    while not (jsys_gtsts (.JFN; , STATUS); .STATUS<$(gs_eof)>)
    do begin
       POINTER = ch$ptr (.TXTBUF);
       if jsys_sin (.JFN, .POINTER, BUFFER_SIZE, $LF; ,, LENGTH)
       then begin                       ! Parse one line of command at a time
            LENGTH = BUFFER_SIZE - .LENGTH;

            if .DISPLAY
            then begin                  ! Display the parsed file content
                 jsys_psout (ch$ptr (PROMPT_STRING));
                 jsys_sout ($priou, .POINTER, -.LENGTH);
                 end;

            if .LENGTH gtr 0
            then begin                  ! Check for illegal command
                 local CHAR;

                 ch$wchar (0, ch$plus (.POINTER, .LENGTH));

                 do begin
                    CHAR = ch$rchar (.POINTER);
                    selectone .CHAR of
                        set
                        [$HT,
                         %C' ']:
                            begin
                            POINTER = ch$plus (.POINTER, 1);
                            LENGTH = .LENGTH - 1;
                            end;

                        [%O'0' to %O'10',
                         %O'12' to %O'37',
                         %C'!' to %C'-',
                         %C'/' to %C'@',
                         %C'[' to %C'`',
                         %C'{' to %O'177']:
                            LENGTH = 0;
                        tes;
                    end
                 until (.CHAR neq %C' ')
                 or (.LENGTH leq 0);
                 end;

            ! If line is a non null command, parse and execute

            if (.LENGTH gtr 0)
            and CEX$PARSE_COMMAND_LINE (NO_PROMPT, .TXTBUF)
            then if not CEX$COMMAND_EXECUTOR ()
                 then ERROR = $TRUE;
            end;
         end;

    jsys_closf (.JFN);                  ! Close command file
    MEM$RETURN (.TXTBUF);               ! Return text buffer

    return (not .ERROR);
    end;                                ! End of CEX$PARSE_COMMAND_FILE
%routine ('CEX$PARSE_COMMAND_LINE', PROMPT, SOURCE) =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to set up the parsing block for a command.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        RESULT,
        ERROR,
        PTR,
        LEN,
        PR: ref PARSER_RETURN_BLOCK,
        CB: ref COMMAND_BLOCK;

    PB[PB_TB] = PB$INI;                 ! Initial Parse Block address
    PB[PB_PM] = .PROMPT;                ! Prompt
    PB[PB_CM] = 0;                      ! Let GALAXY allocate page
    PB[PB_SR] = .SOURCE;                ! Source of command line

    if PARSER (PARSE_BLOCK_SIZE, PB)
    then begin                          ! Parsed command successfully
         register AC2 = 2;

         PR = .AC2;                     ! Get parse return block address
         CB = .PR[PRB_CM];              ! Get address of parsed command

         P$SETUP (.CB+.CB[CB_PB]);      ! Set up the parser block

         ERROR = 0;                     ! No error
         RESULT = $TRUE;                ! Successful
         end
    else begin                          ! Failed to parse command
         register AC2 = 2;

         PR = .AC2;                     ! Print error message
         ERROR = .PR[PRB_EM];           ! Get error message

         if .PROMPT eql NO_PROMPT       ! If indirect command, reproduce
         then begin                     ! the erroneous text
              local PTR;

              PTR = ch$ptr (.SOURCE);
              jsys_psout (CH$ASCIZ ('? Command "'));
              jsys_sout ($priou, .PTR, -(CH$LEN (.PTR) - 2));
              jsys_psout (CH$ASCIZ ('" failed', %char($CR,$LF)));
              end;

         jsys_psout (CH$ASCIZ ('? '));
         jsys_psout (ch$ptr (.ERROR));
         jsys_psout (CH$ASCIZ (%char($CR,$LF)));

         RESULT = $FALSE;               ! Failed
         end;

    ! Save the image of the command line without the CR/LF
    ! and make it an ASCIZ string

    LEN = CH$LEN (ch$ptr (.PR[PRB_MS])) - 2;
    PTR = ch$move (.LEN, ch$ptr (.PR[PRB_MS]), ch$ptr (.CONTROL[GCB_COMMAND_STRING]));
    ch$wchar (0, .PTR);

    return .RESULT;
    end;                                ! End of CEX$PARSE_COMMAND_LINE
%routine ('CEX$PARSE_NODESPEC', NODESPEC, NODE, USER, PASSWORD) =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Function to parse a vms style nodespec and separate out
!       the nodename, user and password fields.
!
! FORMAL PARAMETERS:
!
!       NODESPEC address of VMS style node specification,
!                 ex: NODE"USER PASSWORD"::
!       NODE     address of the node name string
!       USER     address of the user id string
!       PASSWORD address of the password string
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        PTR1,
        PTR2,
        LEN,
        DESTPTR;
    
    NODE = 0;
    USER = 0;
    PASSWORD = 0;

    !
    ! Separate out the node name from the nodespec
    !

    PTR1 = ch$ptr (.NODESPEC);
    LEN = ch$len (.PTR1);
    PTR2 = CH$FIND_CH (.LEN, .PTR1, 34);    ! search for the double quote char
    LEN = ch$diff (.PTR1,.PTR2);
    DESTPTR = ch$ptr (.NODE);
    ch$move (.LEN, .PTR1, .DESTPTR);         ! Snarf it

    !
    ! Separate out the user id from the nodespec
    !
   
    PTR1 = .PTR2 + 1;                        ! Skip over the double quote char
    LEN = ch$ptr (.PTR1);
    PTR2 = ch$find_ch (.LEN, .PTR1, %C' ');    ! Search for space between user
                                             ! and password
    if .PTR2 eql 0 then return $TRUE;        ! No user and password specified
    LEN = ch$diff (.PTR1,.PTR2);
    DESTPTR = ch$ptr (.USER);
    ch$move (.LEN, .PTR1, .DESTPTR);
    
    !
    ! Separate out the Password from the Nodespec
    !

    PTR1 = .PTR2 + 1;
    LEN = ch$len (.PTR1);
    PTR2 = ch$find_ch (.LEN, .PTR1, 34);     ! Search for the double quote char
    LEN = ch$diff (.PTR1, .PTR2);
    DESTPTR = ch$ptr (.PASSWORD);
    ch$move (.LEN, .PTR1, .DESTPTR);
    if ch$len (.PTR2) neq 3 then return $FALSE;

    return $TRUE;
    end;                                ! End of CEX$PARSE_NODESPEC
%global_routine ('CEX$COMMAND_PARSER') : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Entry point of the command parser.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       $TRUE   Successful.
!       $FALSE  Otherwise.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    IB[IB_PROGRAM] = PROGRAM_NAME;      ! Initialize program PARSE
    if not I_INIT (INITIAL_BLOCK_SIZE, IB)
    then begin                          ! Failed to initialize GALAXY library
         jsys_psout (CH$ASCIZ ('Failed to initialize GALAXY'));
         jsys_haltf ();
         end;

    ! Process initialize file

    if CEX$PARSE_COMMAND_FILE (CH$ASCIZ ('DSK:SNT.INI'), $FALSE)
    then jsys_psout (CH$ASCIZ ('Initialization Completed'));

    ! Parse commands from TTY:

    while not .CONTROL[GCB_EXIT]
    do begin
       if CEX$PARSE_COMMAND_LINE (PROMPT_STRING, PARSE_TTY)
       then CEX$COMMAND_EXECUTOR ();
       end;

    FIL$CLOSE_TRACE_FILE ();
    FIL$CLOSE_OUTPUT_FILE ();
    GAD$DISCONNECT_LINK(.ST[ST_JFN]);
    jsys_rljfn (-1);   ! release all the JFNs belonging to this process
    return;
    end;                                ! End of CEX$COMMAND_PARSER
end                                   ! End of SNTCEX module
eludom
! Local Modes:
! Mode:BLISS
! Auto Save Mode:2
! Comment Column:40
! Comment Rounding:+1
! End: