[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS RTL Library (LIB$) Manual


Previous Contents Index

The LIB$T[ABLE_]PARSE macros assign an index number to each keyword. The index number is stored in the symbol type byte in the transition; it locates the associated keyword vector entry. The keyword strings are stored in the order encountered in the state table. Each keyword string is terminated by a byte containing the value --1. Between the keywords of adjacent states is an additional --1 byte to stop the ambiguous keyword scan.

To ensure that the keyword vector is adjacent to the keyword string area, the keyword vector is located in PSECT _LIB$KEY0$ and the keyword strings and stored in PSECT _LIB$KEY1$.

Your program should not use any of the three PSECTs used by LIB$T[ABLE_]PARSE (_LIB$STATE$, _LIB$KEY0$, and _LIB$KEY1$). The PSECTs _LIB$KEY0$ and _LIB$KEY1$ refer to each other using 16-bit displacements, so user PSECTs inserted between them can cause truncation errors from the linker.


Condition Values Returned

SS$_NORMAL Routine successfully completed. LIB$T[ABLE_]PARSE has executed a transition to TPA$_EXIT at main level, not within a subexpression.
LIB$_SYNTAXERR Parse completed with syntax error. LIB$T[ABLE_]PARSE has encountered a state at main level in which none of the transitions match the input string, or in which a transition to TPA$_FAIL was executed.
LIB$_INVTYPE State table error. LIB$T[ABLE_]PARSE has encountered an invalid entry in the state table.
Other If an action routine returns a failure status other than zero, and the parse consequently fails, LIB$T[ABLE_]PARSE returns the status returned by the action routine.

Examples

Example 1a
The following DEC C program accepts and parses the command line of a CREATE/DIRECTORY command using LIB$TABLE_PARSE. It uses the state table defined in Example 1b.


/*
** This DEC C program accepts and parses the command line of a CREATE/DIRECTORY
** command.  This program uses the LIB$GET_FOREIGN call to acquire the command
** line from the CLI and parse it with LIB$TABLE_PARSE, leaving the necessary
** information in its global data base.  The command line is of
** the following format:
**
**      CREATE/DIR DEVICE:[MARANTZ.ACCOUNT.OLD]
**                 /OWNER_UIC=[2437,25]
**                 /ENTRIES=100
**                 /PROTECTION=(SYSTEM:R,OWNER:RWED,GROUP:R,WORLD:R)
**
** The three qualifiers are optional.  Alternatively, the command
** may take the form:
**
**       CREATE/DIR DEVICE:[202,31]
**
** using any of the optional qualifiers.
**
** The source for this program can be found in:
**
**       SYS$EXAMPLES:LIB$TABLE_PARSE_DEMO.COM
**
*/

/*
** Specify the required header files
*/

# include <tpadef.h>
# include <descrip.h>
# include <starlet.h>
# include <lib$routines.h>

/*
** Specify macro definitions
*/

# define max_name_count 8
# define max_token_size 9
# define uic_string_size 6
# define command_buffer_size 256


/*
** Specify persistent data that's local to this module
*/

static
  union
    uic_union {
      __int32 bits;
      struct {
        char first;
        char second;
        } bytes;
      struct {
        __int16 first;
        __int16 second;
        } words;
      }
      file_owner;                             /* Actual file owner UIC */

static
  int
    name_count;                               /* Number of directory names */

static
  char
    uic_string[ uic_string_size + 1 ];        /* Buffer for string */

static
  struct
    dsc$descriptor_s
      name_vector[ max_name_count ];          /* Vector of descriptors */

/*
** Specify persistent data that's global to this module.
** This data is referenced externally by the state table definitions.
*/

union
  uic_union
    uic_group,                                /* Tempt for UIC group */
    uic_member;                               /* Tempt for UIC member */


int
  parser_flags,                               /* Keyword flags */
  entry_count,                                /* Space to preallocate */
  file_protect;                               /* Directory file protection */

struct
  dsc$descriptor_s
    device_string =                           /* Device string descriptor */
      { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) 0 };

/*
** Specify the user action routines.
**
** Please note that if it were LIB$TPARSE being called, the user action
** routines would have to be coded as follows:
**
**       int user_action_routine( __int32 psuedo_ap )
**         {
**         struct tpadef
**           *tparse_block = (tpadef *) (&psuedo_ap - 1);
**         printf( "Parameter value: %d\n",
**                 tparse_block->tpa$l_param
**                 );
**         }
*/

/*
** Shut off explicit blank processing after passing the command name.
*/

int blanks_off( struct tpadef *tparse_block ) {
  tparse_block->tpa$v_blanks = 0;
  return( 1 );
  }

/*
** Check the UIC for legal value range.
*/

int check_uic( struct tpadef *tparse_block ) {
  if ( (uic_group.words.second != 0) ||
       (uic_member.words.second != 0)
       )
    return( 0 );


  file_owner.words.first = uic_member.words.first;
  file_owner.words.second = uic_group.words.first;

  return( 1 );
  }

/*
** Store a directory name component.
*/

