zOs/REXX/MATCH

/* copy match begin **************************************************/
/*--- wildCard matching with the following wildchars:
          * 0-n chars
          ? 1 char
      fill matched expressions instem st if st is non empty
      return 1 if mask matches wert ---------------------------------*/
match: procedure expose m.
parse arg wert, mask
    if symbol('m.match_m.mask') == 'VAR' then
        interpret m.match_m.mask
    else
        interpret matchGen('MATCH_M.'mask, mask, 'm')
endProcedure match

matchGG: procedure expose m.
parse arg wert, cd, vars
    interpret cd
endProcedure matchGG

matchVars: procedure expose m.
parse arg wert, mask, vars
    if symbol('m.match_v.mask') == 'VAR' then
        interpret m.match_v.mask
    else
        interpret matchGen('MATCH_V.'mask, mask, 'v')
endProcedure match

matchRep: procedure expose m.
parse arg wert, mask, mOut
    vars = 'MATCH_VV'
    mm = mask'\>'mOut
    if symbol('m.match_r.mm') == 'VAR' then
        interpret m.match_r.mm
    else
        interpret matchGen('MATCH_R.'mm, mask, 'r', mOut)
endProcedure matchRep

matchGen: procedure expose m.
parse arg m, mask, opt, mOut
    a = matchScan(match_sM, mask)
    if symbol('m.match_g') \== 'VAR' then
        m.match_g = 0
    if opt \== 'r' then do
        r = matchgenMat(a, opt, 1, m.a.0, 0)
        end
    else do
        m.match_g = m.match_g + 1
        sub = 'MATCH_G'm.match_g
        m.sub = matchgenMat(a, 'v', 1, m.a.0, 0)
        o = matchScan(match_sO, mOut)
        r = matchGenRep(o, m.a.wildC)
        r = 'if matchGG(wert, m.'sub', vars) then return' r';' ,
            'else return "";'
        end
    m.m = r
    return r
endProcedure matchGen

