MPE/iX 5.5 CI Enhancements

by Jeff Vance CSY

Overview

The Command Interpreter (CI) has been improved in MPE/iX Release 5.5. In addition to the Express 3 CI enhancements (X access for UDCs/command files, POSIX-named command files and directories in HPPATH, console over LAN, REDO enhancements, new CI variables), the following features were added to the CI:

New CI Variables

There are four new predefined CI variables in Release 5.5.

HPREMIPADDR is a string variable that contains the IP address of a remotely connected user (client). If the user is directly connected to the HP 3000 HPREMIPADDR is set to "" (empty string).

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 the user is directly connected to the HP 3000 HPREMPORT is zero.

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 the user is directly connected to the HP 3000, HPLOCIPADDR is set to "". HP3000s 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 is an integer variable that contains the local TCP port number for the network service provided to the client. If the user is 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.
   *********

Longer CI Variables

In Releases 5.0 and earlier, CI variable values were limited to 255 characters. Beginning in MPE/iX Release 5.5, CI variables 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 Release 5.5 the maximum number of variables that can be created is approximately 10,700. This number is inversely related to the length of the variable's name and the length of its value. In Release 5.5 the maximum number of variables that can be created with 254 character names and 255 character values is 2,190, compared to 974 in Release 5.0.

New Evaluator Functions

To ease the parsing of the output of CI commands and of user input, five new evaluator functions were added and three existing functions were enhanced in Release 5.5: word(), edit(), repl(), delimpos(), pmatch(), str(), rht(), input()


WORD() - 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.
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, equalsign, square brackets, single and double quotes, parenthesis. 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 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 extracted word. end_var cannot be a string expreession - the actual unquoted name must be used. The default is to not set a variable. If the nth word is not found end_var is not set. For nth >= 0 the highest 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 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".
  1. word(str,,5) returns "", since there are only four words in str.
  2. 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.
  3. word(str,,5,j) does not set the variable J.
  4. 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.
str
Required. str is any quoted string or string 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'

Here's how to provide REDO capability to an interactive command file:

         ...
         # parse user input, buf, into "cmd" and "parms"
         setvar cmd ups(word(buf))
         ...
         if cmd = "REDO" then
            # fetch command to redo from history stack
            ...
            setvar buf history!index
            echo !buf
            setvar bufedit input()
            while len(bufedit) > 0 do
               setvar buf edit(buf,bufedit)
               echo !buf
               setvar bufedit input()
            endwhile
         endif
         ...


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.
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 will be replaced by newstr. No replacement occur if oldstr is empty.
newstr
Required. newstr is the string that is substituted for oldstr and it can be empty ("")
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 replace the first two occurrences, 3 indicates replace the first three 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.
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, equalsign, square brackets, single and double quotes, parenthesis.
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 second occurrence of "abcd". The delimpos() function only supports single character matches; however, several characters can be tested for a match, e.g., 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.
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, SHOWVAR and STORE (without the exception fileset (minus) patterns).
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 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 rightmost 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 cnt bytes will be 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, the user 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.

Note: equivalent functionality is available to the INPUT command via the new READCNT= keyword.

Online HELP for CI Variables and Functions

Information about all CI variables has been supported via HELP since 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.