A Detailed Look at CI Enhancements

by Jeff Vance
Commercial Systems Division

Overview

This article provides a more indepth understanding of the following CI enhancements introduced in the "CI Enhancements Overview" article in Chapter 3, "System Management." Note that the CI enhancements in Release 5.5 are a superset of the CI enhancements in Express 3.

Following is a summary of the CI enhancements:

New CI Variables

Eight new predefined CI variables were added in MPE/iX Release 5.5:

  • HPLOCIPADDR
  • HPREMPORT
  • HPLOCIPADDR
  • HPLOCPORT
  • HPSTREAMEDBY
  • HPLASTJOB
  • HPOSVERSION
  • HPRELVERSION

HPREMIPADDR

HPREMIPADDR is a string variable that contains the IP address of a remotely connected user (client). If you are directly connected to the HP 3000, HPREMIPADDR is set to &dquote;&dquote; (empty string).

HPREMPORT

HPREMPORT is an integer variable that contains the TCP port number allocated on the remote machine (client) for use on the incoming TCP connection. If you are directly connected to the HP 3000, HPREMPORT is zero.

HPLOCIPADDR

HPLOCIPADDR is a string variable that contains the IP address of the HP 3000 local Network Interface (NI) that will be used for outbound data. If you are directly connected to the HP 3000, HPLOCIPADDR is set to &dquote;&dquote;. HP 3000s support several network interface cards and thus can have more than one IP address.


NOTE: HPLOCIPADDR may not reflect the IP address of the NI used for inbound data flow from the same client due to either network load balancing or a misconfiguration.

HPLOCPORT

HPLOCPORT is an integer variable that contains the local TCP port number for the network service provided to the client. If you are directly connected to the HP 3000, HPLOCPORT is zero. For example, a telnet connection uses port 23, NS/VT connections use ports 1537 and 1570, an ftp data connection uses port 20.

Below is a sample logon UDC that filters logons based on time-of-day, inbound IP addresses and inbound port number (service being used). Security on this UDC is assigned so that only the file's creator has read/write access, all others have only execute access.

   SYSLOGON
   OPTION LOGON, NOBREAK
   # This system-wide logon UDC ensures that no one logs on "after hours"
   # from outside our company via NS/VT.

# After hours are weekends and weekdays after 6pm and before 7am setvar too_early 7 setvar too_late 6

# Currently only checking for VT connections, later will add telnet check setvar msg_mode_VT 1537 setvar stream_mode_VT 1570

# Check weekday and time of day first if word(hpdatef) = "SAT" or word(hpdatef) = "SUN" or && (word(hptimef,,-1) = "PM" and ![word(hptimef,":")] > too_late) or && (word(hptimef,,-1) = "AM" and ![word(hptimef,":")] < too_early) then

# It is too late or too early or the weekend. # Check for an offsite IP address via NS/VT. if HPREMIPADDR <> "" then # A network connection # Determine n/w mask based on host's IP address class setvar class_octet ![word(HPLOCIPADDR,".")]

if class_octet < 128 then # Class A addr setvar nw_mask word(HPLOCIPADDR,".") elseif class_octet < 192 then # Class B addr setvar nw_mask lft(HPLOCIPADDR,pos(".",HPLOCIPADDR,2)-1) else # Assume Class C addr setvar nw_mask lft(HPLOCIPADDR,pos(".",HPLOCIPADDR,3)-1) endif

# See if connection is outside the company if lft(HPREMIPADDR,len(nw_mask)) <> nw_mask then # Outside connection, check for NS/VT if HPLOCPORT = msg_mode_VT or HPLOCPORT = stream_mode_VT then echo Connection refused, please contact MIS. bye endif endif deletevar class_octet, nw_mask endif endif deletevar too_early, too_late, msg_mode_VT, stream_mode_VT echo Welcome to !HPSYSNAME. *********

HPSTREAMEDBY