int store_name( struct tpadef *tparse_block ) {
  if ( (name_count >= max_name_count) ||
       (tparse_block->tpa$l_tokencnt > max_token_size)
       )
    return( 0 );

  name_vector[ name_count ].dsc$w_length = tparse_block->tpa$l_tokencnt;
  name_vector[ name_count ].dsc$b_dtype = DSC$K_DTYPE_T;
  name_vector[ name_count ].dsc$b_class = DSC$K_CLASS_S;
  name_vector[ name_count++ ].dsc$a_pointer = tparse_block->tpa$l_tokenptr;

  return( 1 );
  }

/*
** Convert a UIC into its equivalent directory file name.
*/

int make_uic( struct tpadef *tparse_block ) {

  $DESCRIPTOR( control_string, "!OB!OB" );
  $DESCRIPTOR( dirname, uic_string );

  if ( (uic_group.bytes.second != '\0') ||
       (uic_member.bytes.second != '\0')
       )
    return( 0 );

  sys$fao( &control_string,
           &dirname.dsc$w_length,
           &dirname,
           uic_group.bytes.first,
           uic_member.bytes.first
           );


  return( 1 );
  }

/*
** The main program section starts here.
*/

main( ) {

/*
** This program creates a directory. It gets the command
** line from the CLI and parses it with LIB$TABLE_PARSE.
*/

extern
  char
    ufd_state,
    ufd_key;

char
  command_buffer[ command_buffer_size + 1 ];

int
  status;

$DESCRIPTOR( prompt, "Command> " );
$DESCRIPTOR( command_descriptor, command_buffer );

struct
  tpadef
    tparse_block = { TPA$K_COUNT0,            /* Longword count */
                     TPA$M_ABBREV             /* Allow abbreviation */
                          |
                     TPA$M_BLANKS             /* Process spaces explicitly */
                     };

status = lib$get_foreign( &command_descriptor,
                          &prompt,
                          &command_descriptor.dsc$w_length
                          );

if ( (status & 1) == 0 )
  return( status );


/*
** Copy the input string descriptor into the control block
** and then call LIB$TABLE_PARSE. Note that impure storage is assumed
** to be zero.
*/

tparse_block.tpa$l_stringcnt = command_descriptor.dsc$w_length;
tparse_block.tpa$l_stringptr = command_descriptor.dsc$a_pointer;

return( status = lib$table_parse( &tparse_block, &ufd_state, &ufd_key ) );

}
      

Example 1b
The following MACRO assembly language program module defines the state tables for the preceding sample program.


   .TITLE        CREATE_DIR_TABLES - Create Directory File (tables)
        .IDENT        "X-1"

;+
;
; This module defines the state tables for the preceding
; sample program, which accepts and parses the command line of the
; CREATE/DIRECTORY command. The command line has the following format:
;
;        CREATE/DIR DEVICE:[MARANTZ.ACCOUNT.OLD]
;                /OWNER_UIC=[2437,25]
;                /ENTRIES=100
;                /PROTECTION=(SYSTEM:R,OWNER:RWED,GROUP:R,WORLD:R)
;
; The three qualifiers are optional. Alternatively, the command
; may take the form
;
;        CREATE/DIR DEVICE:[202,31]
;
; using any of the optional qualifiers.
;
;-

;+
;
; Global data, control blocks, etc.
;
;-
         .PSECT  IMPURE,WRT,NOEXE
;+
; Define control block offsets
;-

        $CLIDEF
        $TPADEF

         .EXTRN BLANKS_OFF, -            ; No explicit blank processing
                CHECK_UIC, -             ; Validate and assemble UIC
                STORE_NAME, -            ; Store next directory name
                MAKE_UIC                 ; Make UIC into directory name


;+
; Define parser flag bits for flags longword
;-

UIC_FLAG            = 1        ; /UIC seen
ENTRIES_FLAG        = 2        ; /ENTRIES seen
PROT_FLAG           = 4        ; /PROTECTION seen

        .SBTTL        Parser State Table

;+
; Assign values for protection flags to be used when parsing protection
; string.
;-

SYSTEM_READ_FLAG = ^X0001
SYSTEM_WRITE_FLAG = ^X0002
SYSTEM_EXECUTE_FLAG = ^X0004
SYSTEM_DELETE_FLAG = ^X0008
OWNER_READ_FLAG = ^X0010
OWNER_WRITE_FLAG = ^X0020
OWNER_EXECUTE_FLAG = ^X0040
OWNER_DELETE_FLAG = ^X0080
GROUP_READ_FLAG = ^X0100
GROUP_WRITE_FLAG = ^X0200
GROUP_EXECUTE_FLAG = ^X0400
GROUP_DELETE_FLAG = ^X0800
WORLD_READ_FLAG = ^X1000
WORLD_WRITE_FLAG = ^X2000
WORLD_EXECUTE_FLAG = ^X4000
WORLD_DELETE_FLAG = ^X8000

$INIT_STATE     UFD_STATE,UFD_KEY

;+
; Read over the command name (to the first blank in the command).
;-

        $STATE       START
        $TRAN        TPA$_BLANK,,BLANKS_OFF
        $TRAN        TPA$_ANY,START


;+
; Read device name string and trailing colon.
;-

        $STATE
        $TRAN        TPA$_SYMBOL,,,,DEVICE_STRING

        $STATE
        $TRAN        ':'
