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

Lexical Functions: F$PID

In the previous article we discussed the F$CONTEXT lexical function. In this article, we'll cover the F$PID lexical function, which uses the context that F$CONTEXT set up.

Here is a description of the F$PID lexical function:
Each call to F$PID will return the next process ID that matches the context set up by F$CONTEXT. The context is updated to point to the next process ID.

Format
F$PID(symbol)

Return Value
Returns the ID of the next process matching the criteria, or a null string if no more processes match.

Arguments

symbol
Specifies a symbol that UCL will use to refer to the context object that holds the UOS process context. Multiple contexts can exist simultaneously, each one specified with a different symbol.

The first time you use F$PID in a script, you should use a symbol that is either undefined or equated to null, or that has been created by the F$CONTEXT function. If the symbol was used with F$CONTEXT then F$PID function returns the first process that fits the criteria specified in the F$CONTEXT function and are accessible to your current privileges.

If a null string is passed to F$PID, it is considered to be a wildcard context and F$PID will iterate through all processes on the sytem that the caller has the privileges to access. There can only be one wildcard process context at a time for a given calling process.

After the last PID in the process list is returned, F$PID returns a null string.

Example:
$ PID = F$PID(CONTEXT)

        Function_PID : begin
                           if( Missing_Parentheses( '(' ) ) then
                           begin
                               exit ;
                           end ;
                           if( Process_PID( Err, Context ) ) then
                           begin
                               exit ;
                           end ;
                           if( Missing_Parentheses( ')' ) ) then
                           begin
                               exit ;
                           end ;
                           if( Err = 0 ) then
                           begin
                               S := Context ;
                           end ;
                       end ;
First we add the case to the Function_Reference function to handle the F$PID function.

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

var Buffer : array of byte ;


    procedure Extend( Amount : integer ) ;

    begin
        setlength( Buffer, length( Buffer ) + Amount ) ;
    end ;



var Descriptor : array[ 0..1 ] of TSYS_Descriptor ;
    E : int64 ; // Exception
    Filter : TFilter ;
    I : int64 ;
    IOSB : TIOSB ;
    Loop : integer ;
    P : integer ;
    pidctx : int64 ;
    Reference_Descriptor : TPSCAN_Reference_Descriptor ;
    S, Sym : string ;
    UCL_Context : TUCL_Context ;
    Value_Descriptor : TPSCAN_Value_Descriptor ;

begin // Process_PID
    // Setup...
    Err := 0 ;
    Context := '' ;
    Result := False ;
The Process_PID function will return the next process matching the context specified in symbol name that is the next token. If a UOS context has not yet been created, we will create one. This will require us to build up an item list to pass to SYS_PROCESS_SCAN. This is stored in the Buffer dynamic array. To simplify the code, we define the local function which will extend the array length by a specific amount.

The first few lines of the function set up for the following code.

    // Get context symbol name...
    Sym := Get_Token ;
    if( ( Sym <> '' ) and ( not Valid_Symbol_Name( Sym ) ) ) then
    begin
        Result := True ;
        Err := UCL_IVSYMB ; // Invalid symbol name
        exit ;
    end ;
First, we grab the symbol token. The value must be a valid symbol name, or null.

    // Check context...
    UCL_Context := nil ;
    if( Sym = '' ) then
    begin
        S := '' ;
    end else
    begin
        S := Symbol_Value( Sym ) ;
    end ;
If a symbol name is provided, we get the value for the symbol and assign it to S. If no symbol name is present, we set S to null. So, after this code, S will be the symbol value or null.

    if( S <> '' ) then
    begin
        if( trystrtoint64( S, I ) ) then
        begin
            UCL_Context := TUCL_Context( pointer( I ) ) ;
            if( Contexts_List.Indexof( UCL_Context ) = -1 ) then // Not a valid context
            begin
                UCL_Context := nil ;
            end ;
        end ;
        if( UCL_Context = nil ) then // No context
        begin
            UCL_Context := TUCL_Context.Create ;
            I := int64( UCL_Context ) ;
            Err := LIB_Set_Symbol( Sym, inttostr( I ) ) ;
            if( Err <> 0 ) then
            begin
                Result := True ;
                UCL_Context.Free ;
                Err := UCL_IVSYMB ; // Most likely cause of set_symbol failure (review)
                exit ;
            end ;
        end ; // if( UCL_Context = nil )
