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 UCL Command execution
62 UCL Command execution, part 2
63 UCL Command Abbreviation
64 ASTs
65 UCL Expressions, Part 1
66 UCL Expressions, Part 2: Support code
67 UCL Expressions, part 3: Parsing
68 SYS_GETJPIW and SYS_TRNLNM
69 UCL 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 UCL Lexical functions: F$GETDVI
98 Parse_GetDVI

Glossary/Index


Download sources
Download binaries

LIB_FAO and LIB_FAOL

As we did for the date/time formatting functions, we will start in the executive and then move up to the UCL usage of the FAO service. This is because UCL uses a subset of the functions that FAO offers and I think it makes more sense to talk about the full service before we talk about the subset of functionality that UCL offers.

LIB_FAO performs string formatting. As with the date/time formatting functions, VMS put the FAO service in the executive. Again, I disagree with that approach. First, it makes the executive larger than it needs to be. Second, it is less efficient due to the overhead of calling across rings and mapping user memory in the executive to access the data. So UOS puts the FAO service in starlet. Thus, although we put FAO in the SYS unit in order to be compatible with VMS, the SYS unit's FAO function simply redirects to starlet.

There are two related FAO functions: LIB_FAO and LIB_FAOL. The only difference between them is that LIB_FAOL is passed a buffer of raw data while LIB_FAO passes a parameter list. Otherwise, the behavior of the two routines is identical. Note that FAO stands for "Formatted ASCII Output", but it should be understood by now that we are formatting UTF-8.

VMS allows address and integer directives. UOS makes no distinction between them. UOS supports both directive types, but they operate the same. It is possible that, on some architectures, an address is formatted differently than a linear address space. In such a case, this code might need to be altered to use the proper display for addresses.

The !%U directive is used to convert to a VMS-style UIC specification. UOS uses simple integers for UICs, so the directive simply inserts the integer value. Note also that UOS adds binary directives - they are not in VMS.

One more addition added in UOS is the support for TSRB structures. VMS uses structures called "descriptors" to pass data around. String descriptors are used to pass various formats of strings. UOS supports this for compatibility with VMS, but generally it uses the TSRB structure to pass string data. So we added support for strings passed via TSRB. Here is the description of the routines.

FAO and FAOL format parameters consisting of strings and integer values, according to directives embedded in a control string. The output is the control string with substitutions made depending upon the embedded directives and the parameter values.

FAO can take up to 17 parameters in the function call. FAO is passed a pointer to an array of parameters.

Format
LIB_FAO( control, outlen, outbuf, {p1..p17} )
LIB_FAOL( control, outlen, outbuf, parameters )

Arguments
control

Contains the text to be output, together with one or more FAO directives. Each directive begins with an exclamation point (!). To include a literal exclamation point, the !! directive must be used. There is no limit to the size of the string or how many directives it contains. The valid directives are listed below.

outlen

Defines the address of the maximum output buffer size (an 1nt64) on call. On return, the actual size of the data written to the output buffer is written to the address. Note that the output will never exceed the value at the time the function is called.

outbuf

Defines the address of the output buffer. The converted control string is written here.

p1..p17

Up to 17 64-bit integer values that can represent actual data or pointers to string data. There must be one value for each directive in the string. If the string requires more than are supplied, the missing parameters are assumed to be 0. Not all directives require a parameter, and some constructs may require up to three. Extra parameters are ignored. The parameters are processed sequentially as the control string is processed from left to right. If more than 17 parameters are required, use the LIB_FAOL function instead.

parameters

A pointer to an array of 64-bit integer values that can represent actual data or pointers to string data. There must be one value for each directive in the string. If the string requires more than are supplied, the behavior of the function is undefined, but will probably cause an error. Not all directives require a parameter, and some constructs may require up to three. Extra parameters are ignored. The parameters are processed sequentially as the control string is processed from left to right.

Description
FAO converts integer values into binary, octal, decimal, or hexadecimal values, and can insert strings, and conditionally process directives. See the section below, describing the directives.

FAO Directives
FAO directives can appear anywhere in the control string and have the general form:
!ZZ
where the exclamation point (!) indicates the start of the directive and "ZZ" indicates a 1- or 2-character FAO directive. All alphabetic characters in a directive must be uppercase.

