1 Introduction
2 Ground Rules

Building a File System
3 File Systems
4 File Content Data Structure
5 Allocation Cluster Manager
6 Exceptions and Emancipation
7 Base Classes, Testing, and More
8 File Meta Data
9 Native File Class
10 Our File System
11 Allocation Table
12 File System Support Code
13 Initializing the File System
14 Contiguous Files
15 Rebuilding the File System
16 Native File System Support Methods
17 Lookups, Wildcards, and Unicode, Oh My
18 Finishing the File System Class

The Init Program
19 Hardware Abstraction and UOS Architecture
20 Init Command Mode
21 Using Our File System
22 Hardware and Device Lists
23 Fun with Stores: Partitions
24 Fun with Stores: RAID
25 Fun with Stores: RAM Disks
26 Init wrap-up

The Executive
27 Overview of The Executive
28 Starting the Kernel
29 The Kernel
30 Making a Store Bootable
31 The MMC
32 The HMC
33 Loading the components
34 Using the File Processor
35 Symbols and the SSC
36 The File Processor and Device Management
37 The File Processor and File System Management
38 Finishing Executive Startup

Users and Security
39 Introduction to Users and Security
40 More Fun With Stores: File Heaps
41 File Heaps, part 2
42 SysUAF
43 TUser
44 SysUAF API

Terminal I/O
45 Shells and UCL
46 UOS API, the Application Side
47 UOS API, the Executive Side
48 I/O Devices
49 Streams
50 Terminal Output Filters
51 The TTerminal Class
52 Handles
53 Putting it All Together
54 Getting Terminal Input
55 QIO
56 Cooking Terminal Input
57 Putting it all together, part 2
58 Quotas and I/O

UCL
59 UCL Basics
60 Symbol Substitution
61 Command execution
62 Command execution, part 2
63 Command Abbreviation
64 ASTs
65 Expressions, Part 1
66 Expressions, Part 2: Support code
67 Expressions, part 3: Parsing
68 SYS_GETJPIW and SYS_TRNLNM
69 Expressions, part 4: Evaluation

UCL Lexical Functions
70 PROCESS_SCAN
71 PROCESS_SCAN, Part 2
72 TProcess updates
73 Unicode revisted
74 Lexical functions: F$CONTEXT
75 Lexical functions: F$PID
76 Lexical Functions: F$CUNITS
77 Lexical Functions: F$CVSI and F$CVUI
78 UOS Date and Time Formatting
79 Lexical Functions: F$CVTIME
80 LIB_CVTIME
81 Date/Time Contexts
82 SYS_GETTIM, LIB_Get_Timestamp, SYS_ASCTIM, and LIB_SYS_ASCTIM
83 Lexical Functions: F$DELTA_TIME
84 Lexical functions: F$DEVICE
85 SYS_DEVICE_SCAN
86 Lexical functions: F$DIRECTORY
87 Lexical functions: F$EDIT and F$ELEMENT
88 Lexical functions: F$ENVIRONMENT
89 SYS_GETUAI
90 Lexical functions: F$EXTRACT and F$IDENTIFIER
91 LIB_FAO and LIB_FAOL
92 LIB_FAO and LIB_FAOL, part 2
93 Lexical functions: F$FAO
94 File Processing Structures
95 Lexical functions: F$FILE_ATTRIBUTES
96 SYS_DISPLAY
97 Lexical functions: F$GETDVI
98 Parse_GetDVI
99 GetDVI
100 GetDVI, part 2
101 GetDVI, part 3
102 Lexical functions: F$GETJPI

Glossary/Index


Download sources
Download binaries

Parse_GetDVI

Parse_GetDVI does the actual work for the F$GETDVI lexical function that we described in the previous article. The system service that it wraps has over 200 items of information that it can return. This makes our function rather long, although not too complex. The main points here are that the GETDVI system call takes a list of descriptors, although we will only ever pass a single descriptor for this function (and the null terminating descriptor), and the executive returns to us a value that is a string, an integer, or a boolean value. Boolean values are returned as integers as well, with a 0 indicating False and 1 indicating True. F$GETDVI makes things a little easier for the user by allowing the retrieval of certain device flags without the user having to parse them. In these cases, we will get the device flags and check for the presence of the specific flag, returning TRUE or FALSE, as appropriate.

