| 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
 201 Mailbox Services
 202 Mailboxes, Part 2
 203 DEFINE
 204 CRELNM
 205 DISABLE
 206 STOP
 207 OPCCRASH and SHUTDOWN
 208 APPEND
 209 APPEND and CONTINUE
 
 Glossary/Index
 
 
 Downloads
 
 | AUTHORIZE utility, Part 4 
In the last article, we looked at various support routines.  In this article we will
look at the code that implements the RENAME and REMOVE commands, and at the code that
prepares for the handling of the other commands.
 
 
The Run procedure, as in other CUSPs, is the entry point when running the program
(as opposed to calling it within another program).  This is what we've seen before:
we get any default settings and pass them along with the command line to the callable
interfaceunit Authorizemain ;
interface
function Run : int64 ;
function Authorize_SET( Command, Defaults : PChar ; Standalone : boolean ) : int64 ;
implementation
uses // Delphi...
     sysutils, // inttostr
     // C&C...
     _ASCII, // CR
     _UE, // TUnified_Exception
     Misc, // Space
     Parse, // Parse_Switch
     Ustrings, // Left
     UI_Compiler, // TUUI
     _Unicode, // TT_UTF8
     Unicode, // WC_Match
     // UOS...
     _Starlet, // TCOM_UOS_File
     _UOS, // TSRB
     OS_UOS, // TOS_UOS
     PasStarlet, // Get_Command_With_Timeout
     _Stores, // TStore_Address64
     Starlet, // LIB_RUN
     Sys, // SYS_EXIT
     SysUAF, // Get_User
     _UOS_File_System, // TUOS_File
     UOS_Util ; // TStringList
type TOperation = ( Op_None, Op_Modify, Op_Copy ) ;
var Buf : array[ 0..1023 ] of char ;
    BufLen : int64 ;
    Highlight : integer = 0 ;
    IOSB : TIOSB ;
    Operation : TOperation ;
    Source_UIC : integer ;
function Run : int64 ;
var C : string ;
    OS : POS_UOS ;
begin
    OS := new( POS_UOS, Init ) ;
    C := LIB_Get_Symbol( 'authorize$defaults' ) ;
    Result := Authorize_SET( PChar( OS^.Command_Line ), PChar( C ), True ) ;
    if( Result <> 0 ) then
    begin
        OS^.OutputLn( 0, LIB_Get_Exception_Text( 0, Result ) ) ;
    end ;
    OS.Free ;
    SYS_EXIT( 0 ) ;
end ;
 Authorize_SET.  If that returns with an error, we display the
error.  Either way, we clean up and exit.
TOperationis used to indicate which operation we are performing. 
 
