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
103 GETJPI
104 Lexical functions: F$GETSYI
105 GETSYI
106 Lexical functions: F$INTEGER, F$LENGTH, F$LOCATE, and F$MATCH_WILD
107 Lexical function: F$PARSE
108 FILESCAN
109 SYS_PARSE
110 Lexical Functions: F$MODE, F$PRIVILEGE, and F$PROCESS
111 File Lookup Service
112 Lexical Functions: F$SEARCH
113 SYS_SEARCH
114 F$SETPRV and SYS_SETPRV
115 Lexical Functions: F$STRING, F$TIME, and F$TYPE
116 More on symbols
117 Lexical Functions: F$TRNLNM
118 SYS_TRNLNM, Part 2
119 Lexical functions: F$UNIQUE, F$USER, and F$VERIFY
120 Lexical functions: F$MESSAGE
121 TUOS_File_Wrapper
122 OPEN, CLOSE, and READ system services

UCL Commands
123 WRITE
124 Symbol assignment
125 The @ command
126 @ and EXIT
127 CRELNT system service
128 DELLNT system service
129 IF...THEN...ELSE
130 Comments, labels, and GOTO
131 GOSUB and RETURN
132 CALL, SUBROUTINE, and ENDSUBROUTINE
133 ON, SET {NO}ON, and error handling
134 INQUIRE
135 SYS_WRITE Service
136 OPEN
137 CLOSE
138 DELLNM system service
139 READ
140 Command Recall
141 RECALL
142 RUN
143 LIB_RUN
144 The Data Stream Interface
145 Preparing for execution
146 EOJ and LOGOUT
147 SYS_DELPROC and LIB_GET_FOREIGN

CUSPs and utilities
148 The I/O Queue
149 Timers
150 Logging in, part one
151 Logging in, part 2
152 System configuration
153 SET NODE utility
154 UUI
155 SETTERM utility
156 SETTERM utility, part 2
157 SETTERM utility, part 3
158 AUTHORIZE utility
159 AUTHORIZE utility, UI
160 AUTHORIZE utility, Access Restrictions
161 AUTHORIZE utility, Part 4
162 AUTHORIZE utility, Reporting
163 AUTHORIZE utility, Part 6
164 Authentication
165 Hashlib
166 Authenticate, Part 7
167 Logging in, part 3
168 DAY_OF_WEEK, CVT_FROM_INTERNAL_TIME, and SPAWN
169 DAY_OF_WEEK and CVT_FROM_INTERNAL_TIME
170 LIB_SPAWN
171 CREPRC
172 CREPRC, Part 2
173 COPY
174 COPY, part 2
175 COPY, part 3
176 COPY, part 4
177 LIB_Get_Default_File_Protection and LIB_Substitute_Wildcards
178 CREATESTREAM, STREAMNAME, and Set_Contiguous
179 Help Files
180 LBR Services
181 LBR Services, Part 2
182 LIBRARY utility
183 LIBRARY utility, Part 2
184 FS Services
185 FS Services, Part 2
186 Implementing Help
187 HELP
188 HELP, Part 2
189 DMG_Get_Key and LIB_Put_Formatted_Output
190 LIBRARY utility, Part 3
191 Shutting Down UOS
192 SHUTDOWN
193 WAIT
194 SETIMR
195 WAITFR and Scheduling
196 REPLY, OPCOM, and Mailboxes
197 REPLY utility
198 Mailboxes
199 BRKTHRU
200 OPCOM

Glossary/Index


Downloads

Lexical Functions - F$TRNLNM

This lexical function makes use of the TRNLNM system service, which uses the symbol tables, including the new features we've added in the previous article. Remember that, in UOS, symbols and logicals are the same thing, whereas in VMS they are separate. Here is the definition for F$TRNLNM.

F$TRNLNM translates a symbol name and returns the equivalence name string or the requested attributes of the specified symbol name.

Format
F$TRNLNM( name {, table {, index {, mode {, case {, item}}}}} )

Return Value
A character string containing the equivalence name or requested attribute of the symbol name. If no match is found, null is returned.

Arguments
name