;+
; Read directory string, which is either a UIC string or a general
; directory string.
;-

        $STATE
        $TRAN        !UIC,,MAKE_UIC
        $TRAN        !NAME

;+
; Scan for options until end of line is reached
;-

        $STATE        OPTIONS
        $TRAN        '/'
        $TRAN        TPA$_EOS,TPA$_EXIT

        $STATE
        $TRAN        'OWNER_UIC',PARSE_UIC,,UIC_FLAG,PARSER_FLAGS
        $TRAN        'ENTRIES',PARSE_ENTRIES,,ENTRIES_FLAG,PARSER_FLAGS
        $TRAN        'PROTECTION',PARSE_PROT,,PROT_FLAG,PARSER_FLAGS

;+
; Get file owner UIC.
;-

        $STATE        PARSE_UIC
        $TRAN        ':'
        $TRAN        '='

        $STATE
        $TRAN        !UIC,OPTIONS


;+
; Get number of directory entries.
;-

        $STATE        PARSE_ENTRIES
        $TRAN        ':'
        $TRAN        '='

        $STATE
        $TRAN        TPA$_DECIMAL,OPTIONS,,,ENTRY_COUNT

;+
; Get directory file protection. Note that the bit masks generate the
; protection in complement form. It will be uncomplemented by the main
; program.
;-

        $STATE        PARSE_PROT
        $TRAN        ':'
        $TRAN        '='

        $STATE
        $TRAN        '('

        $STATE        NEXT_PRO
        $TRAN        'SYSTEM', SYPR
        $TRAN        'OWNER',  OWPR
        $TRAN        'GROUP',  GRPR
        $TRAN        'WORLD',  WOPR

        $STATE        SYPR
        $TRAN        ':'
        $TRAN        '='

        $STATE        SYPRO
        $TRAN        'R',SYPRO,,SYSTEM_READ_FLAG,FILE_PROTECT
        $TRAN        'W',SYPRO,,SYSTEM_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',SYPRO,,SYSTEM_EXECUTE_FLAG,FILE_PROTECT
        $TRAN        'D',SYPRO,,SYSTEM_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        OWPR
        $TRAN        ':'
        $TRAN        '='


        $STATE        OWPRO
        $TRAN        'R',OWPRO,,OWNER_READ_FLAG,FILE_PROTECT
        $TRAN        'W',OWPRO,,OWNER_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',OWPRO,,OWNER_EXECUTE_FLAG,FILE_PROTECT
        $TRAN        'D',OWPRO,,OWNER_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        GRPR
        $TRAN        ':'
        $TRAN        '='

        $STATE        GRPRO
        $TRAN        'R',GRPRO,,GROUP_READ_FLAG,FILE_PROTECT
        $TRAN        'W',GRPRO,,GROUP_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',GRPRO,,GROUP_EXECUTE_FLAG,FILE_PROTECT
        $TRAN        'D',GRPRO,,GROUP_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        WOPR
        $TRAN        ':'
        $TRAN        '='

        $STATE        WOPRO
        $TRAN        'R',WOPRO,,WORLD_READ_FLAG,FILE_PROTECT
        $TRAN        'W',WOPRO,,WORLD_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',WOPRO,,WORLD_EXECUTE_FLAG,FILE_PROTECT
        $TRAN        'D',WOPRO,,WORLD_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        ENDPRO
        $TRAN        <','>,NEXT_PRO
        $TRAN        ')',OPTIONS

;+
; Subexpression to parse a UIC string.
;-

        $STATE        UIC
        $TRAN        '['

        $STATE
        $TRAN        TPA$_OCTAL,,,,UIC_GROUP


        $STATE
        $TRAN        <','>        ; The comma character must be
                                  ;   surrounded by angle brackets
                                  ;   because MACRO restricts the use
                                  ;   of commas in arguments to macros.

        $STATE
        $TRAN        TPA$_OCTAL,,,,UIC_MEMBER

        $STATE
        $TRAN        ']',TPA$_EXIT,CHECK_UIC

;+
; Subexpression to parse a general directory string
;-

        $STATE        NAME
        $TRAN        '['

        $STATE        NAMEO
        $TRAN        TPA$_STRING,,STORE_NAME

        $STATE
        $TRAN        '.',NAMEO
        $TRAN        ']',TPA$_EXIT
        $END_STATE

 .END
      

Example 2
The following OpenVMS BLISS program accepts and parses the command line of a CREATE/DIRECTORY command using LIB$TPARSE.


MODULE CREATE_DIR (                        ! Create directory file
                IDENT = 'X0000',
                MAIN = CREATE_DIR) =
BEGIN

 !+
 ! This OpenVMS BLISS program accepts and parses the command line
 ! of a CREATE/DIRECTORY command.  This program uses the
 ! LIB$GET_FOREIGN call to acquire the command line from
 ! the CLI and parse it with LIB$TPARSE, leaving the necessary
 ! information in its global data base.  The command line is of
 ! the following format:
 !
 !      CREATE/DIR DEVICE:[MARANTZ.ACCOUNT.OLD]
 !                 /UIC=[2437,25]
 !                 /ENTRIES=100
 !                 /PROTECTION=(SYSTEM:R,OWNER:RWED,GROUP:R,WORLD:R)
 !
 ! The three qualifiers are optional.  Alternatively, the command
 ! may take the form
 !
 !       CREATE/DIR DEVICE:[202,31]
 !
 ! using any of the optional qualifiers.
 !-

 !+
 ! Global data, control blocks, etc.
 !-

