5.5 MPEJXQ1 CI Enhancements

by Jeff Vance
Commercial Systems Division

Introduction

This article is intended for those who would like a more indepth understanding of the CI enhancements introduced in the the MPEJXQ1 MPE/iX 5.5 patch, also known as the "extended filename characters" patch. A freeware, UNSUPPORTED version of this patch is available here! (MPEJXQ1)

Extended Characters for POSIX Filenames

Prior to the JXQ1 patch, characters in POSIX filenames were restricted to upper and lower case letters, numbers, dash, underbar and dot. Now, a POSIX filename can contain the following additional characters:

    ~ ` $ % ^ * + | { } :

A POSIX filename may begin with any supported character except a dash. There are no changes to MPE filename rules. The chances of supporting even more characters in a filename are low until the CI (and maybe the file system) can uniformly support general character escaping. Even if this becomes possible, there are forward compatibility issues in cases where POSIX filenames are blindly processed via CI commands.

There is a companion patch, PXJXQ2, that enables the shell and utilities to support the same characters permitted in JXQ1.

Examples:

      BUILD ./ab$cd:ef
      LISTFILE ./ab$cb:ef,6
      /SYS/PUB/ab$cd:ef

      COPY ./ab$cd:ef  ./~anew%
      LISTFILE ./[a~]@
      ab$cd:ef  ~anew%


Enhancements to the COPY Command

The COPY command has been enhanced to accept MPE-syntax and POSIX-syntax directory names for the TO= parameter. Additionally, a space is an accepted delimiter between the FROM= and TO= arguments.

For example (assume your CWD is /SYS/PUB):

      NEWDIR mydir
      NEWDIR ./mydir
      BUILD ./foo

      COPY ci,   boo       -- creates BOO.PUB.SYS, as always
      COPY ci    mydir     -- creates /SYS/PUB/MYDIR/CI
      COPY ci    ./mydir   -- creates /SYS/PUB/mydir/CI
      COPY ci,   /SYS      -- creates /SYS/CI
      COPY ./foo mydir     -- creates /SYS/PUB/MYDIR/foo
      COPY ./foo ./mydir/  -- creates /SYS/PUB/mydir/foo

If the target name is a directory in POSIX-syntax, a trailing slash may be specified, but is not required. Using a trailing slash may be useful to improve readability in scripts or JCL,

File equations are supported for both the FROM= and TO= parameters. However, the TO= name cannot be a back reference to a file equation who's actual filename is a directory. As before, symbolic links are accepted as the source and/or target filenames.

New Evaluator Functions

The new ANYPARM evaluator function accepts all characters up to a trailing right parentheses and treats them as a single string value.

The new BASENAME evaluator function returns the filename component (base) of a filename.

The new DECIMAL function is analogous to hex() and octal(), in that it converts an integer to its decimal string equivalent.

The new DIRNAME evaluator function returns the directory components of a filename.

The new FQUALIFY evaluator function returns a qualified filename for POSIX or MPE names.

The new FSYNTAX evaluator function returns the syntax of a filename.

The new QUOTE evaluator function returns the input string with all quotemarks doubled.

The new XWORD evaluator function works similarly to the word() function, except, rather than extracting a single word from a string, xword() returns the original string less the word that word() would have extracted based on the same arguments.



ANYPARM() - returns any combination of characters as a string. String function.

Syntax: anyparm(anything)

This new function accepts all characters, including, commas, quotes, right parentheses, etc. and treats them as a single string value. This is handy when used in conjunction with the ANYPARM parameter type.

The anyparm() function has two important restrictions: These constraints are necessary since anyparm() accepts all characters as its argument, including right parentheses.

Examples:

     Assume the script is named "doit":

     ANYPARM p1
     option list
     setvar _infostr ANYPARM(!p1)
     run prog; info="![repl(_infostr,'"','""')]"
     ...

     :doit abc"def'fhi)klm,p,q)r
     setvar _infostr anyparm(abc"def'fhi)klm,p,q)r)
     run prog; info="abc""def'fhi)klm,p,q)r"

Note: in the last example if one of the characters is a "!" then the CI will attempt to reference a variable that follows the "!". For example, if the "f" is replaced by a "!" then the CI will try to reference a variable named HI. If this variable is not found a CI warning is reported.



BASENAME() - returns the filename component of a POSIX or MPE filename. String function.

Syntax: basename(str[,suffix])

This new function returns the base component (file part only) for the passed filename. str can be any filename in MPE or POSIX syntax. suffix is an optional string, that if supplied and the filename base ends in suffix then the suffix is removed from the basename. suffix applies to MPE and POSIX names. The suffix portion of the basename will not be deleted if this results in deleting the entire basename.

Examples:

     CALC basename('a.b.c')
     A

     CALC basename('/a/b/c')
     c

     CALC basename('./a/b')
     b

     CALC basename("./a.sl",".sl")
     a

     CALC basename('/')
     /

     CALC basename("*feq")
     *FEQ

     CALC basename('$null')
     $NULL

     CALC basename('abc.g','c')
     AB

     CALC basename('/usr/lib/liby.a','.a')
     liby

     CALC basename('/usr/lib/liby.a','liby.a')
     liby.a



DECIMAL() - returns a string value of an integer. String function.

Syntax: decimal(int)

This new function behaves analogously to the existing hex() and octal() functions. It accepts a single integer argument and functionally returns the decimal string equivalent.

Examples:

      CALC decimal(255)
      255              <-- as a string
      
      CALC len(decimal($ff))
      3, $3, %3

      setvar i 0
      while setvar(i,i+1) < 10 and &
            finfo("FILE"+DECIMAL(i), 'exists') do
      ... 

The last example is significant since this is the only case where explicit variable substitution ('!varname') does not work as an alternative to decimal. If the finfo() line was written as:

            finfo("FILE"+"!i", 'exists') do

then the first iteration would call FINFO on a file named 'FILE0' rather than a file named 'FILE1'. This is because explicit variable dereferencing is performed early by the CI, well before the setvar() function is called.



DIRNAME() - returns the directory components of a POSIX or MPE filename. String function.

Syntax: dirname(str)

This new function returns the directory components for the passed filename. str can be any filename in MPE or POSIX syntax. MPE filenames are converted to POSIX names before extracting the directory portion of the name.

Examples:

     CALC dirname('a.b.c')
     /C/B

     CALC dirname('/a/b/c')
     /a/b

     CALC dirname('./a/b')
     ./a

     CALC dirname("./a.sl")
     .

     CALC dirname('/')
     /

     CALC dirname("*feq")
     [empty string]

     CALC dirname('$null')
     [empty string]

     CALC dirname('abc.g')
     /SYS/G

     CALC dirname(fqualify('./a'))
     /ACCOUNT/GROUP     # when the CWD is your logon group  -- or --
     /CWD               # when the CWD is a directory



FQUALIFY() - returns a fully qualified filename. String function.

Syntax: fqualify(str)

This new function returns the qualified filename for the passed filename in str. str can be any filename in MPE or POSIX syntax. str is first attempted to be translated into an MPE name. If that fails it is converted into a POSIX name. POSIX names are prepended with the CWD for relative pathnames.

Examples:

     CALC fqualify('a')   
     A.GROUP.ACCOUNT    # when the CWD is your logon group  -- or --
     /CWD/A             # when the CWD is a directory

     CALC fqualify('a.b')  
     A.B.ACCOUNT

     CALC fqualify('a.b.c')
     A.B.C

     CALC fqualify('./a')  
     /ACCOUNT/GROUP/a

     CALC fqualify('./A')
     A.GROUP.ACCOUNT    # when the CWD is your logon group  -- or --
     /CWD/A             # when the CWD is a directory

     CALC fqualify('/a/b/c')
     /a/b/c          

     CALC fqualify('*a')  
     *A    

     CALC fqualify('$null')
     $NULL           

     CALC dirname(fqualify('./a'))
     /ACCOUNT/GROUP     # when the CWD is your logon group  -- or --
     /CWD               # when the CWD is a directory



FSYNTAX() - returns the syntax of the passed filename argument. String function.

Syntax: fsyntax(filename_str)

This new function accepts an MPE or POSIX style filename and evaluates the filename's syntax, if wildcard characters are present, lockwords, back reference to a file equation, remote environment IDs and system defined files. If an error occurs the error number, following the word "ERROR" is returned. Possible return values are:

     - "MPE" "MPE;WILD" "MPE;LOCK" "MPE;FEQ" "MPE;$FILE"
       "MPE;REMOTE"  and combinations where appropriate, e.g.,
       "MPE;LOCK,REMOTE"

     - "POSIX" "POSIX;WILD"

     - "ERROR=nnn" for syntax error nnn

Examples:

     fsyntax('a.b.c')
     MPE
     fsyntax('/a/b/c')
     POSIX
     fsyntax('./ab@/c')
     POSIX;WILD
     fsyntax('$null')
     MPE;$FILE
     fsyntax('a.b.c.d')
     ERROR=426

     if word(setvar(_error, FSYNTAX(myfile))) = "ERROR" then
        echo Syntax error: ![word(_error,,-1)]
     endif

     if word(FSYNTAX(a_file)) = "MPE" then
        # MPE filename
     elseif word(FSYNTAX(a_file)) = "POSIX" then
        # POSIX filename
     else
        # error

     if pos("WILD", FSYNTAX(another_file)) > 0 then
        # wildcarded MPE or POSIX filename



QUOTE() - returns the input string with all quotemarks doubled. String function. Note: the quote function will not exist on MPE/iX release 6.0 and later. The repl() function provides very similar functionality. Also, it may be incorrect for the quote function to double both kinds of quotemarks inside INFO= strings, for instance.

Syntax: quote(str)

This new function scans str and doubles all single and double quote characters found. This is useful when str is passed to CI parameter that requires its own quotes, like an INFO= string, or a quoted string value in the SETVAR command.

Examples:

     calc QUOTE('abc"de""f')
     abc""de""""f

     calc QUOTE("xyz'z'y'")
     xyz''z''y''

     calc anyparm(abc'def"ghi)k)
     abc'def"ghi)k
     calc QUOTE(hpresult)
     abc''def""ghi)k

     setvar x quote('ab"c')
     showvar x
     X = ab""c
     setvar x "!x"
     showvar x
     X = ab"c

The last example shows that the CI does quote folding in expressions, e.g., "ab""c" is folded to the string ab"c.



XWORD() - returns a string less 'word'. String function.

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

This new function locates the nth word from str beginning at start, delimited by one of the characters in delims, and places the index of the delimiter that terminated the word in a CI variable named by the end_var argument. It returns str minus the located word and minus the word delimiter. It is syntatically equivalent to word(), but opposite in semantics.

xword() is usefull for removing a token from a command line string since the token and its delimiter are not returned.

Please refer to WORD for a description of the arguments to xword() and examples of using word().

The same examples used for the word() function are repeated below for xword():

      xword('file a=bb,old;rec=40,,f,ascii')           returns:
                                     'a=bb,old;rec=40,,f,ascii'

      xword('file a=bb,old;rec=40,,f,ascii',,2)        returns:
                                  'file bb,old;rec=40,,f,ascii'

      xword('file a=bb,old;rec=40,,f,ascii',";,",,j,8) returns:
                                   'file a=old;rec=40,,f,ascii' and J=10

      xword('file a=bb,old;rec=40,,f,ascii',,-4,j)     returns:
                                   'file a=bb,old;rec=,f,ascii' and J=18

It may be illustrative to execute the above examples substituting word in place of xword, or refer the word examples referenced above.