a string containing the name of the symbol/logical to translate.

table

A string containing the name of the symbol table that F$TRNLNM should search to translate the symbol name. If no table is specified, F$TRNLNM searches the process, job, group, system, and cluster symbol tables, in that order.

index

The index of the equivalence value to return. The first equivalence value is index 0, which is the default used if this option is omitted or null.

mode

A string containing one of the following access modes:
USERUser mode (ring 3). This is the default.
SUPERVISORSupervisor mode (ring 2).
DEVICEDevice mode (ring 1).
EXECUTIVEAn alternate value for DEVICE, provided for compatibility with VMS.
KERNELKernel mode (ring 0).

When a table is being searched for a symbol, a symbol with the specified mode is looked for first. If not found, the next lower level access mode is looked for, and so forth down to Kernel mode.

case

A string containing any of the following items, delimited by commas. If omitted or a null string is specified, the defaults are used.
CASE_BLINDDefault. The first symbol matching the name is used, regardless of the case of the symbol name.
CASE_SENSITIVEThe symbol must match the name exactly, including case, to be returned.
INTERLOCKEDWait to complete lookup until any current clusterwide symbol changes are finished.
NONINTERLOCKEDDefault. Symbol lookup occurs without waiting for any clusterwide symbol changes to finish.

item

A string containing one of the following items. If omitted or a null string is specified, the item defaults to "VALUE".
ACCESS_MODEThe access mode associated with the symbol. One of the following: USER, SUPERVISOR, EXECUTIVE, KERNEL.
CLUSTERWIDETRUE or FALSE to indicate if the symbol is in a clusterwide symbol table.
CONCEALEDTRUE or FALSE to indicate if the CONCEALED attribute is set for the symbol.
CONFINETRUE or FALSE to indicate if the symbol is confined (not copied to subprocesses).
CRELOGTRUE or FALSE to indicate if the symbol was defined with the CRELOG system service.
LENGTHLength of the value (equivalence name) of the specified symbol.
MAX_INDEXLargest index for the symbol's equivalence values.
NAMEThe case-sensitive name of the found symbol.
NO_ALIASTRUE or FALSE to indicate if the NO_ALIAS flag is set for the symbol.
TABLETRUE or FALSE to indicate whether the symbol name is the name of a symbol table.
TABLE_NAMEThe name of the table in which the symbol was found.
TERMINALTRUE or FALSE to indicate if the TERMINAL flag is set for the symbol.
VALUEThe symbol's value. If the symbol has multiple equivalence values, the equivalence value associated with the specified index is returned.

Description
F$TRNLNM uses the TRNLNM system service to translate a symbol and return the equivalence name value, or other requested data. The translation is not iterative.

You can omit optional arguments to the right of the last specified argument. Any arguments to the left can be omitted, but the comma delimiter must be included.

Examples
$ A = F$TRNLNM("a","LNM$PROCESS",,,,"NAME")
This would return the case-sensitive name of the symbol whose normalized (upper case) name is A. If A is not defined, a null string is returned.

        Function_TRNLNM : begin
                              if( Missing_Parentheses( '(' ) ) then
                              begin
                                  exit ;
                              end ;
                              if( Process_TRNLNM( Err, Context ) ) then
                              begin
                                  exit ;
                              end ;
                              if( Missing_Parentheses( ')' ) ) then
                              begin
                                  exit ;
                              end ;
                              S := Context ;
                          end ;
This code is added to the Function_Reference.

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

var I : int64 ;
    AcMode, Attr, Flags, Item_Code, Index : integer ;
    CS, Item, Mode, Name, S, Table : string ;
    ItemType : TItemType ;

begin
    // Setup...
    Result := False ; // Assume no problems
    Context := '' ;