type TItemType = ( IT_String, IT_Integer, IT_Boolean, IT_DT ) ;
This enumeration allows us to identify the type of item we are processing. IT_DT is used to indicate a flag within the device flags and the other codes indicate the returned data type.

function Parse_GetDVI( var Err : integer ; var Context : string ) : boolean ;

var Code : int64 ;
    I, I1 : integer ;
    Dev, Itm, Path : string ;
    ItemType : TItemType ;

begin
    // Setup...
    Result := False ; // Assume no problems
    Err := 0 ;
    Context := '' ;
    ItemType := IT_String ;
Here we initialize the function. We'll default to string return values.

    // Get device name....
    Dev := lowercase( Get_Parameter( Err, Context ) ) ;
    if( Err <> 0 ) then
    begin
        exit ;
    end ;
    if( Missing_Comma( Err ) ) then
    begin
        exit ;
    end ;

    // Get item....
    Itm := trim( lowercase( Get_Parameter( Err, Context ) ) ) ;
    if( Err <> 0 ) then
    begin
        exit ;
    end ;

    Path := Get_Token ;
    if( Path = ',' ) then // Optional path
    begin
        Path := trim( lowercase( Get_Parameter( Err, Context ) ) ) ;
        if( Err <> 0 ) then
        begin
            exit ;
        end ;
    end else
    begin
        Parser.Put_Token( Path ) ;
        Path := '' ;
    end ;
We've seen this kind of code before, we're getting the parameters from the token stream and exiting if there is an error. Itm contains the item name and Dev contains the device name. Path is the optional path parameter.

    // Process item...
    Code := -1 ; // Assume no match
    if( Itm = 'devchar' ) then
    begin
        Code := DVI_DEVCHAR ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'accesstimes_recorded' ) then
    begin
        Code := DVI_ACCESSTIME_RECORDED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'acppid' ) then
    begin
        Code := DVI_ACPPID ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'acptype' ) then
    begin
        Code := DVI_ACPTYPE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'all' ) then
    begin
        Code := DVI_ALL ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'alldevnam' ) then
    begin
        Code := DVI_ALLDEVNAM ;
    end else
    if( Itm = 'alloclass' ) then
    begin
        Code := DVI_ALLOCLASS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'alt_host_avail' ) then
    begin
        Code := DVI_ALT_HOST_AVAIL ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'alt_host_name' ) then
    begin
        Code := DVI_ALT_HOST_NAME;
    end else
    if( Itm = 'alt_host_type' ) then
    begin
        Code := DVI_ALT_HOST_TYPE ;
    end else
    if( Itm = 'available_path_count' ) then
    begin
        Code := DVI_AVAILABLE_PATH_COUNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'avl' ) then
    begin
        Code := DVI_AVL ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'ccl' ) then
    begin
        Code := DEV_V_CCL ;
        ItemType := IT_DT ;
    end else
