zOs/REXX.O13/F

/* copy f begin *******************************************************/
f: procedure expose m.
parse arg ggFmt, ggA1, ggA2
    if symbol('M.f.fmt.ggFmt') == 'VAR' then
        interpret M.f.fmt.ggFmt
    else
        interpret fGen(ggFmt)
endProcedure f

fAll: procedure expose m.
parse arg fmt
    do forever
        o = inO()
        if o == '' then
            return
        call out f(fmt, o)
        end
endProcedure f

/*--- format character2hex (if not sql null) -------------------------*/
fH: procedure expose m.
parse arg v, l
    if v \== m.sqlNull then
        v = c2x(v)
    if l >= 0 then
        return right(v, l)
    else
        return left(v, -l)
endProcedure fH

/*--- format integer or fixPoint Decimal -----------------------------*/
fI: procedure expose m.
parse arg v, l, d
    if datatype(v, 'n') then do
        if d == '' then
            v = format(v, ,0,0)
        else
            v = format(v, ,d,0)
        if abbrev(l, '+') then
            if \ abbrev(v, '-') then
                v = '+'v
        if length(v) > abs(l) then
            return right('', abs(l), '*')
        end
    if l >= 0 then
        return right(v, l)
    else
        return left(v, -l)
endProcedure fI

/*--- format floating point in E notitaion ---------------------------*/
fE: procedure expose m.
parse arg v, l, d, eChar
    if eChar == '' then
        eChar = 'e'
    if \ datatype(v, 'n') then
        return left(v, l)
    else if l = 7 then
        return fEStrip(format(v, 2, 2, 2, 0), 0, 2, 0, 2, eChar)
    else if l = 8 then
        return fEStrip(format(v, 2, 2, 2, 0), 1, 2, 0, 2, eChar)
    else if l < 7 then
        call err 'bad width fE('v',' l',' d')'
    else if d == '' then
        return fEStrip(format(v, 2, l-6, 2, 0), 1, l-6, 0, 2, eChar)
    else if l - d - 5 < 1 then
        call err 'bad prec fE('v',' l',' d')'
    else
        return fEStrip(format(v, 2, d, l-d-5, 0), 1, d, 1, l-d-5, eChar)
endProcedure fE

fEStrip: procedure expose m.
parse arg v, mSi, de, eSi, ePr, eChar
    parse var v ma 'E' ex
    if ex == '' then do
        ma = strip(ma, 't')
        ex = '+'left('', ePr, 0)
        end
    if eSi == 0 then do
        if abbrev(ex, '+') then
            ex = substr(ex, 2)
        else if abbrev(ex, '-0') then
            ex = '-'substr(ex, 3)
        else do
            exO = ex
            ex = left('-9', ePr, '9')
       /*   say 'format('ma '* (1E'exO') / (1E'ex'), 2,' de', 0)' */
            ma = format(ma * ('1E'exO) / ('1E'ex), 2, de, 0)
            end
        end
    if mSi == 0 then
        if abbrev(ma, ' ') then
            ma = substr(ma, 2)
        else
            ma = format(ma, 2, de-1)
    r = ma || eChar || ex
    if length(r) - length(eChar) <> 2 + mSi + de + eSi + ePr then
        call err 'bad fEStrip('v',' mSi',' de',' eSi',' ePr',' eChar ,
             || ') ==>' r 'bad len' length(r)
    return r
endProcedure fEStrip
/*--------------------------------------------------------------------
fGen: Format generator    should be compatible with fPrint|
 <<<< + extension of fPrint, - in fPrint but not implemented

 + \s   a single space
 + \n   a newLine
 + \%  \@ \\ the escaped char
   ('@' argN? '.'? field)?'%' flags? width? ('.' precision)? specifier
 specifier: is the most significant one and defines the type

 - c Character a
 - C Cut %-nC = left(v,n), %nC = right(v,n) %n.mC = substr(m, n)
 - d or i Signed decimal integer
 - e Scientific notation (mantissa/exponent) using e character 3.9265e+2
 - E Scientific notation (mantissa/exponent) using E character 3.9265E+2
 - f Decimal floating point
 - g Use the shorter of %e or %f
 - G Use the shorter of %E or %f
 - h Characters in hex
 - o Unsigned octal 610
 - S Strip(..., both)
 - u Unsigned decimal integer
 - x Unsigned hexadecimal integer
 - X Unsigned hexadecimal integer (capital letters)
 - p Pointer address
 - n Nothing printed. The argument must be a pointer to a signed int, wh
 + % A % followed by another % character will write % to stdout. %
 + Q for iterator first nxt end
 Flags:
 - - Left-justify within the given field width; Right justification is
 - + Forces to precede the result with a plus or minus sign (+ or -)
 - (space) If no sign is going to be written, a blank space is inserte
 - # Used with o, x or X specifiers the value is preceeded with 0, 0x
         force decimalpoint ...
 - 0 Left-pads the number with zeroes (0) instead of spaces, where pad
 + = reuse previous input argument

 length not implemented
----------------------------------------------------------------------*/
fGen: procedure expose m.
parse arg src, key
    if key == '' then do
        qSuf = right(src, 3)
        if length(qSuf) == 3 & abbrev(qSuf, '%Q') then
            s2 = left(src, length(src) - 3)
        else
            s2 = src
        call fGen s2, s2
        if symbol('m.f.fmt.src') == 'VAR' then
            return m.f.fmt.src
        call err fGen 'format' src 'still undefined'
        end
    call scanIni
    cx = 1
    ky = key
    do forever
        cy = pos('%q', src, cx)
        if cy < 1 then do
            m.f.fmt.ky = fGenCode(substr(src, cx), 'F.INFO.'ky)
            leave
            end
        m.f.fmt.ky = fGenCode(substr(src, cx, cy-cx), 'F.INFO.'ky)
        if substr(src, cy, 3) == '%q^' then do
            if substr(src, cy, 5) == '%q^%q' then
                cy = cy+3
            else if length(src) = cy + 2 then
                leave  /* do not overrite existing fmt | */
            end
        if cy > length(src)-2 then
            call err 'bad final %q in' src
        if substr(src, cy, 3) == '%q^' then
            ky = key
        else
            ky = key'%Q'substr(src, cy+2, 1)
        m.f.tit.ky.0 = 0
        cx = cy+3
        end
    if symbol('m.f.fmt.key') == 'VAR' then
        return m.f.fmt.key
    call scanErr fGen 'format' src 'still undefined'