This is the callable interface for Authorize.  It first looks for the SYSUAF symbol.
If not found, it defaults to the current UOS boot folder.  Next we check to see if
the file exists.  If not, we indicate such to the user (if we're in stand-alone mode),
and then create a new file.function Authorize_SET( Command, Defaults : PChar ; Standalone : boolean ) : int64 ;
var Component : TUUI_Component ;
    Flags_To_Set, Flags_To_Reset : int64 ;
    F : TCOM_UOS_File ;
    File_Wrapper : TUOS_File ;
    D : string ;
    P : int64 ;
    C, S : string ;
    OS : POS_UOS ;
    UEC : TUnified_Exception ;
begin
    S := LIB_Get_Symbol( 'sysuaf' ) ;
    if( S = '' ) then
    begin
        S := 'sys$boot:\uos\sysuaf.dat' ;
    end ;
    if( not File_Exists( S ) ) then
    begin
        if( Standalone ) then
        begin
            OS := new( POS_UOS, Init ) ;
            OS^.Outputln( RH_SysError, '%UAF-E-NAOFIL, unable to open SYSUAF.DAT, creating a new one' ) ;
        end ;
        F := Open_Binary_File( S, FM_RW or FAB_V_CIF ) ;
        if( F.IO_Error <> nil ) then
        begin
            Result := F.IO_Error.Get_Error ;
            F.Free ;
            exit ;
        end ;
        F.Free ;
    end ;
 
 
Next, we open the file, create a wrapper for it, as discussed in the previous article,
and then set the SYSUAF file (in the SYSUAF module) to this wrapper.  If there is an
error, we exit.    F := Open_Binary_File( S, FM_RW ) ;
    if( F.IO_Error <> nil ) then
    begin
        Result := F.IO_Error.Get_Error ;
        F.Free ;
        exit ;
    end ;
    File_Wrapper := Create_UOS_File_Wrapper( F ) ;
    UEC := Set_Sysuaf_File( File_Wrapper ) ;
    if( UEC <> nil ) then
    begin
        Result := UEC.Get_Error ;
        exit ;
    end ;
 
 
Next, we create a UUI instance and set the prompt variable value.  Then we set the
UI definition, which we included a couple of articles ago.  If there was an error
processing the UI, we return the error and exit.  Otherwise, we insert the default
switches prior to any existing command-line switches (or at the end of the command-line
if no switches).  Then we set the command line and a responder.  We will cover the
responder in a bit.  This is a feature of the UUI that we introduce here.  The UUI
makes calls to a responder (if defined) at certain points to allow customization
of UI handling - because no matter how flexible the UUI is, there will always be some
situation that it doesn't cover.  Thus, it only handles common UOS UI issues and leaves
handling of the exceptional circumstances to those programs that need them.    // Setup...
    Result := 0 ;
    UUI := TUUI.Create ;
    UUI.Set_Variable( '$prompt', 'UAF> ' ) ;
    UUI.Definition := UI ;
    S := UUI.Error ;
    if( S <> '' ) then
    begin
        OS^.Outputln( RH_SysError, S ) ;
        OS^.Outputln( RH_SysError, UUI.Error_Line ) ;
        exit ;
    end ;
    D := Defaults ;
    // Prepend command line with defaults...
    P := Switch_Present( Command ) ;
    if( P = 0 ) then
    begin
        P := length( Command ) + 1 ;
    end ;
    C := copy( Command, 1, P - 1 ) + D + copy( Command, P, length( Command ) ) ;
    UUI.Command_Line := PChar( C ) ;
    UUI.Responder := TAuth_Responder.Create ;
 
 
Finally, we execute the UI and return any errors upon return.    // Processing...
    UUI.Execute( '', Standalone ) ;
    Result := Error_Code ;
end ; // Run
 
 
TheTUUI_Responder = class
                     public // API...
                         function Callback( Component : TUUI_Component ;
                             Action : TAction ; Command : PChar ;
                             var Abort : boolean ; var Handled : boolean ) : PChar ;
                             virtual ; abstract ;
                         function Post_Processing : boolean ;
                             virtual ; abstract ;
                 end ;
const Highlight_Blink = 1 ;
const Highlight_Bold = 2 ;
const Highlight_Reverse = 3 ;
const Highlight_Underline = 4 ;
const Pages_Clear_Screen = -1 ;
const Pages_Scroll = -2 ;
type TAuth_Responder = class( TUUI_Responder )
                           public // API...
                               Auth_Command : string ; // Authorize command used
                               Target : string ; // Target username
                               Temp : string ;
                               function Callback( Component : TUUI_Component ;
                                   Action : TAction ; Command : PChar ;
                                   var Abort : boolean ;
                                   var Handled : boolean ) : PChar ; override ;
                               function Post_Processing : boolean ; override ;
                       end ;
 TUUI_Responderclass is what the UUI uses to handle customization.TAuth_Responderis the implementation of this class for Authorize.
If there are any actions defined and a responder set, the UUI calls the responder'sCallbackmethod.  This is called after the UI definition is parsed and
before the command line is processed.  The method takes the current command line and
can return a modified command line back to UUI.  If Abort is set to true, the UUI
processing is aborted.  This is only used if there was a serious error.Handledis set to true if the responder handles the current command line and false to allow
the UUI to process the returned command line.  Unless handled, the method typically
returns the command line that was passed.Commandcontains the name of
the action component that matches the command in the command line.  Action indicates the
type of callback (we ignore that for now).
Post_Processingis called after the command line is processed.  It takes
no parameters and returns true if the post processing is successful and false if there
was an error.  In the case of an error, the UUI will exit. 
 
This method starts with processing any/all access modifiers - which are not handled
by the UUI due to being rather complicated.  First we set up things, including setting the operation tofunction TAuth_Responder.Callback( Component : TUUI_Component ;
    Action : TAction ; Command : PChar ; var Abort : boolean ;
    var Handled : boolean ) : PChar ;
var C, P, S, Other_Switches : string ;
    I : integer ;
    U : TUser ;
begin
    // Set up...
    Result := nil ;
    C := Command ;
    Access_Switches := '' ;
    Other_Switches := '' ;
    Operation := Op_None ;
 Op_Noneto indicate that there is no further processing to be done, which we will set under
certain circumstances.
 
This loop pulls all access restriction switches out of the command line, placing them
in the    // Handle access switches...
    while( true ) do
    begin
        S := Next_Switch( C, P ) ;
        if( S = '' ) then
        begin
            break ;
        end ;
        S := '/' + S ;
        if( MinMatch( '/ACCESS', S, 5 )
            or
            MinMatch( '/NOACCESS', S, 7 )
            or
            MinMatch( '/BATCH', S, 3 )
            or
            MinMatch( '/INTERACTIVE', S, 2 )
            or
            MinMatch( '/NOINTERACTIVE', S, 4 )
            or
            MinMatch( '/LOCAL', S, 3 )
            or
            MinMatch( '/NETWORK', S, 2 )
            or
            MinMatch( '/REMOTE', S, 2 )
            or
            MinMatch( '/PRIMEDAYS', S, 2 )
          ) then
        begin
            if( P <> '' ) then
            begin
                S := S + '=' + P ;
            end ;
            Access_Switches := Access_Switches + S ;
        end else
        begin
            if( P <> '' ) then
            begin
                S := S + '=' + P ;
            end ;
            Other_Switches := Other_Switches + S ;
        end ;
    end ; // while( true )
    C := C + Other_Switches ;
    Temp := C ;
    Result := Pchar( Temp ) ;
 Access_Switchesstring.  Other switches are placed inOther_Switches,
and sets up the command line to include only those switches.MinMatchis used to
allow the access switches to be abbreviated.
 
If the command is EXIT, we set    // Process command...
    Auth_Command := Component.Name ;
    if( Component.Name = 'exit' ) then
    begin
        Handled := True ;
        Abort := True ;
        exit ;
    end ;
    if( Component.Name = 'help' ) then
    begin
        Handled := True ;
        //TODO
        exit ;
    end ;
    if( Component.Name = 'remove' ) then
    begin
        Handled := True ;
        S := UUI.Get_Parameter( 'Authorize', 'User to remove: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        Target := S ;
        U := Get_User( S ) ;
        if( U = nil ) then
        begin
            Error_Code := AUTH_NOTFOUND ;
            Abort := True ;
            exit ;
        end ;
        Delete_User( U ) ;
        exit ;
    end ;
 AbortandHandledso 
that the UUI will immediately exit back to the callingAuthorize_SETmethod.
The HELP command is something that we will cover in a future article.
The REMOVE command is handled here.  The processing is simple because it takes no
switches.  The Get_Parametermethod is used to obtain a parameter for
the REMOVE command.  If the parameter is in the command line, it is extracted from
there, otherwise the user is prompted.  The parameter is the user to remove.  If the 
result is a special character, we exit with an abort.  Otherwise we take the name and 
obtain theTUserinstance for the user with that name.  If the returned
user is nil, the user doesn't exist and we exit with an error.  Otherwise, we delete
the user by callingDelete_Userin the SYSUAF module. 
 
The RENAME command is only slightly more involved than the REMOVE command.  In this case,
we get two parameters: the current user name and the new user name.  If the current user
doesn't exist, we exit with an error.  If the new username is invalid, we exit with an
error.  If the new username matches an existing user, we exit with an error.  Otherwise,
we call    if( Component.Name = 'rename' ) then
    begin
        Handled := True ;
        S := UUI.Get_Parameter( 'Authorize', 'Username: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        Target := S ;
        U := Get_User( S ) ;
        if( U = nil ) then
        begin
            UUI.Show_Error( AUTH_NOTFOUND, 'User not found' ) ;
            exit ;
        end ;
        S := UUI.Get_Parameter( 'Authorize', 'New name: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        Target := S ;
        U := Get_User( S ) ;
        if( U <> nil ) then
        begin
            UUI.Show_Error( AUTH_EXISTS, 'User already exists' ) ;
            exit ;
        end ;
        if( not Valid_Username( S ) ) then
        begin
            UUI.Show_Error( AUTH_INVNAM, 'Invalid name' ) ;
            exit ;
        end ;
        Rename_User( Target, S ) ;
        exit ;
    end ;
 Rename_Userto change the user's name.
 
The ADD command depends upon the multitude of Authorize switches, so we only do a little bit of
processing here, and then let the UUI process the switches.  Remember that Add is simply a form
of copy, so we set    if( Component.Name = 'add' ) then
    begin
        Handled := True ;
        Result := nil ;
        S := UUI.Get_Parameter( 'Authorize', 'New username: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        if( not Valid_Username( S ) ) then
        begin
            UUI.Show_Error( AUTH_INVNAM, 'Invalid name' ) ;
            exit ;
        end ;
        Target := S ;
        U := Get_User( S ) ;
        if( U <> nil ) then
        begin
            UUI.Show_Error( AUTH_EXISTS, 'User already exists' ) ;
            exit ;
        end ;
        Source_UIC := 0 ;
        Operation := Op_Copy ;
        U := Get_User( 'default' ) ; // Get Default user
        Update_User_UI( U ) ;
        exit ;
    end ; // if( Component.Name = 'Add' )
 OperationtoOp_Copy, set the source UIC to 0 (the
default user), and set the target to the name of the new user, which we get by callingGet_Parameter.
We validate that the target user name is valid and that the user doesn't already exist.
 
Like the ADD command, the COPY command does a copy operation.  In this case, we prompt for both the
source and Target user names.  We use    if( Component.Name = 'copy' ) then
    begin
        Handled := True ;
        S := UUI.Get_Parameter( 'Authorize', 'Username to copy: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        U := Get_User( S ) ;
        if( U = nil ) then
        begin
            UUI.Show_Error( AUTH_NOTFOUND, 'User not found' ) ;
            exit ;
        end ;
        Source_UIC := U.UIC ;
        Update_User_UI( U ) ;
        S := UUI.Get_Parameter( 'Authorize', 'New username: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        if( not Valid_Username( S ) ) then
        begin
            UUI.Show_Error( AUTH_INVNAM, 'Invalid name' ) ;
            exit ;
        end ;
        Target := S ;
        U := Get_User( S ) ;
        if( U <> nil ) then
        begin
            UUI.Show_Error( AUTH_EXISTS, 'User already exists' ) ;
            exit ;
        end ;
        Operation := Op_Copy ;
        exit ;
    end ; // if( Component.Name = 'Copy' )
 Get_Parameterto get the source and target user
names.  If the source user doesn't exist, we exit with an error.  If the new (target)  user name is
invalid or already exists, we exit with the appropriate error.  Otherwise, we setTarget,Source_UIC, andOperation.
 
As discussed previously, the DEFAULT and MODIFY commands are identical except in terms of which account
is modified.  In the case of DEFAULT, the processing is easy - we set the target and operation.  For
the MODIFY command, we get the target user and validate that the user exists.  As with ADD and COPY,
we let UUI handle the switches and we'll process things after that.    if( Component.Name = 'default' ) then
    begin
        Handled := True ;
        Target := 'DEFAULT' ;
        Operation := Op_Modify ;
        exit ;
    end ; // if( Component.Name = 'Add' )
    if( Component.Name = 'modify' ) then
    begin
        Handled := True ;
        S := UUI.Get_Parameter( 'Authorize', 'User to Modify: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        Target := S ;
        U := Get_User( S ) ;
        if( U = nil ) then
        begin
            UUI.Show_Error( AUTH_NOTFOUND, 'User not found' ) ;
            exit ;
        end ;
        Operation := Op_Modify ;
        exit ;
    end ; // if( Component.Name = 'Modify' )
 
 
The SHOW and LIST commands differ primarily in terms of which switches are handled and
what parameters are passed to    if( Component.Name = 'show' ) then
    begin
        Handled := True ;
        S := UUI.Get_Parameter( 'Authorize', 'User to show: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        Target := S ;
        if( pos( '*', S ) + pos( '?', S ) = 0 ) then // No wildcard
        begin
            U := Get_User( S ) ;
            if( U = nil ) then
            begin
                UUI.Show_Error( AUTH_NOTFOUND, 'User not found' ) ;
                exit ;
            end ;
        end ;
        Highlight := 0 ;
        Pages := 0 ;
        Search_Text := '' ;
        Brief := False ;
        Full := False ;
        case Parse_Switch( 'H|IGHLIGHT', 'NOH|IGHLIGHT', C, P ) of
            1 : // Switch matching /HIGHLIGHT
                begin
                    P := trim( lowercase( P ) ) ;
                    if( MinMatch( 'blink', P, 2 ) ) then
                    begin
                        Highlight := Highlight_Blink ;
                    end else
                    if( MinMatch( 'bold', P, 2 ) or ( P = '' ) ) then
                    begin
                        Highlight := Highlight_Bold ;
                    end else
                    if( MinMatch( 'reverse', P, 1 ) ) then
                    begin
                        Highlight := Highlight_Reverse ;
                    end else
                    if( MinMatch( 'underline', P, 1 ) ) then
                    begin
                        Highlight := Highlight_Underline ;
                    end else
                    begin
                        UUI.Show_Error( UUI_INVSWVAL, 'Invalid switch value' ) ;
                        exit ;
                    end ;
                end ;
            2 : // Switch matching /NOHIGHLIGHT
                begin
                    if( P <> '' ) then
                    begin
                        UUI.Show_Error( UUI_NOSWITCH, 'Parameter not allowed on switch' ) ;
                        exit ;
                    end ;
                    Highlight := 0 ;
                end ;
        end ;
        case Parse_Switch( 'P|AGE', 'NOP|AGE', C, P ) of
            1 : // Switch matching /PAGE
                begin
                    P := trim( lowercase( P ) ) ;
                    if( MinMatch( 'clear_screen', P, 1 ) ) then
                    begin
                        Pages := Pages_Clear_Screen ;
                    end else
                    if( MinMatch( 'scroll', P, 2 ) ) then
                    begin
                        Pages := Pages_Scroll ;
                    end else
                    begin
                        I := pos( ':', p + ':' ) ;
                        S := copy( P, I + 1, length( S ) ) ;
                        P := copy( P, 1, I - 1 ) ;
                        if( S = '' ) then
                        begin
                            S := '5' ;
                        end ;
                        if( MinMatch( 'save', P, 2 ) ) then
                        begin
                            if( not trystrtoint( S, Pages ) ) then
                            begin
                                Error_Code := UUI_INVSWVAL ;
                                Abort := True ;
                                exit ;
                            end ;
                            if( Pages < 1 ) then
                            begin
                                Error_Code := UUI_INVSWVAL ;
                                Abort := True ;
                                exit ;
                            end ;
                        end else
                        begin
                            UUI.Show_Error( UUI_INVSWVAL, 'Invalid switch value' ) ;
                            exit ;
                        end ;
                    end ;
                end ;
            2 : // Switch matching /NOPAGE
                begin
                    if( P <> '' ) then
                    begin
                        UUI.Show_Error( UUI_NOSWITCH, 'Parameter not allowed on switch' ) ;
                        exit ;
                    end ;
                    Pages := 0 ;
                end ;
        end ;
        if( Parse_Switch( 'S|EARCH', '', C, Search_Text ) = 1 ) then
        begin
            if( Search_Text = '' ) then
            begin
                UUI.Show_Error( UUI_NOSWITCH, 'Parameter required on switch' ) ;
                exit ;
            end ;
        end ;
        if( Parse_Switch( 'B|RIEF', '', C, Search_Text ) = 1 ) then
        begin
            if( Search_Text <> '' ) then
            begin
                UUI.Show_Error( UUI_NOSWITCH, 'No parameter allowed on switch' ) ;
                exit ;
            end ;
            Brief := True ;
        end ;
        if( Parse_Switch( 'F|ULL', '', C, Search_Text ) = 1 ) then
        begin
            if( Search_Text <> '' ) then
            begin
                UUI.Show_Error( UUI_NOSWITCH, 'No parameter allowed on switch' ) ;
                exit ;
            end ;
            Full := True ;
        end ;
        if( Full and Brief ) then
        begin
            UUI.Show_Error( UUI_CONFLICT, 'Conflicting switches' ) ;
            exit ;
        end ;
        Error_Code := Show_Report( Target, '' ) ;
        if( Error_Code <> 0 ) then
        begin
            UUI.Show_Error( Error_Code, 'No matches found' ) ;
        end ;
        exit ;
    end ; // if( Component.Name = 'Show' )
    if( Component.Name = 'list' ) then
    begin
        Handled := True ;
        S := UUI.Get_Parameter( 'Authorize', 'User to list: ' ) ;
        if( ( S = Control_Z ) or ( S = Control_C ) or ( S = Control_Y ) or ( S = ESC ) ) then
        begin
            Abort := True ;
            exit ;
        end ;
        Target := S ;
        if( pos( '*', S ) + pos( '?', S ) = 0 ) then // No wildcard
        begin
            U := Get_User( S ) ;
            if( U = nil ) then
            begin
                UUI.Show_Error( AUTH_NOTFOUND, 'No matches found' ) ;
                exit ;
            end ;
        end ;
        Highlight := 0 ;
        Pages := 0 ;
        Search_Text := '' ;
        Brief := False ;
        Full := False ;
        if( Parse_Switch( 'B|RIEF', '', C, Search_Text ) = 1 ) then
        begin
            if( Search_Text <> '' ) then
            begin
                UUI.Show_Error( UUI_NOSWITCH, 'No parameter allowed on switch' ) ;
                exit ;
            end ;
            Brief := True ;
        end ;
        if( Parse_Switch( 'F|ULL', '', C, Search_Text ) = 1 ) then
        begin
            if( Search_Text <> '' ) then
            begin
                UUI.Show_Error( UUI_NOSWITCH, 'No parameter allowed on switch' ) ;
                exit ;
            end ;
            Full := True ;
        end ;
        if( Full and Brief ) then
        begin
            UUI.Show_Error( UUI_CONFLICT, 'Conflicting switches' ) ;
            exit ;
        end ;
        Error_Code := Show_Report( Target, 'sysuaf.lis' ) ;
    end ; // if( Component.Name = 'List' )
end ; // TAuth_Responder.Callback
 Show_Report.  In both cases, we get the user
specification.  If it doesn't include a wildcard, we validate that the user exists and
then process the various switches.
We will cover the Show_Reportfunction and thePost_Processingmethod 
in the next article.   Copyright © 2022 by Alan Conroy.  This article may be copied
in whole or in part as long as this copyright is included. |