|
OpenVMS Programming Concepts Manual
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
|
Chapter 25 Using Cross-Reference Routines
The cross-reference routines are contained in a separate, shareable
image capable of creating a cross-reference analysis of symbols. They
accept cross-reference data, summarize it, and format it for output.
Two facilities that use the cross-reference routines are the VMS Linker
and the MACRO assembler. They are sufficiently general, however, to be
used by any native-mode utility.
Table 25-1 lists the entry points and functions of the
cross-reference routines.
Table 25-1 Cross-Reference Routines
Entry Point |
Function |
LIB$CRF_INS_KEY
|
Inserts key information
|
LIB$CRF_INS_REF
|
Inserts reference information
|
LIB$CRF_OUTPUT
|
Summarizes and formats cross-reference information
|
The interface to the cross-reference routines is by way of a set of
control blocks, format definition tables, and a set of callable entry
points. Macros are provided for assembly language and BLISS
initialization of the control blocks and format definition tables.
25.1 How to Use the Cross-Reference Routines
Using the cross-reference routines involves the following steps:
- Define a table of control information, using the $CRFCTLTABLE macro.
- Define each field of the output line, using the $CRFFIELD macro.
- Specify the end of each set of macros that define a field in the
output line, using the $CRFFIELDEND macro.
- Provide data by calling one of the two following cross-reference
entry points:
- LIB$CRF_INS_KEY inserts an entry for the specified key in the
specified symbol table.
- LIB$CRF_INS_REF inserts a reference to a key in the specified
symbol table.
- Call LIB$CRF_OUTPUT, the cross-reference output routine, to
summarize and format the data.
- Supply a routine that the output routine calls to print each line
in the output file. Because you supply this routine, you can control
the number of lines per page and the header lines.
Figure 25-1 illustrates the steps required in using the
cross-reference routines.
Figure 25-1 Using Cross-Reference Routines
The Run-Time Library provides three macros to initialize the data
structures used by the cross-reference routines:
- $CRFCTLTABLE defines a table of control information.
- $CRFFIELD defines each field of the output format definition table.
Multiple $CRFFIELD macro instructions can be issued in defining one
particular field.
- $CRFFIELDEND ends a set of $CRFFIELD macro instructions (a format
table).
25.2 $CRFCTLTABLE Macro
$CRFCTLTABLE initializes a cross-reference control table. Your program
must issue one $CRFCTLTABLE macro for each cross-reference table you
build. You can accumulate information for more than one cross-reference
table at a time. For this reason, you must define a table for each set
of cross-references, and include the address of that table each time
you call a cross-reference routine to insert data.
The $CRFCTLTABLE macro instruction has the following format:
label: $CRFCTLTABLE keytype, output, error, memexp, key1table,
key2table, val1table, val2table,
ref1table, ref2table
|
label
The address of the control table. You must specify a control table
address in all calls to the cross-reference routines.
keytype
The type of key to enter into the table. The following key types are
defined:
ASCIC
|
Keys are counted ASCII strings, with a maximum of 31 characters (symbol
name).
|
BIN_U32
|
Keys are 32-bit unsigned binary values. The binary-to-ASCII conversion
is done by $FAO using the format string for the KEY1 field.
|
output
The address of the routine that you supply to print a formatted output
line. The output line is passed to the output routine by descriptor.
error
The address of an error routine to execute if the called
cross-reference routine encounters an error. The error code (longword)
is passed to the error routine by value. In other words, it is a copy
of the constant on the stack. A value of zero indicates that no error
routine is supplied.
memexp
The number of pages by which to expand region when needed. The default
is 50.
key1table
The address of the field descriptor table for the KEY1 field. A value
of zero indicates that the field is not to be included in the output
line.
The remaining arguments provide the address of the field descriptor
tables for the KEY2, VAL1, VAL2, REF1, and REF2 fields, respectively,
of the output line. You can use these argument names as keywords in the
macros. For example, you can use KEYTYPE as a keyword when issuing the
$CRFCTLTABLE macro.
25.3 $CRFFIELD Macro
For each field in the output line, you must issue a $CRFFIELD
instruction to identify the field, supply an $FAO command string to
control the printing of the field, and provide flag information. See
the program example and the description of $FAO (formatted ASCII
output) in the OpenVMS System Services Reference Manual. The
$CRFFIELD macro has the following format:
label: $CRFFIELD bit_mask, fao_string, field_width,
set_clear
|
label
The address of the field descriptor table generated as a result of this
set of $CRFFIELD macro instructions. The label field can be omitted
after the first macro of the set. These addresses correspond to the
field descriptor table addresses in the $CRFCTLTABLE macro.
bit_mask
A 16-bit mask. When the user enters a key or reference, the
cross-reference routine stores flag information with the entry. When
preparing the output line, LIB$CRF_OUTPUT performs an AND operation on
the 16-bit mask in the field descriptor table with the flag stored with
the entry. Any number of bit masks can be defined for a field.
$CRFFIELD macro instructions are used to define multiple bit patterns
for a flag field. The high-order bit is reserved to the cross-reference
routines.
fao_string
The $FAO command string. LIB$CRF_OUTPUT uses this string to determine
the $FAO format when formatting this field for output.
field_width
The maximum width of the output field.
set_clear
The indicator used to determine whether the bit mask is to be tested as
set or clear when determining which flag to use. SET indicates test for
set; CLEAR indicates test for clear.
You can use the argument names shown here as keywords in your program.
In the following example, one bit pattern is defined twice; once
indicating a string that is to be printed if the pattern is set, and
once indicating that spaces are to appear if the pattern is clear.
$CRFFIELD BIT_MASK=SYM$M_REL, FAO_STRING=3_\##_\,-
SET_CLEAR=CLEAR, FIELD_WIDTH=2
$CRFFIELD BIT_MASK=SYM$M_REL, FAO_STRING=_\-R_\,-
SET_CLEAR=SET, FIELD_WIDTH=2
|
If more than one set of flags is defined for a field, each FAO string
must print the same number of characters; otherwise, the output is not
aligned in columns.
The fields for the symbol name, symbol value, and references are always
formatted using the first descriptor in the corresponding table.
25.4 $CRFFIELDEND Macro
The $CRFFIELDEND macro instruction marks the end of a set of macros
that describe one field of the output line. It is used once to end each
set of field descriptors. It has the following format:
25.5 Cross-Reference Output
LIB$CRF_OUTPUT can format output lines for three types of
cross-reference listings:
- A summary of symbol names and their values, as illustrated in
Figure 25-2.
- A summary of symbol names, their values, and the names of modules
that refer to the symbol, as illustrated in Figure 25-3.
- A summary of symbol names, their values, the name of the defining
module, and the names of those modules that refer to the symbol, as
illustrated in Figure 25-4.
Figure 25-2 Summary of Symbol Names and Values
Figure 25-3 Summary of Symbol Names, Values, and Name of
Referring Modules
Figure 25-4 Summary Indicating Defining Module
Regardless of the format of the output, LIB$CRF_OUTPUT considers the
output line to consist of the following six different field types:
- KEY1 is the first field in the line. It contains a symbol name.
- KEY2 is the second field in the line. It contains a set of flags
(for example,--R) providing information about the symbol.
- VAL1 is the third field in the line. It contains the value of the
symbol.
- VAL2 is the fourth field in the line. It contains a set of flags
describing VAL1.
- REF1 and REF2 fields. Within each REF1 and REF2 pair, REF1 provides
a set of flags and REF2 provides the name of a module that references
the symbol.
Figure 25-5 shows that any of these fields can be omitted from the
output.
Figure 25-5 Output Line for LIB$CRF_OUTPUT
|