First we default the Code variable to -1 in case we don't find a match to what the user specified. We check for each valid item and, when found, set the DVI code and the item type (result type). In this sample, we see the different result types. For DEVCHAR, we expect the system to return an integer value. For ALL, we expect a boolean. In the case of ALLDEVNAM, we don't set the item type since that was already defaulted to string. And for CCL, we are going to parse the device flags for DEV_V_CCL. So we set the result type to IT_DT and set the code to the device flag instead of the DVI item code. Now let's see the rest of the items:

    if( Itm = 'cluster' ) then
    begin
        Code := DVI_CLUSTER ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'concealed' ) then
    begin
        Context := 'FALSE' ; //TODO
    end else
    if( Itm = 'cylinders' ) then
    begin
        Code := DVI_CYLINDERS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'devbufsiz' ) then
    begin
        Code := DVI_DEVBUFSIZ ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'devchar2' ) then
    begin
        Code := DVI_DEVCHAR2 ;
    end else
    if( Itm = 'devclass' ) then
    begin
        Code := DVI_DEVCLASS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'devdepend' ) then
    begin
        Code := DVI_DEVDEPEND ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'devdepend2' ) then
    begin
        Code := DVI_DEVDEPEND2 ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'device_max_io_size' ) then
    begin
        Code := DVI_DEVICE_MAX_IO_SIZE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'device_type_name' ) then
    begin
        Code := DVI_DEVICE_TYPE_NAME ;
    end else
    if( Itm = 'devlocknam' ) then
    begin
        Code := DVI_DEVLOCKNAM ;
    end else
    if( Itm = 'devnam' ) then
    begin
        Code := DVI_DEVNAM ;
    end else
    if( Itm = 'devsts' ) then
    begin
        Code := DVI_DEVSTS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'devtype' ) then
    begin
        Code := DVI_DEVTYPE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'dfs_access' ) then
    begin
        Code := DVI_DFS_ACCESS ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'dir' ) then
    begin
        Code := DEV_V_DIR ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'dmt' ) then
    begin
        Code := DEV_V_DMT ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'dua' ) then
    begin
        Code := DEV_V_DUA ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'elg' ) then
    begin
        Code := DEV_V_ELG ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'erase_on_delete' ) then
    begin
        Code := DVI_ERASE_ON_DELETE ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'errcnt' ) then
    begin
        Code := DVI_ERRCNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'error_reset_time' ) then
    begin
        Code := DVI_ERROR_RESET_TIME ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'exists' ) then
    begin
        Code := DVI_EXISTS ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'expsize' ) then
    begin
        Code := DVI_EXPSIZE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'fc_hba_firemware_rev' ) then
    begin
        Code := DVI_FC_HBA_FIRMWARE_REV ;
    end else
    if( Itm = 'fc_node_name' ) then
    begin
        Code := DVI_FC_NODE_NAME ;
    end else
    if( Itm = 'fc_port_name' ) then
    begin
        Code := DVI_FC_PORT_NAME ;
    end else
    if( Itm = 'firmware_rev' ) then
    begin
        Code := DVI_FIRMWARE_REV ;
    end else
    if( Itm = 'fod' ) then
    begin
        Code := DEV_V_FOD ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'for' ) then
    begin
        Code := DEV_V_FOR ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'freeblocks' ) then
    begin
        Code := DVI_FREEBLOCKS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'fulldevnam' ) then
    begin
        Code := DVI_FULLDEVNAM ;
    end else
    if( Itm = 'gen' ) then
    begin
        Code := DEV_V_GEN ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'hardlinks_supported' ) then
    begin
        Code := DVI_HARDLINKS_SUPPORTED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'host_avail' ) then
    begin
        Code := DVI_HOST_AVAIL ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'host_count' ) then
    begin
        Code := DVI_HOST_COUNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'host_name' ) then
    begin
        Code := DVI_HOST_NAME ;
    end else
    if( Itm = 'host_type' ) then
    begin
        Code := DVI_HOST_TYPE ;
    end else
    if( Itm = 'idv' ) then
    begin
        Code := DEV_V_IDV ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'lan_all_multicast_mode' ) then
    begin
        Code := DVI_LAN_ALL_MULTICAST_MODE ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'lan_autoneg_enabled' ) then
    begin
        Code := DVI_LAN_AUTONEG_ENABLED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'lan_default_mac_address' ) then
    begin
        Code := DVI_LAN_DEFAULT_MAC_ADDRESS ;
    end else
    if( Itm = 'lan_full_duplex' ) then
    begin
        Code := DVI_LAN_FULL_DUPLEX ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'lan_jumbo_frames_enabled' ) then
    begin
        Code := DVI_LAN_JUMBO_FRAMES_ENABLED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'lan_link_state_valid' ) then
    begin
        Code := DVI_LAN_LINK_STATE_VALID ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'lan_link_up' ) then
    begin
        Code := DVI_LAN_LINK_UP ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'lan_mac_address' ) then
    begin
        Code := DVI_LAN_MAC_ADDRESS ;
    end else
    if( Itm = 'lan_promiscuous_mode' ) then
    begin
        Code := DVI_LAN_PROMISCUOUS_MODE ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'lan_protocol_name' ) then
    begin
        Code := DVI_LAN_PROTOCOL_NAME ;
    end else
    if( Itm = 'lan_protocol_type' ) then
    begin
        Code := DVI_LAN_PROTOCOL_TYPE ;
    end else
    if( Itm = 'lan_speed' ) then
    begin
        Code := DVI_LAN_SPEED ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'lockid' ) then
    begin
        Code := DVI_LOCKID ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'logvolnam' ) then
    begin
        Code := DVI_LOGVOLNAM ;
    end else
    if( Itm = 'mailbox_buffer_quota' ) then
    begin
        Code := DVI_MAILBOX_BUFFER_QUOTA ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'mailbox_initial_quota' ) then
    begin
        Code := DVI_MAILBOX_INITIAL_QUOTA ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'maxblock' ) then
    begin
        Code := DVI_MAXBLOCK ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'maxfiles' ) then
    begin
        Code := DVI_MAXFILES ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'mbx' ) then
    begin
        Code := DEV_V_MBX ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'media_id' ) then
    begin
        Code := DVI_MEDIA_ID ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'media_name' ) then
    begin
        Code := DVI_MEDIA_NAME ;
    end else
    if( Itm = 'media_type' ) then
    begin
        Code := DVI_MEDIA_TYPE ;
    end else
    if( Itm = 'mnt' ) then
    begin
        Code := DEV_V_MNT ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'mount_time' ) then
    begin
        Code := DVI_MOUNT_TIME ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'mountcnt' ) then
    begin
        Code := DVI_MOUNTCNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'mountver_eligible' ) then
    begin
        Code := DVI_MOUNTVER_ELIGIBLE ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'mpdev_auto_path_sw_cnt' ) then
    begin
        Code := DVI_MPDEV_AUTO_PATH_SW_CNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'mpdev_current_path' ) then
    begin
        Code := DVI_MPDEV_CURRENT_PATH ;
    end else
    if( Itm = 'mpdev_man_path_sw_cnt' ) then
    begin
        Code := DVI_MPDEV_MAN_PATH_SW_CNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'mt3_density' ) then
    begin
        Code := DVI_MT3_DENSITY ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'mt3_supported' ) then
    begin
        Code := DVI_MT3_SUPPORTED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'multipath' ) then
    begin
        Code := DVI_MULTIPATH ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'mvsupmsg' ) then
    begin
        Code := DVI_MVSUPMSG ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'net' ) then
    begin
        Code := DEV_V_NET ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'nextdevnam' ) then
    begin
        Code := DVI_NEXTDEVNAM ;
    end else
    if( Itm = 'nocache_on_volume' ) then
    begin
        Code := DVI_NOCACHE_ON_VOLUME ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'nohighwater' ) then
    begin
        Code := DVI_NOHIGHWATER ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'noshare_mounted' ) then
    begin
        Code := DVI_NOSHARE_MOUNTED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'ods2_subset0' ) then
    begin
        Code := DVI_ODS2_SUBSET0 ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'ods5' ) then
    begin
        Code := DVI_ODS5 ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'odv' ) then
    begin
        Code := DEV_V_ODV ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'opcnt' ) then
    begin
        Code := DVI_OPCNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'opr' ) then
    begin
        Code := DEV_V_OPR ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'ownuic' ) then
    begin
        Code := DVI_OWNUIC ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'path_available' ) then
    begin
        Code := DVI_PATH_AVAILABLE ;
    end else
    if( Itm = 'path_not_responding' ) then
    begin
        Code := DVI_PATH_NOT_RESPONDING ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'path_poll_enabled' ) then
    begin
        Code := DVI_PATH_POLL_ENABLED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'path_switch_from_time' ) then
    begin
        Code := DVI_PATH_SWITCH_FROM_TIME ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'path_switch_to_time' ) then
    begin
        Code := DVI_PATH_SWITCH_TO_TIME ;
    end else
    if( Itm = 'path_user_disabled' ) then
    begin
        Code := DVI_PATH_USER_DISABLED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'pid' ) then
    begin
        Code := DVI_PID ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'preferred_cpu' ) then
    begin
        Code := DVI_PREFERRED_CPU ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'preferred_cpu_bitmap' ) then
    begin
        Code := DVI_PREFERRED_CPU_BITMAP ;
    end else
    if( Itm = 'prot_subsystem_enabled' ) then
    begin
        Code := DVI_PROT_SUBSYSTEM_ENABLED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'qlen' ) then
    begin
        Code := DVI_QLEN ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'rck' ) then
    begin
        Code := DEV_V_RCK ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'rct' ) then
    begin
        Code := DEV_V_RCT ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'rec' ) then
    begin
        Code := DEV_V_REC ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'recsiz' ) then
    begin
        Code := DVI_RECSIZ ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'refcnt' ) then
    begin
        Code := DVI_REFCNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'remote_device' ) then
    begin
        Code := DVI_REMOTE_DEVICE ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'rnd' ) then
    begin
        Code := DEV_V_RND ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'rootdevname' ) then
    begin
        Code := DVI_ROOTDEVNAME ;
    end else
    if( Itm = 'rtm' ) then
    begin
        Code := DEV_V_RTM ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'scsi_device_firmware_rev' ) then
    begin
        Code := DVI_SCSI_DEVICE_FIRMWARE_REV ;
    end else
    if( Itm = 'sdi' ) then
    begin
        Code := DEV_V_SDI ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'sectors' ) then
    begin
        Code := DVI_SECTORS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'serialnum' ) then
    begin
        Code := DVI_SERIALNUM ;
    end else
    if( Itm = 'served_device' ) then
    begin
        Code := DVI_SERVED_DEVICE ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'set_host_terminal' ) then
    begin
        Code := TF_Set_Host ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'shdw_catchup_copying' ) then
    begin
        Code := DVI_SHDW_CATCHUP_COPYING ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'shdw_copier_node' ) then
    begin
        Code := DVI_SHDW_COPIER_NODE ;
    end else
    if( Itm = 'shdw_device_count' ) then
    begin
        Code := DVI_SHDW_DEVICE_COUNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'shdw_generation' ) then
    begin
        Code := DVI_SHDW_GENERATION ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'shdw_master' ) then
    begin
        Code := DVI_SHDW_MASTER ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'shdw_master_mbr' ) then
    begin
        Code := DVI_SHDW_MASTER_MBR ;
    end else
    if( Itm = 'shdw_master_name' ) then
    begin
        Code := DVI_SHDW_MASTER_NAME ;
    end else
    if( Itm = 'shdw_mbr_copy_done' ) then
    begin
        Code := DVI_SHDW_MBR_COPY_DONE ;
    end else
    if( Itm = 'shdw_mbr_count' ) then
    begin
        Code := DVI_SHDW_MBR_COUNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'shdw_mbr_merge' ) then
    begin
        Code := DVI_SHDW_MBR_MERGE_DONE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'shdw_mbr_read_cost' ) then
    begin
        Code := DVI_SHDW_MBR_READ_COST ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'shdw_member' ) then
    begin
        Code := DVI_SHDW_MEMBER ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'shdw_merge_copying' ) then
    begin
        Code := DVI_SHDW_MERGE_COPYING ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'shdw_minimerge_enable' ) then
    begin
        Code := DVI_SHDW_MINIMERGE_ENABLE ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'shdw_next_mbr_name' ) then
    begin
        Code := DVI_SHDW_NEXT_MBR_NAME ;
    end else
    if( Itm = 'shdw_read_source' ) then
    begin
        Code := DVI_SHDW_READ_SOURCE ;
    end else
    if( Itm = 'shdw_site' ) then
    begin
        Code := DVI_SHDW_SITE ;
    end else
    if( Itm = 'shdw_timeout' ) then
    begin
        Code := DVI_SHDW_TIMEOUT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'shr' ) then
    begin
        Code := DEV_V_SHR ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'spl' ) then
    begin
        Code := DEV_V_SPL ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'spldevname' ) then
    begin
        Code := DVI_SPLDEVNAME ;
    end else
    if( Itm = 'sqd' ) then
    begin
        Code := DEV_V_SQD ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'sts' ) then
    begin
        Code := DVI_STS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'swl' ) then
    begin
        Code := DEV_V_SWL ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'total_path_count' ) then
    begin
        Code := DVI_TOTAL_PATH_COUNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tracks' ) then
    begin
        Code := DVI_TRACKS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'transcnt' ) then
    begin
        Code := DVI_TRANSCNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'trm' ) then
    begin
        Code := DEV_V_TRM ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'tt_accpornam' ) then
    begin
        Code := DVI_TT_ACCPORNAM ;
    end else
    if( Itm = 'tt_altypeahd' ) then
    begin
        Code := DVI_TT_ALTYPEAHD ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_ansicrt' ) then
    begin
        Code := DVI_TT_ANSICRT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_app_keypad' ) then
    begin
        Code := DVI_TT_APP_KEYPAD ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_autobaud' ) then
    begin
        Code := DVI_TT_AUTOBAUD ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_avo' ) then
    begin
        Code := DVI_TT_AVO ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_block' ) then
    begin
        Code := DVI_TT_BLOCK ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_brdcstmbx' ) then
    begin
        Code := DVI_TT_BRDCSTMBX ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_charset' ) then
    begin
        Code := DVI_TT_CHARSET ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_crfill' ) then
    begin
        Code := DVI_TT_CRFILL ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_cs_hangul' ) then
    begin
        Code := DVI_TT_CS_HANGUL ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_cs_hanyu' ) then
    begin
        Code := DVI_TT_CS_HANYU ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_hanzi' ) then
    begin
        Code := DVI_TT_CS_HANZI ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_cs_kana' ) then
    begin
        Code := DVI_TT_CS_KANA ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_ca_kanji' ) then
    begin
        Code := DVI_TT_CS_KANJI ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_cs_thai' ) then
    begin
        Code := DVI_TT_CS_THAI ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_deccrt' ) then
    begin
        Code := DVI_TT_DECCRT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_deccrt2' ) then
    begin
        Code := DVI_TT_DECCRT2 ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_deccrt3' ) then
    begin
        Code := DVI_TT_DECCRT3 ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_deccrt4' ) then
    begin
        Code := DVI_TT_DECCRT4 ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_dialup' ) then
    begin
        Code := DVI_TT_DIALUP ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_disconnect' ) then
    begin
        Code := DVI_TT_DISCONNECT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_dma' ) then
    begin
        Code := DVI_TT_DMA ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_drcs' ) then
    begin
        Code := DVI_TT_DRCS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_edit' ) then
    begin
        Code := DVI_TT_EDIT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_editing' ) then
    begin
        Code := DVI_TT_EDITING ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_eightbit' ) then
    begin
        Code := DVI_TT_EIGHTBIT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_escape' ) then
    begin
        Code := DVI_TT_ESCAPE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_fallback' ) then
    begin
        Code := DVI_TT_FALLBACK ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_halfdup' ) then
    begin
        Code := DVI_TT_HALFDUP ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_hangup' ) then
    begin
        Code := DVI_TT_HANGUP ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_hostsync' ) then
    begin
        Code := DVI_TT_HOSTSYNC ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_insert' ) then
    begin
        Code := DVI_TT_INSERT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_lffill' ) then
    begin
        Code := DVI_TT_LFFILL ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_localecho' ) then
    begin
        Code := DVI_TT_LOCALECHO ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_lower' ) then
    begin
        Code := DVI_TT_LOWER ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_mbxdsabl' ) then
    begin
        Code := DVI_TT_MBXDSABL ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_mechform' ) then
    begin
        Code := DVI_TT_MECHFORM ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_mechtab' ) then
    begin
        Code := DVI_TT_MECHTAB ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_modem' ) then
    begin
        Code := DVI_TT_MODEM ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_modhangup' ) then
    begin
        Code := DVI_TT_MODHANGUP ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_nobrdcst' ) then
    begin
        Code := DVI_TT_NOBRDCST ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_noecho' ) then
    begin
        Code := DVI_TT_NOECHO ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_notypeahd' ) then
    begin
        Code := DVI_TT_NOTYPEAHD ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_oper' ) then
    begin
        Code := DVI_TT_OPER ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_page' ) then
    begin
        Code := DVI_TT_PAGE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_pasthru' ) then
    begin
        Code := DVI_TT_PASTHRU ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_phydevnam' ) then
    begin
        Code := DVI_TT_PHYDEVNAM ;
    end else
    if( Itm = 'tt_printer' ) then
    begin
        Code := DVI_TT_PRINTER ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_readsync' ) then
    begin
        Code := DVI_TT_READSYNC ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_regis' ) then
    begin
        Code := DVI_TT_REGIS ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_remote' ) then
    begin
        Code := DVI_TT_REMOTE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_scope' ) then
    begin
        Code := DVI_TT_SCOPE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_secure' ) then
    begin
        Code := DVI_TT_SECURE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_setspeed' ) then
    begin
        Code := DVI_TT_SETSPEED ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_sixel' ) then
    begin
        Code := DVI_TT_SIXEL ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_syspwd' ) then
    begin
        Code := DVI_TT_SYSPWD ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_ttsync' ) then
    begin
        Code := DVI_TT_TTSYNC ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'tt_wrap' ) then
    begin
        Code := DVI_TT_WRAP ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'unit' ) then
    begin
        Code := DVI_UNIT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volchar' ) then
    begin
        Code := DVI_VOLCHAR ;
    end else
    if( Itm = 'volcount' ) then
    begin
        Code := DVI_VOLCOUNT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volnam' ) then
    begin
        Code := DVI_VOLNAM ;
    end else
    if( Itm = 'volnumber' ) then
    begin
        Code := DVI_VOLNUMBER ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volsetmem' ) then
    begin
        Code := DVI_VOLSETMEM ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'volsize' ) then
    begin
        Code := DVI_VOLSIZE ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volume_extend_quantity' ) then
    begin
        Code := DVI_VOLUME_EXTEND_QUANTITY ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volume_mount_group' ) then
    begin
        Code := DVI_VOLUME_MOUNT_GROUP ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'volume_mount_sys' ) then
    begin
        Code := DVI_VOLUME_MOUNT_SYS ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'volume_pending_write_err' ) then
    begin
        Code := DVI_VOLUME_PENDING_WRITE_ERR ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volume_retain_max' ) then
    begin
        Code := DVI_VOLUME_RETAIN_MAX ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volume_retain_max' ) then
    begin
        Code := DVI_VOLUME_RETAIN_MIN ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volume_spooled_dev_cbt' ) then
    begin
        Code := DVI_VOLUME_SPOOLED_DEV_CBT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'volume_window' ) then
    begin
        Code := DVI_VOLUME_WINDOW ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'vprot' ) then
    begin
        Code := DVI_VPROT ;
        ItemType := IT_Integer ;
    end else
    if( Itm = 'wck' ) then
    begin
        Code := DEV_V_WCK ;
        ItemType := IT_DT ;
    end else
    if( Itm = 'writethru_cache_enabled' ) then
    begin
        Code := DVI_WRITETHRU_CACHE_ENABLED ;
        ItemType := IT_Boolean ;
    end else
    if( Itm = 'wwid' ) then
    begin
        Code := DVI_WWID ;
    end else
    begin
        Err := UCL_IVKEYW ; // Unrecognized keyword
        Context := Itm ;
        exit ;
    end ;