LIBRARY 'SYS$LIBRARY:STARLET';
LIBRARY 'SYS$LIBRARY:TPAMAC.L32';

 !+
 ! Macro to make the LIB$TPARSE control block addressable as a block
 ! through the argument pointer.
 !-

MACRO
        TPARSE_ARGS =
                BUILTIN AP;
                MAP AP : REF BLOCK [,BYTE];
                %;
 !+
 ! Declare routines in this module.
 !-

FORWARD ROUTINE
        CREATE_DIR,                      ! Mail program
        BLANKS_OFF,                      ! No explicit blank processing
        CHECK_UIC,                       ! Validate and assemble UIC
        STORE_NAME,                      ! Store next directory name
        MAKE_UIC;                        ! Make UIC into directory name

 !+
 ! Define parser flag bits for flags longword.
 !-

LITERAL
        UIC_FLAG        = 0,                 ! /UIC seen
        ENTRIES_FLAG    = 1,                 ! /ENTRIES seen
        PROT_FLAG       = 2;                 ! /PROTECTION seen
OWN
 !+
 ! This is the LIB$GET_FOREIGN descriptor block to get the command line.
 !-

        COMMAND_DESC        : BLOCK [DSC$K_S_BLN, BYTE],
        COMMAND_BUFF        : VECTOR [256, BYTE],

 !+
 ! This is the LIB$TPARSE argument block.
 !-

        TPARSE_BLOCK        : BLOCK [TPA$K_LENGTH0, BYTE]
                INITIAL (TPA$K_COUNT0,     ! Longword count
                        TPA$M_ABBREV       ! Allow abbreviation
                        OR TPA$M_BLANKS),  ! Process spaces explicitly

 !+
 ! Parser global data:
 !-

        PARSER_FLAGS   : BITVECTOR [32], ! Keyword flags
        DEVICE_STRING  : VECTOR [2],     ! Device string descriptor
        ENTRY_COUNT,                     ! Space to preallocate
        FILE_PROTECT,                    ! Directory file protection
        UIC_GROUP,                       ! Temp for UIC group
        UIC_MEMBER,                      ! Temp for UIC member
        FILE_OWNER,                      ! Actual file owner UIC
        NAME_COUNT,                      ! Number of directory names
        UIC_STRING     : VECTOR [6, BYTE],   ! Buffer for string

        NAME_VECTOR    : BLOCKVECTOR [0, 2], ! Vector of descriptors

        DIRNAME1        : VECTOR [2],         ! Name descriptor 1
        DIRNAME2        : VECTOR [2],         ! Name descriptor 2
        DIRNAME3        : VECTOR [2],         ! Name descriptor 3
        DIRNAME4        : VECTOR [2],         ! Name descriptor 4
        DIRNAME5        : VECTOR [2],         ! Name descriptor 5
        DIRNAME6        : VECTOR [2],         ! Name descriptor 6
        DIRNAME7        : VECTOR [2],         ! Name descriptor 7
        DIRNAME8        : VECTOR [2];         ! Name descriptor 8

 !+
 ! Structure macro to reference the descriptor fields in the vector of
 ! descriptors.
 !-

MACRO
        STRING_COUNT       = 0, 0, 32, 0%,         ! Count field
        STRING_ADDR        = 1, 0, 32, 0%;         ! Address field

 !+
 ! LIB$TPARSE state table to parse the command line
 !-

$INIT_STATE        (UFD_STATE, UFD_KEY);

 !+
 ! Read over the command name (to the first blank in the command).
 !-

$STATE  (START,
        (TPA$_BLANK, , BLANKS_OFF),
        (TPA$_ANY, START)
        );
 !+
 ! Read device name string and trailing colon.
 !-

$STATE  (,
        (TPA$_SYMBOL,,,, DEVICE_STRING)
        );

$STATE  (,
        (':')
        );


 !+
 ! Read directory string, which is either a UIC string or a general
 ! directory string.
 !-

$STATE  (,
        ((UIC),, MAKE_UIC),
        ((NAME))
        );

 !+
 ! Scan for options until end of line is reached.
 !-

$STATE  (OPTIONS,
        ('/'),
        (TPA$_EOS, TPA$_EXIT)
        );

$STATE  (,
        ('UIC', PARSE_UIC,, 1^UIC_FLAG, PARSER_FLAGS),
        ('ENTRIES', PARSE_ENTRIES,, 1^ENTRIES_FLAG, PARSER_FLAGS),
        ('PROTECTION', PARSE_PROT,, 1^PROT_FLAG, PARSER_FLAGS)
        );

 !+
 ! Get file owner UIC.
 !-

$STATE  (PARSE_UIC,
        (':'),
        ('=')
        );

$STATE  (,
        ((UIC), OPTIONS)
        );
 !+
 ! Get number of directory entries.
 !-

$STATE  (PARSE_ENTRIES,
        (':'),
        ('=')

        );