if the value is non-null, we get the corresponding UCL context instance from the address in the value. If the value is non-numeric or doesn't correspond to an instance in Contexts_List, we create a new instance and write the address of that instance to the symbol, exiting if there's an error.

        // Make sure we have a valid context...
        if( UCL_Context.Context = 0 ) then // Need to create new Process_Scan context
        begin
            P := 0 ;
            for Loop := 0 to UCL_Context.Filters.Count - 1 do
            begin
                Filter := TFilter( UCL_Context.Filters[ Loop ] ) ;
                if( Is_By_Reference( Filter.Selection_Criteria ) ) then
                begin
                    Reference_Descriptor.Code := Filter.Selection_Criteria ;
                    Reference_Descriptor.MBO := 1 ;
                    Reference_Descriptor.MBMO := $FFFFFFFF ;
                    Reference_Descriptor.Flags := Filter.Qualifier ;
                    Reference_Descriptor.Length := length( Filter.Value ) ;
                    Extend_Data( length( Filter.Value ) ) ;
                    Reference_Descriptor.Address := integer( PChar( Filter.Value ) ) ;
                    Extend( sizeof( Reference_Descriptor ) ) ;
                    move( Reference_Descriptor, Buffer[ P ], sizeof( Reference_Descriptor ) ) ;
                    P := P + sizeof( Reference_Descriptor ) ;
                end else
                begin
                    Value_Descriptor.Code := Filter.Selection_Criteria ;
                    Value_Descriptor.MBO := 1 ;
                    Value_Descriptor.MBMO := $FFFFFFFF ;
                    Value_Descriptor.Value := strtoint( UCL_Strtoint( Filter.Value ) ) ;
                    Value_Descriptor.Flags := Filter.Qualifier ;
                    Extend( sizeof( Value_Descriptor ) ) ;
                    move( Value_Descriptor, Buffer[ P ], sizeof( Value_Descriptor ) ) ;
                    P := P + sizeof( Value_Descriptor ) ;
                end ;
            end ; // for Loop := 0 to UCL_Context.Filters.Count - 1
If no UOS context has been assigned to the instance's Context, we need to create one. This requires us to build the item list. We loop through the filters, and construct either a reference descriptor or value descriptor, as appropriate. We then extend the buffer and copy the descriptor to the buffer.

            // Write terminating descriptor to buffer...
            fillchar( Value_Descriptor.Code, sizeof( Value_Descriptor ), 0 ) ;
            Extend( sizeof( Value_Descriptor ) ) ;
            move( Value_Descriptor, Buffer[ P ], sizeof( Value_Descriptor ) ) ;

            pidctx := 0 ;
            SYS_PROCESS_SCAN( integer( @pidctx ), integer( @Buffer[ 0 ] ) ) ;
            UCL_Context.Context := pidctx ;
            if( pidctx = 0 ) then // Some error occurred
            begin
                Result := True ;
                E := LIB_Get_Exception( 0 ) ; // Get handle
                Set_Exception( LIB_Get_Exception_Text( 0, E ) ) ;
                exit ;
            end ;
        end ; // if( UCL_Context.Context = 0 )
    end ; // if( S <> '' )
After processing the filters, we add a terminating descriptor (one consisting of nulls). Next, we call SYS_PROCESS_SCAN with the item list that we created. If there was an error, we exit. Otherwise, we set the UCL_Context's context to the UOS context returned.

    // Find next PID...
    PP_Buff := 0 ;
    fillchar( Descriptor, sizeof( Descriptor ), 0 ) ;
    Descriptor[ 0 ].MBO := $FFFF ;
    Descriptor[ 0 ].MBMO := -1 ;
    Descriptor[ 0 ].Buffer_Length := sizeof( PP_Buff ) ;
    Descriptor[ 0 ].Item_Code := JPI_PID ;
    Descriptor[ 0 ].Buffer_Address := integer( @PP_Buff ) ;
    Descriptor[ 0 ].Return_Length_Address := integer( @PP_BufLen ) ;
    if( Sym = '' ) then // Wildcard
    begin
        SYS_GETJPIW( 0, -1, '', integer( @Descriptor ), integer( @IOSB ), 0, 0 ) ;
    end else
    begin
        SYS_GETJPIW( 0, UCL_Context.Context, '', integer( @Descriptor ), integer( @IOSB ), 0, 0 ) ;
    end ;
    if( PP_Buff = 0 ) then
    begin
        Context := '' ;
    end else
    begin
        Context := inttostr( PP_Buff ) ;
    end ;
end ; // Process_PID
By the time we get to this code, we have a context which has a valid UOS context. So we construct a descriptor list with a JPI_PID item and a null and call SYS_GETJPIW to get the next PID. If the result is 0 - meaning that there are no more matching processes - we return a null string. Otherwise we return the process ID.

In the next article, we will continue our examination of UCL lexical functions.

 

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