This new function will process the lexical function. This is the typical setup for these kind of functions.

    // Get parameters...
    Name := trim( Get_Parameter( Err, Context ) ) ;
    if( Err <> 0 ) then
    begin
        exit ;
    end ;
    if( length( Name ) = 0 ) then
    begin
        exit ;
    end ;
    if( Parser.Peek = ',' ) then
    begin
        Get_Token ; // Eat comma
        Table := trim( Get_Parameter( Err, Context ) ) ;
        if( Err <> 0 ) then
        begin
            exit ;
        end ;
        if( Parser.Peek = ',' ) then
        begin
            Get_Token ; // Eat comma
            Index := Get_Numeric_Parameter( Err, Context ) ;
            if( Err <> 0 ) then
            begin
                exit ;
            end ;
            if( Parser.Peek = ',' ) then
            begin
                Get_Token ; // Eat comma
                Mode := uppercase( trim( Get_Parameter( Err, Context, True ) ) ) ;
                if( Err <> 0 ) then
                begin
                    exit ;
                end ;
                if( Parser.Peek = ',' ) then
                begin
                    Get_Token ; // Eat comma
                    CS := uppercase( trim( Get_Parameter( Err, Context, True ) ) ) ;
                    if( Err <> 0 ) then
                    begin
                        exit ;
                    end ;
                    if( Parser.Peek = ',' ) then
                    begin
                        Get_Token ; // Eat comma
                        Item := uppercase( trim( Get_Parameter( Err, Context, True ) ) ) ;
                        if( Err <> 0 ) then
                        begin
                            exit ;
                        end ;
                    end ;
                end ;
            end ;
        end ;
    end ; // if( Parser.Peek = ',' )
First, we obtain all of the parameters.

    // Process access mode...
    if( ( Mode = '' ) or ( Mode = 'USER' ) ) then
    begin
        Mode := 'USER' ;
        AcMode := PSL_C_USER ;
    end else
    if( Mode = 'SUPERVISOR' ) then
    begin
        AcMode := PSL_C_SUPER ;
    end else
    if( ( Mode = 'EXECUTIVE' ) or ( Mode = 'DEVICE' ) ) then
    begin
        AcMode := PSL_C_DRIVER ;
    end else
    if( Mode = 'KERNEL' ) then
    begin
        AcMode := PSL_C_KERNEL ;
    end else
    begin
        Err := UCL_IVKEYW ;
        Context := Mode ;
        exit ;
    end ;

    // Process attributes...
    Attr := LNM_M_CASE_BLIND ;
    while( CS <> '' ) do
    begin
        I := pos( ',', CS + ',' ) ;
        S := copy( CS, 1, I - 1 ) ;
        CS := copy( CS, I + 1, length( CS ) ) ;
        if( S <> '' ) then
        begin
            if( S = 'CASE_BLIND' ) then
            begin
                Attr := Attr or LNM_M_CASE_BLIND ;
            end else
            if( S = 'CASE_SENSITIVE' ) then
            begin
                Attr := Attr and not LNM_M_CASE_BLIND ;
            end else
            if( S = 'INTERLOCKED' ) then
            begin
                Attr := Attr or LNM_M_INTERLOCKED ;
            end else
            if( S = 'NONINTERLOCKED' ) then
            begin
                Attr := Attr and not LNM_M_INTERLOCKED ;
            end else
            begin
                Err := UCL_IVKEYW ;
                Context := S ;
                exit ;
            end ;
        end ;
    end ;

    // Process Item...
    ItemType := IT_String ;
    Flags := 0 ;
    if( Item = 'ACCESS_MODE' ) then
    begin
        ItemType := IT_Integer ;
        Item_Code := LNM_ACMODE ;
    end else
    if( Item = 'CLUSTERWIDE' ) then
    begin
        Flags := LNM_M_CLUSTERWIDE ;
    end else
    if( Item = 'CONCEALED' ) then
    begin
        Flags := LNM_M_CONCEALED ;
    end else
    if( Item = 'CONFINE' ) then
    begin
        Flags := LNM_M_CONFINE ;
    end else
    if( Item = 'CRELOG' ) then
    begin
        Flags := LNM_M_CRELOG ;
    end else
    if( Item = 'LENGTH' ) then
    begin
        ItemType := IT_Integer ;
        Item_Code := LNM_LENGTH ;
    end else
    if( Item = 'MAX_INDEX' ) then
    begin
        ItemType := IT_Integer ;
        Item_Code := LNM_MAX_INDEX ;
    end else
    if( Item = 'NO_ALIAS' ) then
    begin
        Flags := LNM_M_NO_ALIAS ;
    end else
    if( Item = 'TABLE' ) then
    begin
        Flags := LNM_M_TABLE ;
    end else
    if( Item = 'TABLE_NAME' ) then
    begin
        Item_Code := LNM_TABLE ;
    end else
    if( Item = 'TERMINAL' ) then
    begin
        Flags := LNM_M_TERMINAL ;
    end else
    if( Item = 'VALUE' ) then
    begin
        Item_Code := LNM_STRING ;
    end else
    if( Item = 'NAME' ) then
    begin
        Item_Code := LNM_NAME ;
    end else
    if( Item = '' ) then // Default
    begin
        Item_Code := LNM_STRING ;
    end else
    begin
        Err := UCL_IVKEYW ;
        Context := Item ;
        exit ;
    end ;