$STATE  (,
        (TPA$_DECIMAL, OPTIONS,,, ENTRY_COUNT)
        );

 !+
 ! Get directory file protection. Note that the bit masks generate the
 ! protection in complement form. It will be uncomplemented by the main
 ! program.
 !-

$STATE  (PARSE_PROT,
        (':'),
        ('=')
        );

$STATE  (,
        ('(')
        );

$STATE  (NEXT_PRO,
        ('SYSTEM', SYPR),
        ('OWNER',  OWPR),
        ('GROUP',  GRPR),
        ('WORLD',  WOPR)
        );

$STATE  (SYPR,
        (':'),
        ('=')
        );

$STATE  (SYPR0,
        ('R', SYPR0,, %X'0001', FILE_PROTECT),
        ('W', SYPR0,, %X'0002', FILE_PROTECT),
        ('E', SYPR0,, %X'0004', FILE_PROTECT),
        ('D', SYPR0,, %X'0008', FILE_PROTECT),
        (TPA$_LAMBDA, ENDPRO)
        );

$STATE  (OWPR,
        (':'),
        ('=')
        );


$STATE  (OWPR0,
        ('R', OWPR0,, %X'0010', FILE_PROTECT),
        ('W', OWPR0,, %X'0020', FILE_PROTECT),
        ('E', OWPR0,, %X'0040', FILE_PROTECT),
        ('D', OWPR0,, %X'0080', FILE_PROTECT),
        (TPA$_LAMBDA, ENDPRO)
        );

$STATE  (GRPR,
        (':'),
        ('=')
        );

$STATE  (GRPR0,
        ('R', GRPR0,, %X'0100', FILE_PROTECT),
        ('W', GRPR0,, %X'0200', FILE_PROTECT),
        ('E', GRPR0,, %X'0400', FILE_PROTECT),
        ('D', GRPR0,, %X'0800', FILE_PROTECT),
        (TPA$_LAMBDA, ENDPRO)
        );

$STATE  (WOPR,
        (':'),
        ('=')
        );

$STATE  (WOPR0,
        ('R', WOPR0,, %X'1000', FILE_PROTECT),
        ('W', WOPR0,, %X'2000', FILE_PROTECT),
        ('E', WOPR0,, %X'4000', FILE_PROTECT),
        ('D', WOPR0,, %X'8000', FILE_PROTECT),
        (TPA$_LAMBDA, ENDPRO)
        );

$STATE  (ENDPRO,
        (', ', NEXT_PRO),
        (')', OPTIONS)
        );

 !+
 ! Subexpression to parse a UIC string.
 !-

$STATE  (UIC,

        ('[')
        );

$STATE  (,
        (TPA$_OCTAL,,,, UIC_GROUP)
        );

$STATE  (,
        (', ')
        );

$STATE  (,
        (TPA$_OCTAL,,,, UIC_MEMBER)
        );

$STATE  (,
        (']', TPA$_EXIT, CHECK_UIC)
        );

 !+
 ! Subexpression to parse a general directory string
 !-

$STATE  (NAME,
        ('[')
        );

$STATE  (NAME0,
        (TPA$_STRING,, STORE_NAME)
        );

$STATE  (,
        ('.', NAME0),
        (']', TPA$_EXIT)
        );
PSECT OWN = $OWN$;
PSECT GLOBAL = $GLOBAL$;


GLOBAL ROUTINE CREATE_DIR (START_ADDR, CLI_CALLBACK) =

BEGIN

 !+
 ! This program creates a directory. It gets the command

 ! line from the CLI and parses it with LIB$TPARSE.
 !-

LOCAL
        STATUS,                 ! Status from LIB$TPARSE
        OUT_LEN  : WORD;        ! length of returned command line
EXTERNAL
        SS$_NORMAL;

EXTERNAL ROUTINE
        LIB$GET_FOREIGN   : ADDRESSING_MODE (GENERAL),
        LIB$TPARSE        : ADDRESSING_MODE (GENERAL);

                COMMAND_DESC [DSC$W_LENGTH]  = 256;
                COMMAND_DESC [DSC$B_DTYPE]   = DSC$K_DTYPE_T;
                COMMAND_DESC [DSC$B_CLASS]   = DSC$K_CLASS_S;
                COMMAND_DESC [DSC$A_POINTER] = COMMAND_BUFF;


        STATUS = LIB$GET_FOREIGN (COMMAND_DESC,
                                %ASCID'COMMAND: ',
                                OUT_LEN
                                );
        IF NOT .STATUS
                THEN
                SIGNAL (STATUS);


 !+
 ! Copy the input string descriptor into the LIB$TPARSE control block
 ! and call LIB$TPARSE. Note that impure storage is assumed to be zero.
 !-


TPARSE_BLOCK[TPA$L_STRINGCNT] = .OUT_LEN;
TPARSE_BLOCK[TPA$L_STRINGPTR] = .COMMAND_DESC[DSC$A_POINTER];

STATUS = LIB$TPARSE (TPARSE_BLOCK, UFD_STATE, UFD_KEY);
IF NOT .STATUS
THEN
        RETURN 0;
RETURN SS$_NORMAL
END;                                         ! End of routine CREATE_DIR

 !+

 ! Parser action routines
 !-

 !+
 ! Shut off explicit blank processing after passing the command name.
 !-

