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

DMG_Get_Key and LIB_Put_Formatted_Output

In this article, we will address two new system services used by the HELP CUSP code in the previous article. VMS has a set of services called SMG (Screen Management). SMG provides an abstraction away from various DEC terminals, such as VT100, VT220, VT320, VT420, and the VT500 series. We won't be replicating SMG for UOS because SMG is older technology associated with character-cell monofont devices. Instead, UOS has DMG services (Display Management) which supports HTML text and graphics, as well as character cell terminals. In the future, we may write a few SMG wrappers to the DMG services, but I think that trying to create an entire working SMG service is next to pointless since it is oriented to archaic technology; trying to generalize it fully to DMG is a waste of time.

First the user documentation:

DMG_Get_Key

Parse the next keystroke from an input string.

Format

DMG_Get_Key input result length

Parameters

input
A pointer to an SRB that points to the input string to get the next keystroke from.

result
A pointer to an SRB that points to the buffer to receive the keystroke. This should be large enough to contain any key name that the service might return. The length of the SRB indicates the maximum length, in bytes, of the buffer the SRB points to. On return, the length is updated to the number of bytes returned, which will never be larger than the length passed. If the buffer is too small, as much is returned as allowed by the size of the buffer and the SS_BUFFEROVF warning is returned. If 0 is passed, no result is returned.

length
Pointer to a 64-bit integer to receive the length of the escape sequence or UTF-8 characters for the returned result. If 0 is passed, no length is returned.

Description

DMG_Get_Key returns the next key press from the input string. If the key corresponds to a character, that single character is returned. If the key is a non-character key (such as PAGE DOWN) indicated by an escape code, the name of the key is returned. The following standard keys can be returned by this service:
DELETE
DOWN
END
F0
F1
F2
F3
F4
F5
F6
F7
F8
F9
F10
F11
F12
F13
F14
F15
F16
F17
F18
F19
F20
HOME
INSERT
LEFT
PAGEDOWN
PAGEUP
PF1
PF2
PF3
PF4
RIGHT
SELECT
UP
Not all keyboards have all of these keys and some OEM keyboards may return additional key names.

Condition codes returned:

SS_NORMAL indicates normal completion
SS_BUFFEROVF indicates that the result was larger than the provided buffer

const Max_Key_Mapping = 49 ;

const Key_Mapping : array[ 0..Max_Key_Mapping, 0..1 ] of string =
          (
            ( 'A', 'UP' ),
            ( '[A', 'UP' ),
            ( 'OA', 'UP' ),
            ( 'B', 'DOWN' ),
            ( '[B', 'DOWN' ),
            ( 'OB', 'DOWN' ),
            ( 'C', 'RIGHT' ),
            ( '[C', 'RIGHT' ),
            ( 'OC', 'RIGHT' ),
            ( 'D', 'LEFT' ),
            ( '[D', 'LEFT' ),
            ( 'OD', 'LEFT' ),
            ( 'OP', 'PF1' ),
            ( 'OQ', 'PF2' ),
            ( 'OR', 'PF3' ),
            ( 'OS', 'PF4' ),
            ( '[1~', 'HOME' ), // FIND
            ( '[2~', 'INSERT' ), // INSERT HERE
            ( '[3~', 'DELETE' ), // REMOVE
            ( '[4~', 'SELECT' ),
            ( '[5~', 'PAGEUP' ), // PREV SCREEN
            ( '[6~', 'PAGEDOWN' ), // NEXT SCREEN
            ( '[7~', 'HOME' ),
            ( '[H', 'HOME' ),
            ( '[8~', 'END' ),
            ( '[10~', 'F0' ),
            ( '[11~', 'F1' ), // HOLD
            ( '[1P', 'F1' ),
            ( '[12~', 'F2' ), // PRINT
            ( '[1Q', 'F2' ),
            ( '[13~', 'F3' ), // SETUP
            ( '[1R', 'F3' ),
            ( '[14~', 'F4' ), // SESSION
            ( '[1S', 'F4' ),
            ( '[15~', 'F5' ), // BREAK
            ( '[17~', 'F6' ),
            ( '[18~', 'F7' ),
            ( '[19~', 'F8' ),
            ( '[20~', 'F9' ),
            ( '[21~', 'F10' ),
            ( '[23~', 'F11' ), // ESC
            ( '[24~', 'F12' ), // BS
            ( '[25~', 'F13' ), // LF
            ( '[26~', 'F14' ),
            ( '[28~', 'F15' ), // HELP
            ( '[29~', 'F16' ), // DO
            ( '[31~', 'F17' ),
            ( '[32~', 'F18' ),
            ( '[33~', 'F19' ),
            ( '[34~', 'F20' )
          ) ;
These definitions are used to convert standard escape sequences to key names. The escape character itself is not included in the strings.

function DMG_Get_Key( SRB, Res, Len : int64 ) : int64 ; 

var S, S1, S2 : string ;
    I : int64 ;
    L : integer ;
    U : TUnicode_String ;

begin // DMG_Get_Key
    Result := 0 ;
    S := Get_String( PSRB( SRB )^ ) ;
    if( length( S ) = 0 ) then // Null string
    begin
        if( Len <> 0 ) then
        begin
            PInt64( Len )^ := 0 ;
        end ;
        Write_User( '' ) ;
        exit ;
    end ;
The first thing we do is check to see if the input string is null. If so, we return a null string and 0 length.

    if( copy( S, 1, 1 ) = ESC ) then // Possible escape sequence
    begin
        for L := 0 to Max_Key_Mapping do
        begin
            S1 := Key_Mapping[ L, 0 ] ;
            S2 := Key_Mapping[ L, 1 ] ;
            if( copy( S, 2, length( S1 ) ) = S1 ) then
            begin
                S := S2 ;
                if( Len <> 0 ) then
                begin
                    PInt64( Len )^ := length( S1 ) + 1 ;
                end ;
                Write_User( S ) ;
                exit ;
            end ;
        end ;
    end ;