endProcedure fGen

fGenCode: procedure expose m.
parse arg aS, jj
    jx = 0
    call scanSrc fGen, aS
    call scanSrc fGen, aS
    ax = 0
    cd = ''
    do forever
        txt = fText()
        if txt \== '' then
            cd = cd '||' quote(txt, "'")
        if scanEnd(fGen) then do
            m.jj.0 = jx
            if cd \== '' then
                return "return" substr(cd, 4)
            else
                return "return ''"
            end
        an = ''
        af = '-'
        if \ scanLit(fGen, '@') then do
            ax = ax + 1
            end
        else do
            if scanWhile(fGen, '0123456789') then
                ax = m.fGen.tok
            else if ax < 1 then
                ax = 1
            if substr(m.fGen.src, m.fGen.pos, 1) \== '%' then do
                call scanLit fGen, '.'
                af = fText()
                end
            end
        if \ scanLit(fGen, '%') then
            call scanErr fGen, 'missing %'
        call scanWhile fGen, '-+'
        flags = m.fGen.tok
        call scanWhile fGen, '0123456789'
        len   = m.fGen.tok
        siL = len
        if len \== '' & flags \== '' then
            siL = left(flags, 1)len
        prec  = ''
        if scanLit(fGen, '.') then do
            if len == '' then
                call scanErr fGen, 'empty len'
            call scanWhile fGen, '0123456789'
            prec = m.fGen.tok
            end
        call scanChar fGen, 1
        sp = m.fGen.tok
        if ax < 3 then
            aa = 'ggA'ax
        else
            aa = 'arg(' || (ax+1) || ')'
        if af \== '-' then do
            if af \== '' then
                af = '.'af
            if abbrev(aa, 'ggA') & pos('.GG', af) < 1 ,
                 & translate(af) == af then
                aa = 'm.'aa || af
            else
                aa = 'mGet('aa '||' quote(af, "'")')'
            end
        if sp = 'c' then do
            pd = word('rigPad lefPad', (pos('-', flags) > 0)+1)
            if prec \== '' then
                cd = cd '||' pd'(substr('aa',' prec'),' len')'
            else
                cd = cd '||' pd'('aa',' len')'
            end
        else if sp = 'C' then do
            if prec \== '' then
                cd = cd '|| substr('aa',' prec',' len')'
            else if pos('-', flags) > 0 then
                cd = cd '|| left('aa',' len')'
            else
                cd = cd '|| right('aa',' len')'
            end
        else if sp == 'H' then
            cd = cd "|| fH("aa", '"siL"')"
        else if sp == 'h' then
            cd = cd "|| translate(fH("aa", '"siL"'), 'abcdef','ABCDEF')"
        else if sp == 'i' then do
            cd = cd "|| fI("aa", '"siL"'"
            if prec == '' then
                cd = cd')'
            else
                cd = cd',' prec')'
            end
        else if sp == 'E' | sp == 'e' then
            cd = cd "|| fE("aa"," len"," prec", '"sp"')"
        else if sp == 's' then
            cd = cd '||' aa
        else if sp = 'S' then
            cd = cd '|| strip('aa')'
        else
            call scanErr fGen, 'bad specifier' sp
        jx = jx + 1
        m.jj.jx.arg = ax
        m.jj.jx.name = af
        end
endProcedure fGenCode

fText: procedure expose m. ft.
    res = ''
    do forever
        if scanUntil(fGen, '\@%') then
            res = res || m.fGen.tok
        if \ scanLit(fGen, '\') then
            return res
        call scanChar fGen, 1
        if pos(m.fGen.tok, 's\@%') < 1 then
            res = res'\' || m.fGen.tok
        else
            res = res || translate(m.fgen.tok, ' ', 's')
        end
endProcedure fText

/* copy f end   *******************************************************/