The only thing to note is the else condition where we return an IVKEYW error if no item was recognized.

    // Process request...
    if( ItemType = IT_DT ) then
    begin
        Context := Get_DVI( Dev, Path, DVI_DEVCHAR ) ;
        while( length( Context ) < 8 ) do // Pad to 8 bytes (shouldn't be needed)
        begin
            Context := #0 + Context ;
        end ;
        move( PChar( Context )[ 0 ], I, sizeof( I ) ) ;
        Context := Get_DVI( Dev, Path, DVI_DEVCHAR2 ) ;
        while( length( Context ) < 8 ) do // Pad to 8 bytes (shouldn't be needed)
        begin
            Context := #0 + Context ;
        end ;
        move( PChar( Context )[ 0 ], I1, sizeof( I1 ) ) ;
        I := I or I1 ;

        if( ( I and Code ) = 0 ) then
        begin
            Context := 'FALSE' ;
        end else
        begin
            Context := 'TRUE' ;
        end ;
    end else
Now that we know the item code and the return type, we can obtain the value. We first check for the IT_DT result type. In this case we obtain the device characteristics (flags), via Get_DVI. The flags should be an 8-byte integer value. We make sure by extending the the result to that length if it is shorter. The returned string is a binary image of the data, so we copy from the value to the I variable. Because VMS returns device characters in two 32-bit sets, we have to repeat the process for DVI_DEVCHAR2 and then bitwise or the two flag sets together (we can do this because UOS keeps device flags in a single 64-bit value, and returns the low half for DVI_DEVCHAR and the upper half for DVI_DEVCHAR2). Finally, we compare the flag in Code with the combined flags. If the bitwise and is 0, we return FALSE. Otherwise we return TRUE.

    begin
        Context := Get_DVI( Dev, Path, Code ) ;
        if( ( ItemType = IT_Integer ) or ( ItemType = IT_Boolean ) ) then
        begin
            while( length( Context ) < 8 ) do
            begin
                Context := #0 + Context ;
            end ;
            move( PChar( Context )[ 0 ], I, sizeof( I ) ) ;
            Context := inttostr( I ) ;
        end ;
        if( ItemType = IT_Boolean ) then
        begin
            if( Context = '0' ) then
            begin
                Context := 'FALSE' ;
            end else
            begin
                Context := 'TRUE' ;
            end ;
        end ;
    end ;