matchScan: procedure expose m.
parse arg a, mask, opt
    s = match_scan
    call scanSrc s, mask
    ax = 0
    vx = 0
    m.a.wildC = ''
    do forever
        if scanUntil(s, '*?&\') then do
            if m.a.ax == 'c' then do
                m.a.ax.val = m.a.ax.val || m.s.tok
                end
            else do
                ax = ax + 1
                m.a.ax = 'c'
                m.a.ax.val = m.s.tok
                end
            end
        else if scanChar(s, 1) then do
            if pos(m.s.tok, '*?') > 0 then do
                ax = ax + 1
                vx = vx + 1
                m.a.ax = m.s.tok
                m.a.ax.ref = vx
                m.a.wildC = m.a.wildC || m.s.tok
                end
            else if m.s.tok == '\' then do
                call scanChar s, 1
                if pos(m.s.tok, '\*?&') < 1 then
                    return scanErr(s, 'bad char after \')
                if abbrev(m.a.ax, 'c') then
                    m.a.ax.val = m.a.ax.val || m.s.tok
                else do
                    ax = ax + 1
                    m.a.ax = 'c'
                    m.a.ax.val = m.s.tok
                    end
                end
            else if m.s.tok == '&' then do
                if opt \== 'r' then
                    call scanErr s, '& in input'
                if \ scanChar(s,1) | pos(m.s.tok, 'ms123456789')<1 then
                    call scanErr s, 'bad & name' m.s.tok
                ax = ax + 1
                m.a.ax = '&'
                m.a.ax.ref = m.s.tok
                end
            else
                call scanErr s, 'bad char 1 after until'
            end
        else
            leave
        end
    m.a.0 = ax
    if vx \== length(m.a.wildC) then
        call scanErr 'vars' m.a.wildC 'mismatches' vx
    return a
endProcedure matchScan

matchGenMat: procedure expose m.
parse arg a, opt, fx, tx, minLL
    ml = 0
    if fx == 1 then do
        do ax=1 to m.a.0
            if m.a.ax == '?' then
               ml = ml + 1
            else if m.a.ax == 'c' then
               ml = ml + length(m.a.ax.val)
            m.a.minLen.ax = ml
            end
        end
    r = ''
    ret1 = ''
    ret1After = ''
    lO = 0
    do fy=fx to tx
        if m.a.fy == 'c' then do
            r = r 'if substr(wert,' (1+lO)
            if fy < m.a.0 then
                r = r',' length(m.a.fy.val)
            r = r') \==' quote(m.a.fy.val, "'") 'then return 0;'
            lO = lO + length(m.a.fy.val)
            end
        else if m.a.fy == '?' then do
            lO = lO + 1
            if opt == 'v' then
                ret1 = ret1 'm.vars.'m.a.fy.ref ,
                        '= substr(wert,' lO', 1);'
            end
        else if m.a.fy == '*' then
            leave
        else
            call err 'bad match ast' a'.'fy m.a.fy
        end
    rO = 0
    do ty=tx by -1 to fy
        if m.a.ty == 'c' then do
            rO = rO + length(m.a.ty.val)
            r = r 'if substr(wert, length(wert) -' (rO - 1)',' ,
                  length(m.a.ty.val)')' ,
                  '\==' quote(m.a.ty.val, "'") 'then return 0;'
            end
        else if m.a.ty == '?' then do
            rO = rO + 1
            if opt == 'v' then
                ret1 = ret1 'm.vars.'m.a.fy.ref ,
                        '= substr(wert, length(wert) -' (rO-1)', 1);'
            end
        else if m.a.ty ==  '*' then
            leave
        else
            call err 'bad match ast' a'.'fy m.a.fy
        end
    if fy > ty then do /* every thing is handled with fix len */
        if fx = tx & abbrev(m.a.fx, 'c') then
            r = 'if wert \==' quote(m.a.fx.val, "'") ,
                               'then return 0;'
        else
            r = 'if length(wert) \==' (lO + rO) 'then return 0;' r
        end
    else do
        myMiLe = m.a.minLen.ty
        if fy > 1 then do
            fq = fy -1
            myMiLe = myMiLe - m.a.minLen.fq
            end
        if minLL < myMiLe then
            r = 'if length(wert) <' myMiLe 'then return 0;' r
        if fy = ty & m.a.fy == '*' then     /* single * */
            ret1  = ret1 'm.vars.'m.a.fy.ref ,
                 '= substr(wert,' (1+lO)', length(wert) -' (lO+rO)');'
        else if fy < ty & abbrev(m.a.fy, '*') ,
                        & abbrev(m.a.ty, '*') then do
                                /* several variable length parts */
            suMiLe = m.a.minLen.ty - m.a.minLen.fy
            m.match_g = m.match_g + 1
            sub = 'MATCH_G'm.match_g
            m.sub = matchGenMat(a, opt, fy+1, ty, suMiLe)
            if rO = 0 then
                subV = 'substr(wert, lx)'
            else do
                r = r 'wSub = left(wert, length(wert) -' rO');'
                subV = 'substr(wSub, lx)'
                end
            r = r 'do lx = length(wert) -' (suMiLe+rO-1) ,
                       'by -1 to' (lO+1)';' ,
                       'if \ matchGG('subV', m.'sub', vars) then' ,
                            'iterate;'
            ret1  = ret1 'm.vars.'m.a.fy.ref '= substr(wert,' (lO+1) ,
                     ||  ', lx -' (lO+1)');'
            ret1After = 'end; return 0;'
            end
        else
            call err 'matchGenMat bad case' a'.'fy m.a.fy a'.'ty m.a.ty
        end
    if opt == 'v' & fx == 1 then do
        if r <> '' then
           r = 'm.vars.0 = -9;' r
        ret1 = ret1 'm.vars.0 =' length(m.a.wildC)';'
        end
    r = r ret1 'return 1;' ret1After
    return r
endProcedure matchGenMat

matchGenRep: procedure expose m.
parse arg o, wildC
    xQ = 0
    xS = 0
    do ox=1 to m.o.0
        if m.o.ox == '?' then do
             xQ = pos('?', wildC, xQ+1)
             if xQ < 1 then
                 call err 'unmatchted ?' ox
             m.o.ox.re2 = xQ
             end
        else if m.o.ox == '*' then do
             xS = pos('*', wildC, xS+1)
             if xS < 1 then
                 call err 'unmatchted *' ox
             m.o.ox.re2 = xS
             end
        else if m.o.ox == '&' & m.o.ox.ref >> '0' then do
            if m.o.ox.ref > length(wildC) then
                 call err '&'m.o.ox.ref 'but wildcards' wildC
            xQ = m.o.ox.ref
            xS = xQ
            m.o.ox.re2 = xQ
            end
        end
    r = ''
    do ox=1 to m.o.0
        if abbrev(m.o.ox, 'c') then
            r = r '||' quote(m.o.ox.val, "'")
        else if m.o.ox == '&' & m.o.ox.re2 == 's' then
            r = r '|| wert'
        else if m.o.ox == '&' & m.o.ox.re2 == 'm' then
            r = r '||' quote(mask, "'")
        else if pos(m.o.ox, '*?&') > 0 then
            r = r '|| m.vars.'m.o.ox.re2
        end
    if r=='' then
        return "''"
    else
        return substr(r, 5)
endProcedure matchGenRep

/* copy match end ****************************************************/