HPSTREAMEDBY is a read-only string variable. Typically, it contains the user.account name of the user who streamed a job, or who STARTSESSed a session. The exact format is:

   UserName.AcctName (#J|Snnnnn)                                              

However, for the initial OPERATOR.SYS logon or a job streamed from the SYSSTART.PUB.SYS file, the job/session ID is replaced by the string, SYSTEM PROCESS. For example, MANAGER.SYS (SYSTEM PROCESS).

HPLASTJOB

HPLASTJOB is a read-write string variable. It contains the job ID of the job that was most recently STREAMed. The format is: #Jnnnnn and appears the same as the job ID output by the STREAM command.

HPOSVERSION

HPOSVERSION is a read-only string variable. It contains the operating system version ID identical to the middle version string in the SHOWME banner. Remember that the HPVERSION variable contains the user version ID, which can be modified via SYSGEN.

HPRELVERSION

HPRELVERSION is a read-only string variable. It contains the Release version ID identical to the left version string in the SHOWME banner.

Longer CI Variables

In MPE/iX Releases 5.0 and earlier, CI variable values were limited to 255 characters. Beginning with MPE/iX Release 5.5, CI variable values can be up to 1024 characters long. Variable names can continue to be up to 255 characters long. Also the CI's variable table can expand to accommodate approximately two times more variables than previously.

In MPE/iX Release 5.5, the maximum number of variables that can be created is approximately 10700. This number is inversely related to the length of the variable's name and the length of its value. Also, the maximum number of variables that can be created with 254-character names and 255-character values is 2190, compared to 974 in MPE/iX Release 5.0.

New Evaluator Functions

Five new CI evaluator functions were added and three functions were expanded in MPE/iX Release 5.5. Most of these enhancements make parsing text easier via the CI.

The new CI evaluator functions are:

  • word()
  • edit()
  • repl()
  • delimpos()
  • pmatch()

The enhanced functions are:

  • str()
  • rht()
  • input()

word()

A general word extraction. String function.

Syntax: word(str[,delims][,nth][,end_var][,start])

This new function extracts the nth word from str beginning at start, delimited by one of the characters in delims, placing the index of the delimiter that terminated the word in a CI variable named by the end_var argument.

Parameters:

str
Required. str is any quoted string or string variable. This is the source for the word extraction.

delims
Optional. delims is a string that contains a list of characters that constitute the termination of a word. The default delims are: space, comma, semicolon, tab, equal sign, square brackets, single and double quotes, parentheses. All other characters in str are considered part of a word.

nth
Optional. An integer indicating which word to extract from str. The default value is 1, meaning parse out the first word, scanning from left to right. A value of 2 causes the second word in str to be extracted. A negative value means extract a word starting at the end of str, parsing from right to left. A value of -3 means to extract the third from last word in str. A value of -1 indicates the last word in str.

end_var
Optional. The actual name of a variable to be set to the index in str of the delimiter that terminated the extracted word. end_var cannot be a string expression-- the actual unquoted name must be used. The default is to not set a variable. If the nth word is not found then end_var is not set. For nth >= 0 the largest end_var value is len(str)+1, meaning the last word was found. For nth < 0 the smallest end_var value is 0, meaning the first word was found. Multiple spaces in str after the extracted word are skipped.

start
Optional. An integer index into str where the word extraction begins. The default start when nth >= 0 is 1, and when nth < 0 is the index of the last byte in str.

word() starts at str[start] and scans str looking for a word delimiter. The direction of the scan is determined by nth. Positive nth values cause a left to right scan, whereas negative values use a right to left scan.

Initial spaces are skipped. After the delimiter is found, trailing spaces are also skipped until a non-space delimiter is found, if any. end_var is set to the index of this non-space delimiter. If one or more spaces are the only delimiter between words then end_var is set to the index of the last space in str before the next word.

There are two cases when word() can functionally return an empty string:

  1. When the nth word does not exist in str.

  2. When the nth word exists but has no value. Consider:

    setvar str, "rec=10,,f"
    

    • word(str,,5) returns "", since there are only four words in str.

    • word(str,,3) returns "", since the third word has no value -- the third word starts at str[8] and ends at the same index.

    These two cases can be distinguished by passing the end_var parameter.

    • word(str,,5,j) does not set the variable J.
    • word(str,,3,j) sets J to 8.

    Examples:

             word('file a=bb,old;rec=40,,f,ascii')           = 'file'
             word('file a=bb,old;rec=40,,f,ascii',,2)        = 'a'
             word('file a=bb,old;rec=40,,f,ascii',";,",,j,8) = 'bb', j=10
             word('file a=bb,old;rec=40,,f,ascii',,-4,j)     = '40', j=18
    
    Here's how to parse every token in a string by incrementing the starting index.
         setvar j 0
         while setvar(j,j+1) <= len(str) do
            setvar token word(str,,,j,j)
            ...
         endwhile
    

    Another way to parse a string by using nth and omitting start:

         setvar j 0
         setvar cnt 0
         while setvar(cnt,cnt+1) <= 9999 and j <= len(str) do
            setvar token word(str,,cnt,j)
            ...
         endwhile
    

    edit()

    Full REDO-like editing of a string. String function.

    Syntax: edit(str,editstr[,start])

    This new function applies the edit contained in editstr to str starting at start and functionally returns the result.

    Parameters:

    str
    Required. str is any quoted string or string variable. The edit is applied to str.

    editstr
    Required. editstr is a string containing a REDO-like edit. For example, " dddiXYZZY" would delete the 2nd, 3rd, and 4th characters in str and then insert "XYZZY".

    start
    Optional. An integer index into str where editstr is applied. The default start is 1.

    edit() starts at str[start] and applies the edit in editstr exactly as the CI's REDO command edits a command line. The edited string is functionally returned. The size of the string that can be edited is limited to the size of the CI's command buffer, which is currently 512 bytes.

    Examples:

             edit('abcdefg','>dd')       = 'abce'
             edit('ab cd;g','dwd')       = 'cd;g'
             edit('abccd;g','c/c/AA/')   = 'abAAAAd;g'
             edit('abcdefg','^∅^',3)      = 'abCDefg'
    

    repl()

    General string replacement. String function.

    Syntax: repl(str,oldstr,newstr[,cnt][,start])

    This new function replaces cnt occurrences of oldstr in str with newstr, starting at start.

    Parameters:

    str
    Required. str is any quoted string or string variable. This is the source for the replacement.

    oldstr
    Required. oldstr is the string searched for in str. It is replaced by newstr. No replacement occurs if oldstr is empty.

    newstr
    Required. newstr is the string that is substituted for oldstr and it can be empty (&dquote;&dquote;).

    cnt
    Optional. cnt is the number of replacements to be done in str. The default cnt is zero meaning replace all occurrences of oldstr in str. A positive cnt indicates that the replacements are done from left to right, e.g., 1 means replace the first occurrence, 2 means the first two occurrences, etc. A negative cnt indicates right to left replacement, e.g., -1 means replace the last occurrence, -2 means the last two occurrences, etc.

    start
    Optional. An integer index into str where the replacement begins. The default start when cnt >= 0 is 1, and when cnt < 0 is the index of the last byte in str.

    It is possible for the replace operation to overflow str. In that case the maximum number of replacements are done prior to exceeding the maximum size of a string variable (currently 1024 bytes).

    Examples:

             repl('aaabcaab','aa','X')     = 'XabcXb'
             repl('aaabcaab','ab','',-1)   = 'aaabca'
             repl('f*.*','*','@')          = 'f@.@'
    

    delimpos()

    Finds the position (index) of a delimiter. Integer function.

    Syntax: delimpos(str[,delims][,nth][,start])

    This new function returns the position of the nth delimiter in str beginning at start.

    Parameters:

    str
    Required. str is any quoted string or string variable. This is the source for the delimiter searching.

    delims
    Optional. delims is a string that contains a list of one or more characters that are searched for in str. The default delims are the same as for word(): space, comma, semicolon, tab, equal sign, square brackets, single and double quotes, parentheses.

    nth
    Optional. An integer indicating which delimiter occurrence to scan for. The default value is 1, meaning find the position of the 1st delimiter in str. A value of 2 means find the second delimiter, etc. A negative value means search for the delimiter from right to left. A value of -3 means to find the third from last delimiter in str. A value of -1 indicates find the index of the last delimiter in str.

    start
    Optional. An integer index into str where the delimiter searching begins. The default start when nth >= 0 is 1, and when nth < 0 is the index of the last byte in str.

    There are several differences between delimpos() and pos(). The pos() function supports the matching of one or more characters, e.g., pos('abcd',str,2) locates the index in str of the 2nd occurrence of "abcd". The delimpos() function only supports single character matches. However, several characters can be tested for a match. For example, delimpos(str,'abcd',2) locates the index in str of the second occurrence of either an "a" or "b" or "c" or "d".

    Typically, the delimiter string will be token separators like ";", ",", " ", etc. The delimpos() function also supports the start parameter which is not available in pos().

    Examples:

                                1         2                    Funct  Delim
                       12345678901234567890123456789            Rtn   Found
             delimpos('file a=bb,old;rec=40,,f,ascii')           5     ' '
             delimpos('file a=bb,old;rec=40,,f,ascii',,3)        10    ','
             delimpos('file a=bb,old;rec=40,,f,ascii',",;",-4)   14    ';'
             delimpos('file a=bb,old;rec=40,,f,ascii',,,7)       7     '='
    

    pmatch()

    Pattern matching. Boolean function.

    Syntax: pmatch(pattern,str[,start])

    This new function returns TRUE if pattern is found in str, starting at start.

    Parameters:

    pattern
    Required. A string pattern to be matched in str. Wildcard characters are supported.

    str
    Required. str is any quoted string or string variable. This is the source that the pattern is matched against.

    start
    Optional. An integer index into str where the search for the pattern begins. The default start is 1.

    str[start] is scanned looking for pattern. If a match is found then TRUE is returned, else FALSE is returned. The pattern can be any MPE filename character, including all wildcards. pmatch() provides the same pattern matching used by LISTFILE and SHOWVAR.

    pmatch() is different from pos() since wildcards are supported, a start parameter is provided, which occurrence of pattern to match cannot be specified, and true pattern matching is performed. For example, pos('abc','aaabccc') is 3. pmatch('abc','aaabccc') is FALSE. However, pmatch('@abc@','aaabccc') is TRUE.

    Both pattern and str are limited to 256 bytes due to internal interface restrictions. If pattern xor str are empty (but not both) then FALSE is returned. If both pattern and str are empty then TRUE is returned.

    Examples:

             pmatch('f@','fread')    = true
             pmatch('f#','fabc')     = false
             pmatch('@f@,'abcdefg')  = true
             pmatch('abc','abcd')    = false
             pmatch(,'abc')        = false
    

    str()

    General string extraction. String function.

    Syntax: str(str1,start,cnt)

    This existing function extracts cnt characters from str1 starting at start.

    The cnt parameter was enhanced to support an ending index rather than only a byte count. If cnt is negative then the absolute value of cnt is the ending index in str1 to stop the extraction. If cnt is negative and -cnt is less than start then an empty string is returned.

    Examples:

             str('abcde',2,3)      = 'bcd'
             str('abcde',2,-4)     = 'bcd'
             str('abcde',3,-3)     = 'c'
             str('abcde',3,-1)     = 
    

    rht()

    Right-hand string extraction. String function.

    Syntax: rht(str1,cnt)

    This existing function extracts the right-most cnt characters from str1.

    The cnt parameter was modified to support a starting index rather than only a byte count. If cnt is negative then the absolute value of cnt is the starting index in str1 to start the extraction, which includes all characters from str1[-cnt] to the end of str1.

    Examples:

             rht('abcde',3)        = 'cde'
             rht('abcde',-4)       = 'de'
             rht('abcde',-1)       = 'abcde'
    

    input()

    Read from $STDIN. String function.

    Syntax: input([prompt][,wait][,cnt])

    This existing function optionally writes prompt to $STDLIST, reads from $STDIN, with the option of the read being a timed read of wait seconds. The input from $STDIN is functionally returned.

    The cnt parameter is new. If cnt is specified, then only cnt bytes are read from $STDIN. The default cnt is the maximum size of a string variable, currently 1024 characters. If cnt is specified and less than cnt characters are supplied as input, you must still use the RETURN key to send the data.

    Example:

             input('Do this (Y/n)?',10,1)   Prompts to $STDLIST, does a 10 
    					second timed read on $STDIN of 1 
    					character.
    

    Execute Access for UDCs and Command Files

    Prior to the MPE/iX-Express 3 Based on General Release 5.0, all UDC and command file users must be allowed read access to the UDC file or the command file they wish to execute. Although these user command files can be protected by lockwords, the user must know the lockword to be able to read the file's contents.

    Now UDC files and command files can be protected by denying READ (R) access and granting EXECUTE (X) access to users that need to execute the file but are not permitted to read the file. For example, using either of the following command lines grants execute access to the mycmdf file. You can verify the security using LISTFILE formats -2 or 4.

         :altsec mycmdf; access=(x:any; r,w,l,a:gu)
    

    or

         :altsec mycmdf; repacd=(racd,x:@.@; r,w,l,a:$group)                         
    

    If you lack READ access to a command file or UDC file, the system behaves in the following manner:

    • You cannot see any of the commands within the file. Specifically, OPTION LIST and the HPCMDTRACE variable are defeated.

    • HELP is unavailable for the file. For a UDC file this means that all of the UDCs within the file are treated as if OPTION NOHELP was specified.

    • SHOWCATALOG still lists the individual UDCs and UDC filenames.

    • If an error occurs, the offending command line is not echoed to $STDLIST.

    Of course, if you have READ access to the file then everything works in a compatible manner.

    POSIX-Named Command Files

    In MPE/iX General Release 5.0, all command files must follow MPE naming rules and the HPPATH variable can only contain the names of MPE groups and accounts.

    In the Express 3 Release, command files can reside in the Hierarchical File System (HFS) and follow the more flexible POSIX naming conventions. For example, a command file can now be named find_deduction, 123, or AutoExec.BAT. UDC files are still restricted to MPE naming rules.

    Qualified MPE or POSIX filenames are executed immediately, skipping the HPPATH variable. For example, file.grp, *feq, $oldpass, /bin/ls, ./do_it are all qualified filenames and thus HPPATH is ignored. If the file exists, it is executed. If the file is not found, then the following message is reported:

         Unknown command name. (CIERR 975)
    

    Qualified MPE filenames are file.group or file.group.account. Also, back references to a file equation and system-defined files, such as $OLDPASS, are considered qualified MPE names. Qualified POSIX names are absolute pathnames (the name starts at root), or Current Working Directory (CWD) relative names (the name starts at the user's current working directory, ./name).

    The command file named a/b can be considered a qualified POSIX name (file b under directory a), but for compatibility reasons this is first treated as an unqualified MPE name with a supplied lockword. Actually, file.grp could be an unqualified POSIX name (in which case HPPATH is used), but the MPE file, FILE, in the MPE group, GRP, is looked for first. Other examples where the command filename could be both an MPE name or a POSIX name are covered later, but in all of these cases the MPE name is searched for before the POSIX name.

    To execute unqualified POSIX-named command files, HPPATH must contain one or more entries specified in MPE-ESCAPED syntax. That is, the name must begin with a dot (".") or a slash ("/"). The default HPPATH setting is !hpgroup,PUB,PUB.SYS,ARPA.SYS. Since the default HPPATH contains no MPE-ESCAPED named entries, unqualified POSIX-named command files cannot be located.

    If HPPATH is modified to be PUB.SYS,/bin,./mybin, then unqualified POSIX-named command files can be located in /bin and in CWD/mybin. If the System Manager desires to place POSIX-named command files in PUB.SYS then HPPATH needs to contain a /SYS/PUB entry. In other words, to use unqualified POSIX-named scripts, even if the file resides in an MPE group, the location (directory) name must appear in HPPATH in MPE-ESCAPED syntax.

    Following is the basic algorithm for processing MPE- or POSIX-named command files:

    • The command name is parsed twice: first via MPE rules then via POSIX syntax rules.

    • If the name is a qualified MPE name (e.g., a.b) it is tried first.

    • If a file matching the name has not yet been found and the name is not a qualified POSIX name then HPPATH is used to try to locate the name.

      • MPE path elements (group.accounts) are appended to the MPE parsed version of the command filename.

      • POSIX path elements (directories) are prepended to the POSIX parsed version of the command name.

      • The name, qualified by the appropriate HPPATH element, is searched for until the first match.

    • If a file matching the command filename has still not been located and the command name is a qualified POSIX name (e.g., ./a, /a, a/b) then that exact name is searched for.

    • At this point either there is a match or an unknown command error is reported.


    NOTE: The same command filename can be both a qualified MPE name and a qualified POSIX name, e.g., a/b.c. This name could refer to file A in group C with lockword B, or file b.c under directory a. According to the above algorithm, the qualified MPE version of the name is tried first.

    Before showing some examples it is important to remember that MPE command names are delimited by the first character that is not a valid name character. This is how the CI has behaved since MPE XL Release 1.0 and, in most cases, a blank delimits all command names. UDC names are delimited by the first non-alphanumeric character. For example, if the command entered is :udc1a.chv, the CI first looks for a UDC named UDC1A, and if found, passes .chv as the first argument.

    Built-in command names are delimited by the first non-alpha character. For example, if the built-in command is :run$oldpass, $oldpass is passed as the first parameter to the RUN command. Likewise, if the built-in command is :abortio7, 7 is passed as the first argument to the ABORTIO command.

    Command filenames are delimited by the first non-filename character. For example, if the command entered is :xyzzy.g%foo, the file XYZZY.G is passed %foo as its first argument. Again, this is not new behavior for the Express 3 Release, but it is worth describing since users may assume a blank delimiter is required.

    For the examples below, assume that HPPATH is set as:

                                                                           
         :setvar hppath "PUB.SYS, ., /SYS/PUB"
    

    where the directory "." refers to the user's current working directory.

                                                               
    
    Command       HPPATH Searching
    
    :a            A.PUB.SYS, ./a, /SYS/PUB/a                                          
    :A            A.PUB.SYS, ./A, /SYS/PUB/A (redundant)                              
    :./a          Qualified name, HPPATH is ignored, 
    	      ./a is executed    
    
    :/a           Qualified name, HPPATH is ignored, /a is executed 
    
    :a_b          A.PUB.SYS ("_b" passed as 1st parm), ./a_b, /SYS/PUB/a_b
    
    :a.b          Qualified MPE name, A.B.ACCT, if not found then 
    	      HPPATH is used as: ./a.b, /SYS/PUB/a.b 
    	      (MPE path elements are skipped)                                                          
    :_a           ./_a, /SYS/PUB/_a (MPE path elements are skipped)
    
    :a/b          A/B.PUB.SYS (POSIX path elements are skipped), if not 
                  found then qualified POSIX name a/b is executed 
    
    :a/b.c        Qualified MPE name, A/B.C, if not found then                  
                  qualified POSIX name, a/b.c (HPPATH skipped)
    
    :_a/b         Qualified POSIX name, _a/b (HPPATH skipped) 
    

    REDO Enhancements

    The REDO procedure which is invoked by the CI, Debugger, SYSGEN, VOLUTIL and the Link Editor has been enhanced.

    Motivated, in part, by the need for case specificity in POSIX filenames, REDO now supports upshift (^) and downshift (v) edits. Also, as filenames get longer, it becomes more cumbersome to delete a name. Therefore, a word edit has been defined. For example dw deletes a word. REDO defines words to be any characters delimited by a space, comma, semicolon, tab, equal sign, square brackets, single and double quotes, and parentheses. Words can also be upshifted (^w) or downshifted (vw).

    Finally, sometimes the edit needs to be applied to part of a word or to several words, so you can supply your own matching delimiter. For example, d/ would delete to the first "/".

    The new edits can be applied to the end-of-line by preceding the edit with ">". For example, >dw deletes the last word, and >v@ downshifts from the end-of-line to the first "@" character (searching from right-to-left).

    The user-supplied delimiter edits are not performed if the delimiter is not found. Also the special characters space, "^" and ">" cannot be used as delimiters since these symbols have already been defined. If a word edit is specified and a word delimiter is not found then the edit applies to the entire line.

    Online HELP for CI Variables and Functions

    Information about all CI variables has been supported via HELP since MPE/iX Release 5.0, but Release 5.5 also includes HELP for all CI evaluator functions.

    For example:

    HELP FUNCTIONS
    - Shows a table of all evaluator functions.
    HELP FINFO
    - Shows the details of the FINFO function.
    HELP WORD
    - Describes the new WORD function.
    HELP VARIABLES
    - Shows a table of all CI variables.
    HELP HPREMIPADDR
    - Describes the new HPREMIPADDR variable.