Next we check for escape sequences. If the first character is an ASCII Escape, we check the following characters against each escape sequence in Key_Mapping. If a match is found, we return the key and length. Otherwise, we drop down through the end of the loop to the following code.

    // Next character is simply the first character of the string...
    U := TUnicode_String.Create ;
    U.Assign_From_String( S, TT_UTF8 ) ;
    U.Length := 1 ;
    S := U.As_String( TT_UTF8 ) ;
    Write_User( S ) ;
    U.Free ;
    if( Len <> 0 ) then
    begin
        PInt64( Len )^ := length( S ) ;
    end ;
end ; // DMG_Get_Key
If we get to this code, it means the input string is not null and doesn't start with an escape sequence. Since UOS treats strings as UTF-8, we have to determine how many bytes constitute the first character. We do this by creating a Unicode instance and assigning the input string to it. We then set the string length to 1 character and then get it back as a UTF-8 string. Finally, we set the result string and length.

    procedure Write_User( S : string ) ;

    begin
        if( Res <> 0 ) then
        begin
            if( PSRB( Res )^.Length < length( S ) ) then
            begin
                setlength( S, PSRB( Res )^.Length ) ;
                Result := UOSErr_Buffer_Overflow ;
            end ;
            PSRB( Res )^.Length := length( S ) ;
            if( PSRB( Res )^.Buffer <> 0 ) then
            begin
                move( PChar( S )[ 0 ], PChar( PSRB( Res )^.Buffer )[ 0 ], length( S ) ) ;
            end ;
        end ;
    end ;
This local function handles the update of the result SRB. First we make sure an address for the SRB was passed, and then make sure that the result buffer is large enough to hold the result. If not, the result string is truncated and the buffer overflow warning is set. Then the result string is written to the SRB buffer.

function Get_Key( S : string ) : string ;

var Res : TSRB ;
    SRB : TSRB ;
    R : string ;

begin
    Set_String( S, SRB ) ;
    R := S ;
    Set_String( R, Res ) ;
    DMG_Get_Key( int64( @SRB ), int64( @Res ), 0 ) ;
end ;
This is the Pascal wrapper for DMG_Get_Key found in PasStarlet.


The next service, Put_Formatted_Output, is used to write HTML text. As we discussed in a past article, there is raw output and cooked output. Raw output is that processed by the terminal (or other output device) itself. Cooked output is handled by the terminal driver in the FIP, which takes care of various translations required to make output look correct on terminals with less features (such as using spaces to simulate tabs). The Put_Output service simply passes text on to the terminal driver.

Put_Formatted_Output, however, is another level of output data cooking that handles converting HTML tags into the appropriate mechanism to best represent the HTML on the output device. For terminals that can only handle plain text, this service will convert the HTML to plain text. On other terminals, special effects may be applied based on the HTML tags. On a PC screen, the HTML is rendered exactly. On some printers, the data may be converted to Postscript. This service does the necessary work and then passes the modified text/commands on to the output device. You can think of this as three layers in the process of cooking output: Put_Formatted_Output passes processed (cooked) text on to the terminal driver via Put_Output. The terminal driver then further processes the text and passes it on to the physical output device.

Most output should be done via Put_Formatted_Output. However, if you want raw output, Put_Output should be used instead. When would raw output be used? This might be used for a terminal that has special processing of output and UOS has no filter for that terminal. In that case, the program would have to make use of the features for that specific device. In fact, this is what an output filter does. Filters will be discussed in the future.

Put_Formatted_Output

Writes HTML formatted output.

Format

Put_Formatted_Output file output

Parameters

file
A pointer to a UOS file to which the data will be written.

output
A pointer to an SRB that points to the string to write to the file.

Description

Put_Formatted_Output writes HTML text to the file in such a way to most closely match the HTML formatting on the output device.

Condition codes returned:

SS_NORMAL indicates normal completion

function LIB_Put_Formatted_Output( F, SRB : int64 ) : int64 ;

var Fil : TCOM_UOS_File ;
    S : string ;

begin
    // Setup...
    Result := 0 ;
    Fil := TCOM_UOS_File( pointer( F ) ) ;
    S := Get_String( PSRB( pointer( SRB ) )^ ) ;

    //TODO: For now, we do plain text output...
    S := From_HTML( S, -1 ) ;

    //TODO: For now, convert to ASCII...
    U := TUnicode_String.Create ;
    U.Assign_From_String( D, TT_UTF8 ) ;
    S := U.As_String( TT_ASCII7 ) ;
    U.Free ;

    // Write string...
    Fil.Write( S ) ;
    UEC := Fil.Get_IO_Error ;
    if( UEC <> nil ) then
    begin
        Result := UEC.Get_Error ;
    end ;
end ;
For now, we simply convert the HTML to plain text. In a future article, we will address converting HTML to the appropriate output based on the output device. We also convert from unicode to 7-bit ASCII. In the future, we will address handling Unicode output.

function Put_Formatted_Output( F : TCOM_UOS_File ; const S : string ) : int64 ;

var P : string ;
    SRB : TSRB ;

begin
    P := S ;
    Set_String( P, SRB ) ;
    Result := LIB_Put_Formatted_Output( int64( @F ), int64( @SRB ) ) ;
end ;
This is the Pascal wrapper for LIB_Put_Formatted_Output, in PasStarlet.

In the next article, we will look at the next CUSP.