Document revision date: 30 March 2001

## OpenVMS RTL Library (LIB$) Manual

Previous | Contents | Index

4 Data Representation
This section describes the binary representation and allocation of a LIB$T[ABLE_]PARSE state table and a keyword table. While this information is not required to use LIB$T[ABLE_]PARSE, it may be useful in debugging your program.

4.1 State Table Representation
Each state consists of its transitions concatenated in memory. LIB$T[ABLE_]PARSE equates the state label to the address of the first byte of the first transition. A marker in the last transition identifies the end of the state. The LIB$T[ABLE_]PARSE table macros build the state table in the PSECT _LIB$STATE$.

Each transition in a state consists of 2 to 23 bytes containing the arguments of the transition. The state table generation macros do not allocate storage for arguments not specified in the transition macro. This allows simple transitions to be represented efficiently. For example, the following transition, which simply accepts the character "?" and falls through to the next state, is represented in two bytes:

$TRAN '?'

In this section, pointers described as self-relative are signed displacements from the address following the end of the pointer (this is identical to branch displacements in the OpenVMS VAX instruction set).

Table lib-12 describes the elements of a state transition in the order in which they appear, if present, in the transition. If a transition does not include a specific option, no bytes are assigned to the option within the transition.

Table lib-12 Binary Representation of a LIB$T [ABLE_]PARSE State Transition
Transition Element | No. of Bytes | Description
--- | --- | ---
Symbol type | 1 | The first byte of a transition always contains the binary coding of the symbol type accepted by this transition. Flag bit 0 in the flags byte controls the interpretation of the type byte. If the flag is clear, the type byte represents a single character (the ' x' construct). If the flag bit is set, the type byte is one of the other type codes (keyword, number, and so on). The following table lists the symbol types accepted by LIB$T[ABLE_]PARSE:
Symbol Type | Binary Encoding
--- | ---
' x' | ASCII code of the character (8 bits)
' keyword' | The keyword index (0 to 219)
TPA$_DECIMAL_64 (Alpha only) | 228
TPA$_OCTAL_64 (Alpha only) | 229
TPA$_HEX_64 (Alpha only) | 230
TPA$_NODE_ACS | 231
TPA$_NODE_PRIMARY | 232
TPA$_NODE | 233
TPA$_FILESPEC | 234
TPA$_UIC | 235
TPA$_IDENT | 236
TPA$_ANY | 237
TPA$_ALPHA | 238
TPA$_DIGIT | 239
TPA$_STRING | 240
TPA$_SYMBOL | 241
TPA$_BLANK | 242
TPA$_DECIMAL | 243
TPA$_OCTAL | 244
TPA$_HEX | 245
TPA$_LAMBDA | 246
TPA$_EOS | 247
TPA$_SUBEXPR | 248 (subexpression call)
| (Other codes are reserved for expansion)
|  | Use of the TPA$_FILESPEC, TPA$_NODE, TPA$_NODE_PRIMARY, or TPA$_NODE_ACS symbol type results in calls to the $FILESCAN system service. Use of the symbol type TPA$_IDENT results in calls to the $ASCTOID system service. If your application of LIB$T[ABLE_]PARSE runs in an environment other than OpenVMS user mode, you must carefully evaluate whether use of these services is consistent with your environment.
First flags byte | 1 | This byte contains the following bits, which specify the options of the transition. It is always present.
Bit | Description
--- | ---
0 | Set if the type byte is not a single character.
1 | Set if the second flags byte is present.
2 | Set if this is the last transition in the state.
3 | Set if a subexpression pointer is present.
4 | Set if an explicit target state is present.
5 | Set if the mask longword is present.
6 | Set if the msk-adr longword is present.
7 | Set if an action routine address is present.
Second flags byte | 1 | This byte is present if any of its flag bits is set. It contains an additional flag describing the transition. It is used as follows:
Bit | Description
--- | ---
0 | Set if the action routine argument is present.
Subexpression pointer | 2 | This word is present in transitions that are subexpression calls. It is a 16-bit signed self-relative pointer to the starting state of the subexpression.
Argument longword | 4 | This longword field contains the 32-bit action routine argument, when specified.
Action routine address | 4 | This longword contains a self-relative pointer to the action routine, when specified.
Bit mask | 4 | This longword contains the mask argument, when specified.
Mask address | 4 | This longword, when specified, contains a self-relative pointer through which the mask, or data that depends on the symbol type, is to be stored. Because the pointer is self-relative, when it points to an absolute location, the state table is not PIC (position-independent code).
Transition target | 2 | This word, when specified, contains the address of the target state of the transition. The address is stored as a 16-bit signed self-relative pointer. The final state TPA$_EXIT is coded as a word whose value is --1; the failure state TPA$_FAIL is coded as a word whose value is --2.

4.2 Keyword Table Representation
The keyword table is a vector of 16-bit signed pointers that address locations in the keyword string area, relative to the start of the keyword vector. It is the structure to which the $INIT_STATE macro equates its second argument.

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

> Previous | Next | Contents | Index

> | privacy and legal statement |
> 5932PRO_048.HTML