Width
FAO directives optionally can have a width, using this format:
!nZZ
where "n" is the decimal value specifying the width (in characters) for the value substituted for the directive. Example:
!3XB
This would display an integer byte values as hexadecimal (XB) with a width of 3 digits (it is zero-filled on the left).

Repeat
FAO directives optionally can have a repeat count, using this format:
!n(ZZ)
where "n" is the decimal value specifying the number of times that the directive is to be repeated. If the directive requires one or more parameters, sucessive parameters are used for each repetition - the same parameter is not reused for each repetition. Example:
!3(OB)
This would display 3 integer byte values as octal (OB).

Repeat with width
You can specify both a width and a repeat count, using this format:
!n(mZZ)
where "n" is the decimal value specifying the number of times that the directive is to be repeated and "m" is the decimal value specifying the with of the directive output, in characters. Example:
!5(10BB)
This would display five integer byte values as binary (BB), each of which is 10 characters wide.

Variable repeats and widths
You can specify either, or both, a width and a repeat count as variables by using a number sign (#) in place of the decimal value. When such a directive is processed, the next parameter is used in place of the number sign. Example:
!2(#BB)
This would display 2 integer byte values as binary, each of which is a number of characters wide that is defined by the next parameter. Note that even though the directive is repeated, only a single parameter is used for the width - the same width will be used for all iteraions.
!#(OB)
This would display a number of octal values equal to the next parameter.
!#(#OB)
This will read one parameter that will serve as the repeat count, and one more parameter for the width of each octal value output.

Indirect parameters
All string parameters are considered to be addresses of the data. All numeric parameters are assumed to be the actual value. A full 64-bits are required for each parameter value, even if less than 64-bits are required by the directive (the remaining bits are ignored). However, using the indirection symbol (@) in a directive, FAO can be made to treat a parameter as an address that contains the numeric value. Note that only the required number of bytes are read from that address. Example:
[email protected]
In this case, the next parameter is used as an address to a quadword (64-bit) value.

FAO Directives
String Directives:
DirectiveDescription
!ABInserts a string. The parameter is a pointer to a TSRB structure.
!ACInserts a string. The parameter is a pointer to a string whose first byte is the length of the string, followed immediately by that many bytes if text.
!ADInserts a string, with periods (.) substituted for all nonprintable ASCII codes. Two parameters are required: the first is the length of the string and the second is the address of the string data.
!AFInserts a string. Two parameters are required: the first is the length of the string and the second is the address of the string data.
!ASInserts a string. The parameter is the address of a string descriptor for a CLASS_S (static) or CLASS_D (dynamic) string.
!AZInserts a string. The parameter is a pointer to a zero-terminated (ASCIZ) string.
Note: All string lengths indicate number of bytes, not number of characters.

Zero-filled Numeric Directives:
DirectiveDescription
!BBConvert a byte value to the ASCII representation of that value in base 2. Only the low byte of the parameter is used.
!BWConvert a word value to the ASCII representation of that value in base 2. Only the lower two bytes of the parameter are used.
!BLConvert a longword value to the ASCII representation of that value in base 2. Only the lower four bytes of the parameter are used.
!BQConvert a quadword value to the ASCII representation of that value in base 2.
!OBConvert a byte value to the ASCII representation of that value in base 8. Only the low byte of the parameter is used.
!OWConvert a word value to the ASCII representation of that value in base 8. Only the lower two bytes of the parameter are used.
!OLConvert a longword value to the ASCII representation of that value in base 8. Only the lower four bytes of the parameter are used.
!OQConvert a quadword value to the ASCII representation of that value in base 8.
!OASame as !OQ.
!OISame as !OL.
!OHSame as !OQ.
!OJSame as !OQ.
!XBConvert a byte value to the ASCII representation of that value in base 16. Only the low byte of the parameter is used.
!XWConvert a word value to the ASCII representation of that value in base 16. Only the lower two bytes of the parameter are used.
!XLConvert a longword value to the ASCII representation of that value in base 16. Only the lower four bytes of the parameter are used.
!XQConvert a quadword value to the ASCII representation of that value in base 16.
!XASame as !XQ.
!XISame as !XL.
!XHSame as !XQ.
!XJSame as !XQ.
!ZBConvert a byte value to the ASCII representation of that value in base 10. Only the low byte of the parameter is used.
!ZWConvert a word value to the ASCII representation of that value in base 10. Only the lower two bytes of the parameter is used.
!ZLConvert a longword value to the ASCII representation of that value in base 10. Only the lower four bytes of the parameter is used.
!ZQConvert a quadword value to the ASCII representation of that value in base 10.
!ZASame as !ZQ.
!ZISame as !ZL.
!ZHSame as !ZQ.
!ZJSame as !ZQ.

Blank-filled Numeric Directives:
DirectiveDescription
!UBConvert an unsigned byte value to the ASCII representation of that value in base 10. Only the low byte of the parameter is used.
!UWConvert an unsigned word value to the ASCII representation of that value in base 10. Only the lower two bytes of the parameter are used.
!ULConvert an unsigned longword value to the ASCII representation of that value in base 10. Only the lower four bytes of the parameter are used.
!UQConvert an unsigned quadword value to the ASCII representation of that value in base 10.
!UASame as !UQ.
!UISame as !UL.
!UHSame as !UQ.
!UJSame as !UQ.
!SBConvert a signed byte value to the ASCII representation of that value in base 10. Only the low byte of the parameter is used.
!SWConvert a signed word value to the ASCII representation of that value in base 10. Only the lower two bytes of the parameter are used.
!SLConvert a signed longword value to the ASCII representation of that value in base 10. Only the lower four bytes of the parameter are used.
!SQConvert a signed quadword value to the ASCII representation of that value in base 10.
!SHSame as !SL.
!SJSame as !SL

Other Directives:
DirectiveDescription
!/Inserts a new line (carriage return and linefeed). It takes no parameters.
!_Inserts a horizontal tab (ASCII 9). It takes no parameters.
!^Inserts a form feed. It takes no parameters.
!!Inserts an exclamation point. It takes no parameters
!%SInserts the letter S if the most recently converted numeric value is not 1. If the character before the directive is upper case, an upper case S is inserted, otherwise a lowercase s is inserted.
!%TInserts the system time. The parameter is the datetime stamp. If the parameter is 0, the current time is inserted.
!%USame as !UQ.
!%IConverts a UIC to the account name. If an invalid UIC is specified, the directive is treated as !UQ.
!%DInserts the system date and time. The parameter is the timestamp. If the parameter is 0, the current date/time is inserted.
!n%CConditional. See discussion of conditionals below.
!%EElse portion of conditional. See discussion of conditionals below.
!%FEnd of conditional. See discussion of conditionals below.
!n<See next directive.
!>The preceeding directive and this one are used together to define an output field that has a width of n. Within this field are displayed all directives between the !n< and !> directives. The field is blank-filled on the right to make it n characters wide if necessary. All directives within this field are left-justified and blank-filled. Note that these can be nested.
!n*cRepeats the character c in the output n times.
!-Reuse the most recently used parameter value.
!+Skip the next parameter value.

Conditionals
!%nC, !%E, and !%F are used together to insert values depending upon parameter values. This is primarily for use with plurals. The general format is:
!%nCa!%Eb!%F
If n matches the last parameter value, then a is inserted, otherwise b is inserted. Example:
!ZB !%1Cchild!%Echildren!%F
In this example, if the first parameter is 1, the output would be:
1 child
But if the first parameter is not 1, the output would be:
n children
where "n" is the value of the first parameter.

The following table illustrates how the directives interact with width and filling.
Directive TypeDefault output widthWhen explicit width is greater than defaultWhen explicit width is less than default
!BB8Right justify and blank fillResult truncated on left
!BW16Right justify and blank fillResult truncated on left
!BL32Right justify and blank fillResult truncated on left
!BQ64Right justify and blank fillResult truncated on left
!OB3Right justify and blank fillResult truncated on left
!OW6Right justify and blank fillResult truncated on left
!OL11Right justify and blank fillResult truncated on left
!OQ22Right justify and blank fillResult truncated on left
!HB2Right justify and blank fillResult truncated on left
!HW4Right justify and blank fillResult truncated on left
!HL8Right justify and blank fillResult truncated on left
!HQ16Right justify and blank fillResult truncated on left
Unsigned zero-filled decimalAs many characters as are necessaryRight justify and blank fillField completely filled with asterisks (*)
Signed or unsigned deciumalAs many characters as are necessaryRight justify and zero-filled
StringsAs many characters as in the stringLeft justify and blank fill to specified lengthTruncate on right

In the next article, we'll look at the code that implements the FAO service.

 

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