end ; // Parse_GetDVI
For the other return types, we get the result which is assigned to the Context string. If the result type is integer or boolean, the actual result from the system will be an 8-byte integer. In that case we make sure the string is at least 8-bytes long and copy the bits into the I variable. Otherwise, we leave the string as is. Finally, if the result type is boolean, we convert a 0 to FALSE and other values to TRUE.

function Get_DVI( const Device, Path : string ; Code : integer ) : string ;

begin
    Buff := 0 ;
    BufLen := sizeof( Buf ) ;
    fillchar( Descriptor, sizeof( Descriptor ), 0 ) ;
    Descriptor[ 0 ].Buffer_Length := sizeof( Buff ) ;
    Descriptor[ 0 ].Item_Code := Code ; // DVIDEF item
    Descriptor[ 0 ].Buffer_Address := integer( @Buf ) ;
    Descriptor[ 0 ].Return_Length_Address := integer( @BufLen ) ;
    GETDVIW( 0, 0, Device, integer( @Descriptor ), integer( @IOSB ),
        0, 0, Path, 1 ) ;
    setlength( Result, BufLen ) ;
    move( Buf[ 0 ], PChar( Result )[ 0 ], BufLen ) ;
end ;
This function is used in the above code as a short-hand way to obtain a single GETDVI item. It builds a descriptor list consisting of the item passed and the terminating descriptor, gets the result and returns it as a string.

In the next article, we will look at the updated GETDVI system call.

 

Copyright © 2020 by Alan Conroy. This article may be copied in whole or in part as long as this copyright is included.