ROUTINE BLANKS_OFF =
    BEGIN
    TPARSE_ARGS;

    AP[TPA$V_BLANKS] = 0;
    1
    END;

 !+
 ! Check the UIC for legal value range.
 !-

ROUTINE CHECK_UIC =
    BEGIN
    TPARSE_ARGS;

    IF .UIC_GROUP<16,16> NEQ 0
    OR .UIC_MEMBER<16,16> NEQ 0
    THEN RETURN 0;

    FILE_OWNER<0,16> = .UIC_MEMBER;
    FILE_OWNER<16,16> = .UIC_GROUP;
    1
    END;

 !+
 ! Store a directory name component.
 !-

ROUTINE STORE_NAME =
    BEGIN
    TPARSE_ARGS;

    IF .NAME_COUNT GEQU 8
    OR .AP[TPA$L_TOKENCNT] GTRU 9
    THEN RETURN 0;
    NAME_COUNT = .NAME_COUNT + 1;
    NAME_VECTOR [.NAME_COUNT, STRING_COUNT] = .AP[TPA$L_TOKENCNT];

    NAME_VECTOR [.NAME_COUNT, STRING_ADDR] = .AP[TPA$L_TOKENPTR];
    1
    END;

 !+
 ! Convert a UIC into its equivalent directory file name.
 !-

ROUTINE MAKE_UIC =
    BEGIN
    TPARSE_ARGS;

    IF .UIC_GROUP<8,8> NEQ 0
    OR .UIC_MEMBER<8,8> NEQ 0
    THEN RETURN 0;
    DIRNAME1[0] = 0;
    DIRNAME1[1] = UIC_STRING;
    $FAOL (CTRSTR = UPLIT (6, UPLIT BYTE ('!OB!OB')),
           OUTBUF = DIRNAME1,
           PRMLST = UIC_GROUP
           );
    1
    END;
END
ELUDOM                               ! End of module CREATE_DIR
      

Example 3
The following MACRO assembly language program accepts and parses the command line of a CREATE/DIRECTORY command using LIB$TPARSE. It also defines the state table for the parser.


    .TITLE        CREATE_DIR - Create Directory File
         .IDENT        "X0000"
;+
;
; This is a sample OpenVMS MACRO program that accepts and parses the command
; line of the CREATE/DIRECTORY command. This program contains the OpenVMS
; call to acquire the command line from the command interpreter
; and parse it with LIB$TPARSE, leaving the necessary information in
; its global data base. The command line has the following format:
;
;        CREATE/DIR DEVICE:[MARANTZ.ACCOUNT.OLD]
;                /OWNER_UIC=[2437,25]
;                /ENTRIES=100
;                /PROTECTION=(SYSTEM:R,OWNER:RWED,GROUP:R,WORLD:R)
;

; The three qualifiers are optional. Alternatively, the command
; may take the form
;
;        CREATE/DIR DEVICE:[202,31]
;
; using any of the optional qualifiers.
;
;-

;+
;
; Global data, control blocks, etc.
;
;-
         .PSECT  IMPURE,WRT,NOEXE
;+
; Define control block offsets
;-
        $CLIDEF
        $TPADEF
;+
; Define parser flag bits for flags longword
;-

UIC_FLAG            = 1        ; /UIC seen
ENTRIES_FLAG        = 2        ; /ENTRIES seen
PROT_FLAG           = 4        ; /PROTECTION seen

;+
; LIB$GET_FOREIGN string descriptors to get the line to be parsed
;-

STRING_LEN = 256
STRING_DESC:
        .WORD STRING_LEN
        .BYTE DSC$K_DTYPE_T
        .BYTE DSC$K_CLASS_S
        .ADDRESS STRING_AREA
STRING_AREA:
        .BLKB STRING_LEN
PROMPT_DESC:
        .WORD PROMPT_LEN
        .BYTE DSC$K_DTYPE_T
        .BYTE DSC$K_CLASS_S
        .ADDRESS PROMPT

PROMPT:
        .ASCII /qualifiers: /
PROMPT_LEN = .-PROMPT


;+
; TPARSE argument block
;-

TPARSE_BLOCK:
         .LONG        TPA$K_COUNT0          ; Longword count
         .LONG        TPA$M_ABBREV!-        ; Allow abbreviation
                      TPA$M_BLANKS          ; Process spaces explicitly
         .BLKB        TPA$K_LENGTH0-8       ; Remainder set at run time
;+
; Parser global data
;-

RET_LEN:              .BLKW        1        ; LENGTH OF RETURNED COMMAND LINE
PARSER_FLAGS:         .BLKL        1        ; Keyword flags
DEVICE_STRING:        .BLKL        2        ; Device string descriptor
ENTRY_COUNT:          .BLKL        1        ; Space to preallocate
FILE_PROTECT:         .BLKL        1        ; Directory file protection
UIC_GROUP:            .BLKL        1        ; Temp for UIC group
UIC_MEMBER:           .BLKL        1        ; Temp for UIC member
UIC_STRING:           .BLKB        6        ; String to receive converted UIC
FILE_OWNER:           .BLKL        1        ; Actual file owner UIC
NAME_COUNT:           .BLKL        1        ; Number of directory names
DIRNAME1:             .BLKL        2        ; Name descriptor 1
DIRNAME2:             .BLKL        2        ; Name descriptor 2
DIRNAME3:             .BLKL        2        ; Name descriptor 3
DIRNAME4:             .BLKL        2        ; Name descriptor 4
DIRNAME5:             .BLKL        2        ; Name descriptor 5
DIRNAME6:             .BLKL        2        ; Name descriptor 6
DIRNAME7:             .BLKL        2        ; Name descriptor 7
DIRNAME8:             .BLKL        2        ; Name descriptor 8

         .SBTTL Main Program
