 |
HP OpenVMS Programming Concepts Manual
24.7.2 Create a Directory or Subdirectory
The LIB$CREATE_DIR routine creates a directory or a subdirectory. The
calling program must specify the directory specification in standard
OpenVMS RMS format. This directory specification may also contain a
disk specification.
In addition to the required directory specification argument,
LIB$CREATE_DIR takes the following five optional arguments:
- The user identification code (UIC) of the owner of the created
directory or subdirectory
- The protection enable mask
- The protection value mask
- The maximum number of versions allowed for files created in this
directory or subdirectory
- The relative volume number within the volume set on which the
directory or subdirectory is created
See the HP OpenVMS RTL Library (LIB$) Manual for a complete description of LIB$CREATE_DIR.
24.7.3 File Searching Routines
The run-time library provides two routines that your program can call
to search for a file and two routines that your program can call to end
a search sequence:
- When you call LIB$FILE_SCAN with a wildcard file specification and
an action routine, the routine calls the action routine for each file
or error, or both, found in the wildcard sequence. LIB$FILE_SCAN allows
the search sequence to continue even though certain errors are present.
- When you call LIB$FIND_FILE with a wildcard file specification, it
finds the next file specification that matches the wildcard
specification.
In addition to the wildcard file specification, which is a required
argument, LIB$FIND_FILE takes the following four optional arguments:
- The default specification.
- The related specification.
- The OpenVMS RMS secondary status value from a failing RMS operation.
- A longword containing two flag bits. If bit 1 is set, LIB$FIND_FILE
performs temporary defaulting for multiple input files and the related
specification argument is ignored. See the HP OpenVMS RTL Library (LIB$) Manual for a complete
description of LIB$FIND_FILE in template format.
The LIB$FIND_FILE_END routine is called once after each call to
LIB$FIND_FILE in interactive use. LIB$FIND_FILE_END prevents the
temporary default values retained by the previous call to LIB$FIND_FILE
from affecting the next file specification.
The LIB$FILE_SCAN routine uses an optional context argument to perform
temporary defaulting for multiple input files. For example, a command
such as the following would specify A, B, and C in successive calls,
retaining context, so that portions of one file specification would
affect the next file specification:
The LIB$FILE_SCAN_END routine is called once after each sequence of
calls to LIB$FILE_SCAN. LIB$FILE_SCAN_END performs a parse of the null
string to deallocate saved OpenVMS RMS context and to prevent the
temporary default values retained by the previous call to LIB$FILE_SCAN
from affecting the next file specification. For instance, in the
previous example, LIB$FILE_SCAN_END should be called after the C file
specification is parsed, so that specifications from the $COPY files do
not affect file specifications in subsequent commands.
The following BLISS example illustrates the use of LIB$FIND_FILE. It
prompts for a file specification and default specification. The default
specification indicates the default information for the file for which
you are searching. Once the routine has searched for one file, the
resulting file specification determines both the related file
specification and the default file specification for the next search.
LIB$FIND_FILE_END is called at the end of the following BLISS program
to deallocate the virtual memory used by LIB$FIND_FILE.
%TITLE 'FILE_EXAMPLE1 - Sample program using LIB$FIND_FILE'
MODULE FILE_EXAMPLE1( ! Sample program using LIB$FIND_FILE
IDENT = '1-001',
MAIN = EXAMPLE_START
) =
BEGIN
%SBTTL 'Declarations'
!+
! SWITCHES:
!-
SWITCHES ADDRESSING_MODE (EXTERNAL = GENERAL, NONEXTERNAL = WORD_RELATIVE);
!+
! TABLE OF CONTENTS:
!-
FORWARD ROUTINE
EXAMPLE_START; ! Main program
!+
! INCLUDE FILES:
!-
LIBRARY 'SYS$LIBRARY:STARLET.L32'; ! System symbols
!+
! Define facility-specific messages from shared system messages.
!-
$SHR_MSGDEF(CLI,3,LOCAL,
(PARSEFAIL,WARNING));
!+
! EXTERNAL REFERENCES:
!-
EXTERNAL ROUTINE
LIB$GET_INPUT, ! Read from SYS$INPUT
LIB$FIND_FILE, ! Wildcard scanning routine
LIB$FIND_FILE_END, ! End find file
LIB$PUT_OUTPUT, ! Write to SYS$OUTPUT
STR$COPY_DX; ! String copier
LITERAL
TRUE = 1, ! Success
FALSE = 0; ! Failure
%SBTTL 'EXAMPLE_START - Sample program main routine';
ROUTINE EXAMPLE_START =
BEGIN
!+
! This program reads a file specification and default file
! specification from SYS$INPUT. It then prints all the files that
! match that specification and prompts for another file specification.
! After the first file specification no default specification is requested,
! and the previous resulting file specification becomes the related
! file specification.
!-
LOCAL
LINEDESC : $BBLOCK[DSC$C_S_BLN], ! String desc. for input line
RESULT_DESC : $BBLOCK[DSC$C_S_BLN], ! String desc. for result file
CONTEXT, ! LIB$FIND_FILE context pointer
DEFAULT_DESC : $BBLOCK[DSC$C_S_BLN], ! String desc. for default spec
RELATED_DESC : $BBLOCK[DSC$C_S_BLN], ! String desc. for related spec
HAVE_DEFAULT,
STATUS;
!+
! Make all string descriptors dynamic.
!-
CH$FILL(0,DSC$C_S_BLN,LINEDESC);
LINEDESC[DSC$B_CLASS] = DSC$K_CLASS_D;
CH$MOVE(DSC$C_S_BLN,LINEDESC,RESULT_DESC);
CH$MOVE(DSC$C_S_BLN,LINEDESC,DEFAULT_DESC);
CH$MOVE(DSC$C_S_BLN,LINEDESC,RELATED_DESC);
HAVE_DEFAULT = FALSE;
CONTEXT = 0;
!+
! Read file specification, default file specification, and
! related file specification.
!-
WHILE (STATUS = LIB$GET_INPUT(LINEDESC,
$DESCRIPTOR('FILE SPECIFICATION: '))) NEQ RMS$_EOF
DO BEGIN
IF NOT .STATUS
THEN SIGNAL_STOP(.STATUS);
!+
! If default file specification was not obtained, do so now.
!-
IF NOT .HAVE_DEFAULT
THEN BEGIN
STATUS = LIB$GET_INPUT(DEFAULT_DESC,
$DESCRIPTOR('DEFAULT FILE SPECIFICATION: '));
IF NOT .STATUS
THEN SIGNAL_STOP(.STATUS);
HAVE_DEFAULT = TRUE;
END;
!+
! CALL LIB$FIND_FILE until RMS$_NMF (no more files) is returned.
! If an error other than RMS$_NMF is returned, it is signaled.
! Print out the file specification if the call is successful.
!-
WHILE (STATUS = LIB$FIND_FILE(LINEDESC,RESULT_DESC,CONTEXT,
DEFAULT_DESC,RELATED_DESC)) NEQ RMS$_NMF
DO IF NOT .STATUS
THEN SIGNAL(CLI$_PARSEFAIL,1,RESULT_DESC,.STATUS)
ELSE LIB$PUT_OUTPUT(RESULT_DESC);
!+
! Make this resultant file specification the related file
! specification for next file.
!-
STR$COPY_DX(RELATED_DESC,LINEDESC);
END; ! End of loop
! reading file specification
!+
! Call LIB$FIND_FILE_END to deallocate the virtual memory used by LIB$FIND_FILE.
! Note that we do this outside of the loop. Since the MULTIPLE bit of the
! optional user flags argument to LIB$FIND_FILE wasn't used, it is not
! necessary to call LIB$FIND_FILE_END after each call to LIB$FIND_FILE.
! (The MULTIPLE bit would have caused temporary defaulting for multiple input
! files.)
!-
STATUS = LIB$FIND_FILE_END (CONTEXT);
IF NOT .STATUS
THEN SIGNAL_STOP (.STATUS);
RETURN TRUE
END; ! End of main program
END ! End of module
ELUDOM
|
The following BLISS example illustrates the use of LIB$FILE_SCAN and
LIB$FILE_SCAN_END.
%TITLE 'FILE_EXAMPLE2 - Sample program using LIB$FILE_SCAN'
MODULE FILE_EXAMPLE1( ! Sample program using LIB$FILE_SCAN
IDENT = '1-001',
MAIN = EXAMPLE_START
) =
BEGIN
%SBTTL 'Declarations'
!+
! SWITCHES:
!-
SWITCHES ADDRESSING_MODE (EXTERNAL = GENERAL,
NONEXTERNAL = WORD_RELATIVE);
!+
! TABLE OF CONTENTS:
!-
FORWARD ROUTINE
EXAMPLE_START, ! Main program
SUCCESS_RTN, ! Success action routine
ERROR_RTN; ! Error action routine
!+
! INCLUDE FILES:
!-
LIBRARY 'SYS$LIBRARY:STARLET.L32'; ! System symbols
!+
! Define VMS block structures (BLOCK[,BYTE]).
!-
STRUCTURE
BBLOCK [O, P, S, E; N] =
[N]
(BBLOCK + O) <P, S, E>;
!+
! EXTERNAL REFERENCES:
!-
EXTERNAL ROUTINE
LIB$GET_INPUT, ! Read from SYS$INPUT
LIB$FILE_SCAN, ! Wildcard scanning routine
LIB$FILE_SCAN_END, ! End of file scan
LIB$PUT_OUTPUT; ! Write to SYS$OUTPUT
%SBTTL 'EXAMPLE_START - Sample program main routine';
ROUTINE EXAMPLE_START =
BEGIN
!+
! This program reads the file specification, default file specification,
! and related file specification from SYS$INPUT and then displays on
! SYS$OUTPUT all files which match the specification.
!-
LOCAL
RESULT_BUFFER : VECTOR[NAM$C_MAXRSS,BYTE], !Buffer for resultant
! name string
EXPAND_BUFFER : VECTOR[NAM$C_MAXRSS,BYTE], !Buffer for expanded
! name string
LINEDESC : BBLOCK[DSC$C_S_BLN], !String descriptor
! for input line
RESULT_DESC : BBLOCK[DSC$C_S_BLN], !String descriptor
! for result file
DEFAULT_DESC : BBLOCK[DSC$C_S_BLN], !String descriptor
! for default specification
RELATED_DESC : BBLOCK[DSC$C_S_BLN], !String descriptor
! for related specification
IFAB : $FAB_DECL, !FAB for file_scan
INAM : $NAM_DECL, ! and a NAM block
RELNAM : $NAM_DECL, ! and a related NAM block
STATUS;
!+
! Make all descriptors dynamic.
!-
CH$FILL(0,DSC$C_S_BLN,LINEDESC);
LINEDESC[DSC$B_CLASS] = DSC$K_CLASS_D;
CH$MOVE(DSC$C_S_BLN,LINEDESC,RESULT_DESC);
CH$MOVE(DSC$C_S_BLN,LINEDESC,DEFAULT_DESC);
CH$MOVE(DSC$C_S_BLN,LINEDESC,RELATED_DESC);
!+
! Read file specification, default file specification, and related
! file specification
!-
STATUS = LIB$GET_INPUT(LINEDESC,
$DESCRIPTOR('File specification: '));
IF NOT .STATUS
THEN SIGNAL_STOP(.STATUS);
STATUS = LIB$GET_INPUT(DEFAULT_DESC,
$DESCRIPTOR('Default file specification: '));
IF NOT .STATUS
THEN SIGNAL_STOP(.STATUS);
STATUS = LIB$GET_INPUT(RELATED_DESC,
$DESCRIPTOR('Related file specification: '));
IF NOT .STATUS
THEN SIGNAL_STOP(.STATUS);
!+
! Initialize the FAB, NAM, and related NAM blocks.
!-
$FAB_INIT(FAB=IFAB,
FNS=.LINEDESC[DSC$W_LENGTH],
FNA=.LINEDESC[DSC$A_POINTER],
DNS=.DEFAULT_DESC[DSC$W_LENGTH],
DNA=.DEFAULT_DESC[DSC$A_POINTER],
NAM=INAM);
$NAM_INIT(NAM=INAM,
RSS=NAM$C_MAXRSS,
RSA=RESULT_BUFFER,
ESS=NAM$C_MAXRSS,
ESA=EXPAND_BUFFER,
RLF=RELNAM);
$NAM_INIT(NAM=RELNAM);
RELNAM[NAM$B_RSL] = .RELATED_DESC[DSC$W_LENGTH];
RELNAM[NAM$L_RSA] = .RELATED_DESC[DSC$A_POINTER];
!+
! Call LIB$FILE_SCAN. Note that errors need not be checked
! here because LIB$FILE_SCAN calls error_rtn for all errors.
!-
LIB$FILE_SCAN(IFAB,SUCCESS_RTN,ERROR_RTN);
!+
! Call LIB$FILE_SCAN_END to deallocate virtual memory used for
! file scan structures.
!-
STATUS = LIB$FILE_SCAN_END (IFAB);
IF NOT .STATUS
THEN SIGNAL_STOP (.STATUS);
RETURN 1
END; ! End of main program
ROUTINE SUCCESS_RTN (IFAB : REF BBLOCK) =
BEGIN
!+
! This routine is called by LIB$FILE_SCAN for each file that it
! successfully finds in the search sequence.
!
! Inputs:
!
! IFAB Address of a fab
!
! Outputs:
!
! file specification printed on SYS$OUTPUT
!-
LOCAL
DESC : BBLOCK[DSC$C_S_BLN]; ! A local string descriptor
BIND
INAM = .IFAB[FAB$L_NAM] : BBLOCK; ! Find NAM block
! from pointer in FAB
CH$FILL(0,DSC$C_S_BLN,DESC); ! Make static
! string descriptor
DESC[DSC$W_LENGTH] = .INAM[NAM$B_RSL]; ! Get string length
! from NAM block
DESC[DSC$A_POINTER] = .INAM[NAM$L_RSA]; ! Get pointer to the string
RETURN LIB$PUT_OUTPUT(DESC) ! Print name on SYS$OUTPUT
! and return
END;
ROUTINE ERROR_RTN (IFAB : REF BBLOCK) =
BEGIN
!+
! This routine is called by LIB$FILE_SCAN for each file specification that
! produces an error.
!
! Inputs:
!
! ifab Address of a fab
!
! Outputs:
!
! Error message is signaled
!-
LOCAL
DESC : BBLOCK[DSC$C_S_BLN]; ! A local string descriptor
BIND
INAM = .IFAB[FAB$L_NAM] : BBLOCK; ! Get NAM block pointer
! from FAB
CH$FILL(0,DSC$C_S_BLN,DESC); ! Create static
! string descriptor
DESC[DSC$W_LENGTH] = .INAM[NAM$B_RSL];
DESC[DSC$A_POINTER] = .INAM[NAM$L_RSA];
!+
! Signal the error using the shared message PARSEFAIL
! and the CLI facility code. The second part of the SIGNAL
! is the RMS STS and STV error codes.
!-
RETURN SIGNAL((SHR$_PARSEFAIL+3^16),1,DESC,
.IFAB[FAB$L_STS],.IFAB[FAB$L_STV])
END;
END ! End of module
ELUDOM
|
24.7.4 Inserting an Entry into a Balanced Binary Tree
Three routines allow you to manipulate the contents of a balanced
binary tree:
- LIB$INSERT_TREE adds an entry to a balanced binary tree.
- LIB$LOOKUP_TREE looks up an entry in a balanced binary tree.
- LIB$TRAVERSE_TREE calls an action routine for each node in the tree.
Example
The following BLISS example illustrates all three routines. The program
prompts for input from SYS$INPUT and stores each data line as an entry
in a binary tree. When the user enters the end-of-file character
(Ctrl/Z), the tree is printed in sorted order. The program includes
three subroutines:
- The first subroutine allocates virtual memory for a node.
- The second subroutine compares a key with a node.
- The third subroutine is called during the tree traversal. It prints
out the left and right subtree pointers, the current node balance, and
the name of the node.
%TITLE 'TREE_EXAMPLE - Sample program using binary tree routines'
MODULE TREE_EXAMPLE( ! Sample program using trees
IDENT = '1-001',
MAIN = TREE_START
) =
BEGIN
%SBTTL 'Declarations'
!+
! SWITCHES:
!-
SWITCHES ADDRESSING_MODE (EXTERNAL = GENERAL, NONEXTERNAL = WORD_RELATIVE);
!+
! LINKAGES:
!
! NONE
!
! TABLE OF CONTENTS:
!-
FORWARD ROUTINE
TREE_START, ! Main program
ALLOC_NODE, ! Allocate memory for a node
COMPARE_NODE, ! Compare two nodes
PRINT_NODE; ! Print a node (action routine
! for LIB$TRAVERSE_TREE)
!+
! INCLUDE FILES:
!-
LIBRARY 'SYS$LIBRARY:STARLET.L32'; ! System symbols
!+
! Define VMS block structures (BLOCK[,BYTE]).
!-
STRUCTURE
BBLOCK [O, P, S, E; N] =
[N]
(BBLOCK + O) <P, S, E>;
!+
! MACROS:
!-
MACRO
NODE$L_LEFT = 0,0,32,0%, ! Left subtree pointer in node
NODE$L_RIGHT = 4,0,32,0%, ! Right subtree pointer
NODE$W_BAL = 8,0,16,0%, ! Balance this node
NODE$B_NAMLNG = 10,0,8,0%, ! Length of name in this node
NODE$T_NAME = 11,0,0,0%; ! Start of name (variable length)
LITERAL
NODE$C_LENGTH = 11; ! Length of fixed part of node
!+
! EXTERNAL REFERENCES:
!-
EXTERNAL ROUTINE
LIB$GET_INPUT, ! Read from SYS$INPUT
LIB$GET_VM, ! Allocate virtual memory
LIB$INSERT_TREE, ! Insert into binary tree
LIB$LOOKUP_TREE, ! Lookup in binary tree
LIB$PUT_OUTPUT, ! Write to SYS$OUTPUT
LIB$TRAVERSE_TREE, ! Traverse a binary tree
STR$UPCASE, ! Convert string to all uppercase
SYS$FAO; ! Formatted ASCII output routine
%SBTTL 'TREE_START - Sample program main routine';
ROUTINE TREE_START =
BEGIN
!+
! This program reads from SYS$INPUT and stores each data line
! as an entry in a binary tree. When end-of-file character (CTRL/Z)
! is entered, the tree will be printed in sorted order.
!-
LOCAL
NODE : REF BBLOCK, ! Address of allocated node
TREEHEAD, ! List head of binary tree
LINEDESC : BBLOCK[DSC$C_S_BLN], ! String descriptor for input line
STATUS;
TREEHEAD = 0; ! Zero binary tree head
CH$FILL(0,DSC$C_S_BLN,LINEDESC); ! Make a dynamic descriptor
LINEDESC[DSC$B_CLASS] = DSC$K_CLASS_D; ! ...
!+
! Read input lines until end of file seen.
!-
WHILE (STATUS = LIB$GET_INPUT(LINEDESC, ! Read input line
$DESCRIPTOR('Text: '))) ! with this prompt
NEQ RMS$_EOF
DO IF NOT .STATUS ! Report any errors found
THEN SIGNAL(.STATUS)
ELSE BEGIN
STR$UPCASE(LINEDESC,LINEDESC); ! Convert string
! to uppercase
IF NOT (STATUS = LIB$INSERT_TREE(
TREEHEAD, ! Insert good data into the tree
LINEDESC, ! Data to insert
%REF(1), ! Insert duplicate entries
COMPARE_NODE, ! Addr. of compare routine
ALLOC_NODE, ! Addr. of node allocation routine
NODE, ! Return addr. of
0)) ! allocated node here
THEN SIGNAL(.STATUS);
END;
!+
! End of file character encountered. Print the whole tree and exit.
!-
IF NOT (STATUS = LIB$TRAVERSE_TREE(
TREEHEAD, ! Listhead of tree
PRINT_NODE, ! Action routine to print a node
0))
THEN SIGNAL(.STATUS);
RETURN SS$_NORMAL
END; ! End of routine tree_start
ROUTINE ALLOC_NODE (KEYDESC,RETDESC,CONTEXT) =
BEGIN
!+
! This routine allocates virtual memory for a node.
!
! INPUTS:
!
! KEYDESC Address of string descriptor for key
! (this is the linedesc argument passed
! to LIB$INSERT_TREE)
! RETDESC Address of location to return address of
! allocated memory
! CONTEXT Address of user context argument passed
! to LIB$INSERT_TREE (not used in this
! example)
!
! OUTPUTS:
!
! Memory address returned in longword pointed to by retdesc
!-
MAP
KEYDESC : REF BBLOCK,
RETDESC : REF VECTOR[,LONG];
LOCAL
NODE : REF BBLOCK,
STATUS;
STATUS = LIB$GET_VM(%REF(NODE$C_LENGTH+.KEYDESC[DSC$W_LENGTH]),NODE);
IF NOT .STATUS
THEN RETURN .STATUS
ELSE BEGIN
NODE[NODE$B_NAMLNG] = .KEYDESC[DSC$W_LENGTH]; ! Set name length
CH$MOVE(.KEYDESC[DSC$W_LENGTH], ! Copy in the name
.KEYDESC[DSC$A_POINTER],
NODE[NODE$T_NAME]);
RETDESC[0] = .NODE; ! Return address to caller
END;
RETURN .STATUS
END;
ROUTINE COMPARE_NODE (KEYDESC,NODE,CONTEXT) =
BEGIN
!+
! This routine compares a key with a node.
!
! INPUTS:
!
! KEYDESC Address of string descriptor for new key
! (This is the linedesc argument passed to
! LIB$INSERT_TREE)
! NODE Address of current node
! CONTEXT User context data (Not used in this example)
!-
MAP
KEYDESC : REF BBLOCK,
NODE : REF BBLOCK;
RETURN CH$COMPARE(.KEYDESC[DSC$W_LENGTH], ! Compare key with
! current node
.KEYDESC[DSC$A_POINTER],
.NODE[NODE$B_NAMLNG],
NODE[NODE$T_NAME])
END;
ROUTINE PRINT_NODE (NODE,CONTEXT) =
BEGIN
!+
! This routine is called during the tree traversal. It
! prints out the left and right subtree pointers, the
! current node balance, and the name of the node.
!-
MAP
NODE : REF BBLOCK;
LOCAL
OUTBUF : BBLOCK[512], ! FAO output buffer
OUTDESC : BBLOCK[DSC$C_S_BLN], ! Output buffer descriptor
STATUS;
CH$FILL(0,DSC$C_S_BLN,OUTDESC); ! Zero descriptor
OUTDESC[DSC$W_LENGTH] = 512;
OUTDESC[DSC$A_POINTER] = OUTBUF;
IF NOT (STATUS = SYS$FAO($DESCRIPTOR('!XL !XL !XL !XW !AC'),
OUTDESC,OUTDESC,
.NODE,.NODE[NODE$L_LEFT],
.NODE[NODE$L_RIGHT],
.NODE[NODE$W_BAL],
NODE[NODE$B_NAMLNG]))
THEN SIGNAL(.STATUS)
ELSE BEGIN
STATUS = LIB$PUT_OUTPUT(OUTDESC); ! Output the line
IF NOT .STATUS
THEN SIGNAL(.STATUS);
END;
RETURN SS$_NORMAL
END;
END ! End of module TREE_EXAMPLE
ELUDOM
|
|