//
// SANE Extended FP to String conversion library
//
include "inc/cmdsys.plh"
include "inc/sane.plh"
include "inc/fpstr.plh"
//
// Structures for DEC2BIN, BIN2DEC
//
struc t_decrecord
    word sgn
    word exp
    byte sig[29]
end
struc t_decformat
    word style
    word digits
end
//
// Parse string into decrecord, return SANE conversion output
//
export def str2ext(str, ext)
    byte i, d
    byte decrec[t_decrecord]
    word sgnadj, expadj

    decrec:sgn  = 0
    decrec:exp  = 0
    decrec.sig  = 0
    i           = 1
    //
    // Skip whitespace
    //
    while ^(str+i) <= ' ' and i <= ^str; i++; loop
    //
    // Check for sign
    //
    if ^(str+i) == '-'
        decrec:sgn = 1
        i++
    elsif ^(str+i) == '+'
        i++
    fin
    //
    // Skip leading zeros
    //
    while i <= ^str and ^(str+i) == '0'
        i++
    loop
    //
    // Parse number
    //
    while i <= ^str
        d = ^(str+i)
        if d >= '0' and d <= '9'
            //
            // Parse digit
            //
            decrec:sig++
            decrec.sig[decrec.sig] = d
        elsif d == '.'
            //
            // Parse decimal point
            //
            i++
            if !decrec.sig
                //
                // Skip leading zeros
                //
                while i <= ^str and ^(str+i) == '0'
                    decrec:exp--
                    i++
                loop
            fin
            while i <= ^str
                d = ^(str+i)
                if d >= '0' and d <= '9'
                    decrec.sig++
                    decrec.sig[decrec.sig] = d
                    decrec:exp--
                elsif d == 'E' or d == 'e'
                    i--
                    break
                else
                    i = ^str
                fin
                i++
            loop
        elsif d == 'E' or d == 'e'
            //
            // Parse exponent
            //
            i++
            expadj = 0
            sgnadj = 1
            if ^(str+i) == '-'
                sgnadj = -1
                i++
            elsif ^(str+i) == '+'
                i++
            fin
            while i <= ^str
                d = ^(str+i)
                i++
                if d >= '0' and d <= '9'
                    expadj = expadj * 10 + (d - '0')
                else
                    i = ^str
                fin
            loop
            decrec:exp = decrec:exp + (sgnadj * expadj)
        else
            i = ^str
        fin
        i++
    loop
    //
    // Strip trailing zeros from sig
    //
    while decrec.sig > 0 and decrec.sig[decrec.sig] == '0'
        decrec.sig--
        decrec:exp++
    loop
    //
    // Check for zero
    //
    if !decrec.sig
        decrec.sig   = 1
        decrec.sig.1 = '0'
        decrec:sgn   = 0
        decrec:exp   = 0
    fin
    sane:saveZP()
    return sane:restoreZP(sane:op2FP(FFEXT|FOD2B, ext, @decrec))
end
//
// Convert extended FP to string using , return string
//
export def ext2str(ext, str, intdigits, fracdigits, format)
    byte d, numdigits
    word istr, dp, tens
    byte decform[t_decformat]
    byte decrec[t_decrecord]

    numdigits      = intdigits + fracdigits
    decform:style  = format & FPSTR_FIXED
    decform:digits = decform:style ?? fracdigits :: numdigits
    decrec:exp     = 0
    sane:saveZP()
    sane:restoreZP(sane:op3FP(FFEXT|FOB2D, @decrec, ext, @decform))
    ^(str+1) = decrec.sgn ?? '-' :: ' '
    if decrec.sig.1 == 'I'
        ^(str+2) = 'I'
        ^(str+3) = 'n'
        ^(str+4) = 'f'
        ^str     = 4
        return str
    fin
    if decrec.sig.1 == 'N'
        ^(str+2) = 'N'
        ^(str+3) = 'a'
        ^(str+4) = 'N'
        ^str     = 4
        return str
    fin
    dp = decrec.sig + decrec:exp
    if format & FPSTR_EXP
        if format & FPSTR_STRIP
            //
            // Strip off trailing fractional zeros
            //
            while decrec.sig > 1 and decrec.sig[decrec.sig] == '0'
                decrec.sig--
                decrec:exp++
            loop
        fin
        //
        // Copy over all significant digits
        //
        ^(str+2) = decrec.sig.1
        ^(str+3) = '.'
        istr = str + 3
        for d = 2 to decrec.sig
            istr++
            ^istr = decrec.sig[d]
        next
        if ^istr == '.'; istr--; fin
        //
        // Print exponent as 4 digits with leading zeros
        //
        istr++
        ^istr = 'E'
        istr++
        dp--
        if dp < 0
            ^istr = '-'
            dp = -dp
        else
            ^istr = '+'
        fin
        tens = 1000
        while tens
            istr++
            ^istr = (dp / tens) + '0'
            dp = dp % tens
            tens = tens / 10
        loop
    else
        if format & FPSTR_STRIP and decrec:exp < 0
            //
            // Strip off trailing fractional zeros
            //
            while decrec.sig > dp and decrec.sig[decrec.sig] == '0'
                decrec.sig--
                decrec:exp++
            loop
        fin
        if decrec:sig == 1 | '0'<<8
            //
            // Case of zero or underflow
            //
            if decrec:exp == 0
                //
                // Zero
                //
                if format & FPSTR_FIXED
                    //
                    // Add trailing fractional zeros
                    //
                    dp = 1 - fracdigits
                fin
            elsif format & FPSTR_FLEX
                //
                // Underflow
                //
                dp = -fracdigits - 1
            fin
        fin
        if format & FPSTR_FLEX and (dp < -fracdigits or dp > (format & FPSTR_FIXED ?? intdigits :: numdigits))
            //
            // Print as exponent if over/underflow fixed digits
            //
            if numdigits < 7; numdigits = 7; fin
            return ext2str(ext, str, 1, numdigits - 7, FPSTR_EXP | (format & FPSTR_STRIP))
        fin
        //
        // Convert as floating point
        //
        if dp <= 0
            *(str+2) = '0'|('.'<<8)
            istr = str + 3
            while dp < 0
                dp++
                istr++
                ^istr = '0'
            loop
        else
            istr = str + 1
        fin
        for d = 1 to decrec.sig
            istr++
            ^istr = decrec.sig[d]
            if d == dp
                istr++
                ^istr = '.'
            fin
        next
        if ^istr == '.'; istr--; fin
    fin
    ^str = istr - str
    return str
end
//
// Keep module in memory
//
return modkeep
done