Next, we validate the parameters and default any that were omitted. We use the same approach as for previous lexical functions (such as F$GETSYI), setting an item type for each item.

    // Get value...
    if( Flags <> 0 ) then // Obtain a flag
    begin
        S := Get_TRNLNM( LNM_ATTRIBUTES, Attr, Table, Name, AcMode ) ;
        I := Get_Integer_From_String( S ) ;
        if( ( I and Flags ) = 0 ) then
        begin
            Context := 'FALSE' ;
        end else
        begin
            Context := 'TRUE' ;
        end ;
        exit ;
    end ;
If Flags is non-zero, it indicates an attribute flag to check (which implies a boolean item type). So, we call the TRNLNM function to obtain the symbol attributes. Then we convert to an integer value and compare the flags. We return TRUE or FALSE, as appropriate, and exit.

    S := Get_TRNLNM( Item_Code, Attr, Table, Name, AcMode ) ;
    if( ItemType = IT_Integer ) then
    begin
        I := Get_Integer_From_String( S ) ;
        S := inttostr( I ) ;
        if( Item_Code = LNM_ACMODE ) then
        begin
            case I of
                PSL_C_KERNEL : S := 'KERNEL' ;
                PSL_C_EXEC : S := 'EXECUTIVE' ;
                PSL_C_SUPER : S := 'SUPERVISOR' ;
                else S := 'USER' ;
            end ;
        end ;
    end ;
    Context := S ;
end ; // Process_TRNLNM
Otherwise, we obtain the requested item from TRNLNM. If the item is an integer type, we convert the string to an integer, otherwise we return the string as-is. In the case of an integer for item code LNM_ACMODE, we translate the integer value into one of the values: KERNEL, EXECUTIVE, SUPERVISOR, USER. Note that we return "SUPERVISOR" instead of "DEVICE" for compatibility with VMS.

function Get_TRNLNM( Code, attr : int64 ; tabnam, lognam : string ;
    acmode : int64 = 3 ) : string ;

var PP_SYS_Descriptor : array[ 0..1 ] of TSYS_Descriptor ;

begin
    BufLen := sizeof( Buf ) ;
    fillchar( PP_SYS_Descriptor, sizeof( PP_SYS_Descriptor ), 0 ) ;
    PP_SYS_Descriptor[ 0 ].Buffer_Length := sizeof( Buf ) ;
    PP_SYS_Descriptor[ 0 ].Item_Code := Code ; // TRNLNM item
    PP_SYS_Descriptor[ 0 ].Buffer_Address := integer( @Buf ) ;
    PP_SYS_Descriptor[ 0 ].Return_Length_Address := integer( @BufLen ) ;
    TRNLNM( Attr, Tabnam, Lognam, AcMode, integer( @PP_SYS_Descriptor ) ) ;
    setlength( Result, BufLen ) ;
    move( Buf[ 0 ], PChar( Result )[ 0 ], BufLen ) ;
end ;
This new function is the TRNLNM equivalent of other interface functions such as Get_JPI. It is a simplified function that returns the value for a single item. It sets up the descriptor list and calls the system service, then returns the result as a string.

In the next article, we will examine the TRNLNM system service.

 

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