On Thu, 19 Nov 2020, at 19:30, Charles Mills wrote:
>  I am considering an EXEC that would accept parameters of
> 
> 'a quoted string', 'another quoted string', simpletoken1, simpletoken2, ...

One of the drawbacks of a parameter format like that is that it's
not flexible if you have to support optional parameters (unless you 
specify null or placeholder values).

I preferred (in NetView automation routines mainly) to use named parms, 
not least because it's easier to see which is which, and naming the parms
makes it easier to understand what the execs did (eg in NetView logs).

I wrote and used a routine named #KYWDPRS (keyword parse).  It was (in 
NetView terms) a "loaded clist" which meant that a copy was held in NV's
storage so there was no disk search overhead in using it.  

Callers, eg trying to process an argument string with DEL() and MAX()
values possibly present, would use it like this:

 parse arg allparms                                  
                                                     
 hexkr = '#KYWDPRS'("DEL",allparms)                  
 parse var hexkr '!'khex'!'rhex'!'                   
 delay = x2c(khex) ; allparms = x2c(rhex)            
 if ^datatype(delay,"W") then delay = 1              
                                                     
 hexkr = '#KYWDPRS'("MAX",allparms)                  
 parse var hexkr '!'khex'!'rhex'!'                   
 maxno = x2c(khex) ; allparms = x2c(rhex)            
 if ^datatype(maxno,"W") then maxno = 99999          
                                                     
 if strip(allparms) \== "" then ... unexpected parms 

A local copy that I use on my pc these days, which might not be identical
to the mainframe version - can't tell - is as follows.  It looks a LOT better
in a monospaced font...

/* REXX
   Aids parsing of text that may contain "keyword(parameter value)" in
   any position.  Its purpose is to extract a specified keyword's parm
   value & return both the value and the remaining text to the caller.

   To be recognised "keyword(value)" must be comma-delimited or at the
   start/end of the text string, eg "TYPE(2)" will be recognised in:

       "TYPE(2)"
       "FORMAT(NO),TYPE(2)"
       "TYPE(2),USE(YES)"
       "FORMAT(NO),TYPE(2),USE(YES)"

   but not in: "FORMAT(NO),TYPE(2)-USE(YES)"

   Upper-case copies of the incoming keyword and text are used to find
   where the keyword's value is, however the value itself is extracted
   from the original incoming text, thus allowing mixed-case parameter
   values to be identified.   In other words, "TYpe(2)" and "tYPe(Id)"
   will be located if searching for keyword "type" or "TYPE" while the
   returned value will always be what was passed in, eg "2" or "Id".

   The exec does not explicity distinguish between a text string which
   contains "keyword()" and one with no such parameter, as both return
   a null keyword value.   However, the remaining text will be shorter
   than the incoming text if "keyword()" was found & identical if not.

   Rexx lets us return one value to the caller. It must contain a pair
   of texts, each of which may contain any (or no) characters. Each of
   the texts is converted to its hex representation so that it is null
   or a single 'word' of hex digits, then these are delimited by three
   exclamation marks.

   Call as: hexs = '#KYWDPRS'(kwdm,txtm)
     where: kwdm - keyword to be parsed (mixed case ok) eg "Type"
            txtm - text to be searched  (mixed case ok)
            hexs - is !keyword_value_in_hex|remaining_text_in_hex!

*/
signal on syntax  ;  parse source . invokedby rexxname .
parse arg kwdm,txtm

/* Assume no keyword is present so the keyword-value will be null and */
/* the remaining text will be the same as the incoming text:          */

kval = ""  ;  remt = txtm

/* Define upper-case versions of incoming parameters, and also ensure */
/* we have mixed & upper-case texts with guaranteed enclosing commas: */

kwdu     = translate(kwdm)                 /* eg: "TYPE"              */
txtu     = translate(txtm)                 /* eg: "L,TYPE(ID),R"      */
s_txtm_s = "," || txtm || ","              /* eg: ",L,Type(Id),r,"    */
s_txtu_s = "," || txtu || ","              /* eg: ",L,TYPE(ID),R,"    */

/* Define the left & right delimiters that will mark the keyword:     */

ldelimit = "," || kwdu || "("              /* eg: ",TYPE("            */
ldelimsz = length(ldelimit)                /* eg: 6                   */
rdelimit = "),"                            /* ie: "),"                */

/* We have a valid "keyword(value)" if the left-delimiter is found in */
/* the uppercase comma-enclosed text AND if the right-delimiter is in */
/* the text that follows the left-delimiter:                          */

l_dlm_at = pos(ldelimit,s_txtu_s)
if l_dlm_at == 0 then signal byebye

flw_ldlm = substr(s_txtu_s, l_dlm_at+ldelimsz)
r_dlm_at = pos(rdelimit,flw_ldlm)
if r_dlm_at == 0 then signal byebye

/* There are three text fragments to locate - that preceding the left */
/* delimiter, the one between the delimiters, & the one following the */
/* right-delimiter.  The middle one is the keyword-value & the others */
/* will be concatenated to form the remaining text.                   */

/* We know where the right-delimiter is in the text that followed the */
/* left-delimiter; the middle fragment's size is thus one less.  Then */
/* find the absolute position of the right-delimiter in the text:     */

mfrg_siz = r_dlm_at - 1
r_dlm_at = l_dlm_at + ldelimsz + mfrg_siz

/* Extract the fragment texts from the mixed-case string:             */

lft_frag = substr(s_txtm_s,                   1, l_dlm_at-1)
mid_frag = substr(s_txtm_s, r_dlm_at - mfrg_siz, mfrg_siz)
rgt_frag = substr(s_txtm_s, r_dlm_at + 2)

/* If the left/right fragments are non-null they'll contain commas we */
/* added to the ends of the original text.  These need to be removed: */

l_frg_sz = length(lft_frag)
if l_frg_sz > 0 then lft_frag = right(lft_frag,l_frg_sz-1)

r_frg_sz = length(rgt_frag)
if r_frg_sz > 0 then rgt_frag =  left(rgt_frag,r_frg_sz-1)

/* The remaining text is built from non-null end fragments:           */

l_frg_sz = length(lft_frag)
r_frg_sz = length(rgt_frag)
select
   when l_frg_sz > 0 & r_frg_sz > 0 then remt = lft_frag","rgt_frag
   when l_frg_sz > 0                then remt = lft_frag
   when r_frg_sz > 0                then remt = rgt_frag
   otherwise                             remt = ""
end
kval = mid_frag
signal byebye


byebye: /*------------------------------------------------------------*/
return "!" || c2x(kval) || "!" || c2x(remt) || "!"


syntax: /*------------------------------------------------------------*/
emsg = "REXX err" rc errortext(rc) "l="sigl"="sourceline(sigl)
say rexxname emsg ; signal byebye 


-- 
Jeremy Nicoll - my opinions are my own.

----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to lists...@listserv.ua.edu with the message: INFO IBM-MAIN

Reply via email to