;+
; This program gets the CREATE/DIRECTORY command line from
; the command interpreter and parses it.
;-
         .PSECT  CODE,EXE,NOWRT
CREATE_DIR::
         .WORD   ^M<R2,R3,R4,R5>        ; Save registers

;+
; Call the command interpreter to obtain the command line.
;-
        PUSHAW  RET_LEN
        PUSHAQ  PROMPT_DESC
        PUSHAQ  STRING_DESC
        CALLS   #3,G^LIB$GET_FOREIGN    ; Call to get command line
        BLBC    R0, SYNTAX_ERR

;+
; Copy the input string descriptor into the TPARSE control block
; and call LIB$TPARSE.  Note that impure storage is assumed to be zero.
;-
        MOVZWL        RET_LEN, TPARSE_BLOCK+TPA$L_STRINGCNT
        MOVAL         STRING_AREA, TPARSE_BLOCK+TPA$L_STRINGPTR
        PUSHAL        UFD_KEY
        PUSHAL        UFD_STATE
        PUSHAL        TPARSE_BLOCK
        CALLS         #3,G^LIB$TPARSE
        BLBC          R0,SYNTAX_ERR

;+
; Parsing is complete.
;
; You can include here code to process the string just parsed, to call
; another program to process the command, or to return control to
; a calling program, if any.
;-

SYNTAX_ERR:

;+
; Code to handle parsing errors.
;-

        RET

        .SBTTL        Parser State Table

;+
; Assign values for protection flags to be used when parsing protection
; string.
;-

SYSTEM_READ_FLAG = ^X0001
SYSTEM_WRITE_FLAG = ^X0002
SYSTEM_EXECUTE_FLAG = ^X0004
SYSTEM_DELETE_FLAG = ^X0008
OWNER_READ_FLAG = ^X0010
OWNER_WRITE_FLAG = ^X0020
OWNER_EXECUTE_FLAG = ^X0040
OWNER_DELETE_FLAG = ^X0080
GROUP_READ_FLAG = ^X0100
GROUP_WRITE_FLAG = ^X0200
GROUP_EXECUTE_FLAG = ^X0400
GROUP_DELETE_FLAG = ^X0800
WORLD_READ_FLAG = ^X1000
WORLD_WRITE_FLAG = ^X2000
WORLD_EXECUTE_FLAG = ^X4000
WORLD_DELETE_FLAG = ^X8000


$INIT_STATE     UFD_STATE,UFD_KEY

;+
; Read over the command name (to the first blank in the command).
;-
        $STATE       START
        $TRAN        TPA$_BLANK,,BLANKS_OFF
        $TRAN        TPA$_ANY,START
;+
; Read device name string and trailing colon.
;-
        $STATE
        $TRAN        TPA$_SYMBOL,,,,DEVICE_STRING

        $STATE
        $TRAN        ':'
;+
; Read directory string, which is either a UIC string or a general
; directory string.
;-
        $STATE
        $TRAN        !UIC,,MAKE_UIC
        $TRAN        !NAME

;+
; Scan for options until end of line is reached
;-

        $STATE        OPTIONS
        $TRAN        '/'
        $TRAN        TPA$_EOS,TPA$_EXIT

        $STATE
        $TRAN        'OWNER_UIC',PARSE_UIC,,UIC_FLAG,PARSER_FLAGS
        $TRAN        'ENTRIES',PARSE_ENTRIES,,ENTRIES_FLAG,PARSER_FLAGS
        $TRAN        'PROTECTION',PARSE_PROT,,PROT_FLAG,PARSER_FLAGS

;+
; Get file owner UIC.
;-
        $STATE        PARSE_UIC
        $TRAN        ':'
        $TRAN        '='

        $STATE
        $TRAN        !UIC,OPTIONS

;+
; Get number of directory entries.
;-

        $STATE        PARSE_ENTRIES
        $TRAN        ':'
        $TRAN        '='

        $STATE
        $TRAN        TPA$_DECIMAL,OPTIONS,,,ENTRY_COUNT

;+
; Get directory file protection. Note that the bit masks generate the
; protection in complement form. It will be uncomplemented by the main
; program.
;-

        $STATE        PARSE_PROT
        $TRAN        ':'
        $TRAN        '='

        $STATE
        $TRAN        '('

        $STATE        NEXT_PRO
        $TRAN        'SYSTEM', SYPR

        $TRAN        'OWNER',  OWPR
        $TRAN        'GROUP',  GRPR
        $TRAN        'WORLD',  WOPR

        $STATE        SYPR
        $TRAN        ':'
        $TRAN        '='

        $STATE        SYPRO
        $TRAN        'R',SYPRO,,SYSTEM_READ_FLAG,FILE_PROTECT
        $TRAN        'W',SYPRO,,SYSTEM_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',SYPRO,,SYSTEM_EXECUTE_FLAG,FILE_PROTECT
        $TRAN        'D',SYPRO,,SYSTEM_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        OWPR
        $TRAN        ':'
        $TRAN        '='

        $STATE        OWPRO
        $TRAN        'R',OWPRO,,OWNER_READ_FLAG,FILE_PROTECT
        $TRAN        'W',OWPRO,,OWNER_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',OWPRO,,OWNER_EXECUTE_FLAG,FILE_PROTECT
        $TRAN        'D',OWPRO,,OWNER_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        GRPR
        $TRAN        ':'
        $TRAN        '='

        $STATE        GRPRO
        $TRAN        'R',GRPRO,,GROUP_READ_FLAG,FILE_PROTECT
        $TRAN        'W',GRPRO,,GROUP_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',GRPRO,,GROUP_EXECUTE_FLAG,FILE_PROTECT
        $TRAN        'D',GRPRO,,GROUP_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        WOPR
        $TRAN        ':'
        $TRAN        '='

        $STATE        WOPRO
        $TRAN        'R',WOPRO,,WORLD_READ_FLAG,FILE_PROTECT
        $TRAN        'W',WOPRO,,WORLD_WRITE_FLAG,FILE_PROTECT
        $TRAN        'E',WOPRO,,WORLD_EXECUTE_FLAG,FILE_PROTECT

        $TRAN        'D',WOPRO,,WORLD_DELETE_FLAG,FILE_PROTECT
        $TRAN        TPA$_LAMBDA,ENDPRO

        $STATE        ENDPRO
        $TRAN        <','>,NEXT_PRO
        $TRAN        ')',OPTIONS

;+
; Subexpression to parse a UIC string.
;-

        $STATE        UIC
        $TRAN        '['

        $STATE
        $TRAN        TPA$_OCTAL,,,,UIC_GROUP

        $STATE
        $TRAN        <','>        ; The comma character must be
                                  ;   surrounded by angle brackets
                                  ;   because MACRO restricts the use
                                  ;   of commas in arguments to macros.

        $STATE
        $TRAN        TPA$_OCTAL,,,,UIC_MEMBER

        $STATE
        $TRAN        ']',TPA$_EXIT,CHECK_UIC

;+
; Subexpression to parse a general directory string
;-
        $STATE        NAME
        $TRAN        '['

        $STATE        NAMEO
        $TRAN        TPA$_STRING,,STORE_NAME

        $STATE
        $TRAN        '.',NAMEO
        $TRAN        ']',TPA$_EXIT
        $END_STATE

        .SBTTL        Parser Action Routines
        .PSECT        CODE,EXE,NOWRT


;+
; Shut off explicit blank processing after passing the command name.
;-

BLANKS_OFF:
        .WORD        0                      ; No registers saved (or used)
        BBCC         #TPA$V_BLANKS,TPA$L_OPTIONS(AP),10$
10$:    RET

;+
; Check the UIC for legal value range.
;-

CHECK_UIC:
        .WORD       0                       ; No registers saved (or used)
        TSTW        UIC_GROUP+2             ; UIC components are 16 bits
        BNEQ        10$
        TSTW        UIC_MEMBER+2
        BNEQ        10$
        MOVW        UIC_GROUP,FILE_OWNER+2  ; Store actual UIC
        MOVW        UIC_MEMBER,FILE_OWNER   ;  after checking
        RET
10$:    CLRL        R0                      ; Value out of range - fail
        RET                                 ;  the transition

;+
; Store a directory name component.
;-

STORE_NAME:
        .WORD       0                       ; No registers saved (or used)
        MOVL        NAME_COUNT,R1           ; Get count of names so far
        CMPL        R1,#8                   ; Maximum of 8 permitted
        BGEQU       10$
        INCL        NAME_COUNT              ; Count this name
        MOVAQ       DIRNAME1[R1],R1         ; Address of next descriptor
        MOVQ        TPA$L_TOKENCNT(AP),(R1) ; Store the descriptor
        CMPL        (R1),#9                 ; Check the length of the name
        BGTRU       10$                     ; Maximum is 9
        RET
10$:    CLRL        R0                      ; Error in directory name
        RET

;+

; Convert a UIC into its equivalent directory file name.
;-

MAKE_UIC:
        .WORD       0                        ; No registers saved (or used)
        TSTB        UIC_GROUP+1              ; Check UIC for byte values,
        BNEQ        10$                      ;  because UIC type directories
        TSTB        UIC_MEMBER+1             ;  are restricted to this form
        BNEQ        10$
        MOVL        #6,DIRNAME1              ; Directory name is 6 bytes
        MOVAL       UIC_STRING,DIRNAME1+4    ; Point to string buffer
        $FAOL       CTRSTR=FAO_STRING,-      ; Convert UIC to octal string
                    OUTBUF=DIRNAME1,-
                    PRMLST=UIC_GROUP
        RET
10$:    CLRL        R0                       ; Range error - fail it
        RET
FAO_STRING:        .LONG       STRING_END-STRING_START
STRING_START:      .ASCII  '!OB!OB'
STRING_END:



         .END        CREATE_DIR
      


Previous Next Contents Index