U0 SPutChar(U8 **_dst, U8 ch, U8 **_buf)
{
        I64 i;
        U8 *dst = *_dst, *buf;

        if (_buf)
        {
                buf = *_buf;
                i = dst - buf;
                if (i >= MSize(buf))
                {
                        buf = MAlloc(i << 1 + 1);
                        MemCopy(buf, *_buf, i);
                        Free(*_buf);
                        dst = buf + i;
                        *_buf = buf;
                }
        }
        *dst++ = ch;
        *_dst = dst;
}

U0 OutStr(U8 *ptr, U8 **_buf, U8 **_dst, I64 len, I64 flags)
{
        I64 i, j;

        if (!ptr)
                i = 0;
        else
                i = StrLen(ptr);
        if (flags & PRINTF_TRUNCATE && i > len)
                i = len;
        if (flags & PRINTF_LEFT_JUSTIFY)
        {
                for (j = 0; j < i; j++)
                        SPutChar(_dst, *ptr++, _buf);
                for (j = 0; j < len - i; j++)
                        SPutChar(_dst, CH_SPACE, _buf);
        }
        else
        {
                for (j = 0; j < len - i; j++)
                        SPutChar(_dst, CH_SPACE, _buf);
                for (j = len - i; j < len; j++)
                        SPutChar(_dst, *ptr++, _buf);
        }
}

U8 *MPrintTime(CDate cdt)
{
        CDateStruct ds;

        Date2Struct(&ds, cdt + local_time_offset);
        return MStrPrint("%02d:%02d:%02d", ds.hour, ds.min, ds.sec);
}

U8 *MPrintDate(CDate cdt)
{
        CDateStruct ds;

        Date2Struct(&ds, cdt + local_time_offset);
        return MStrPrint("%02d/%02d/%02d", ds.mon, ds.day_of_mon, ds.year % 100);
}

U8 *MPrintQ(U8 *ptr, I64 flags)
{
        U8 **_buf, *buf, **_dst, *dst, buf2[8], *ptr2;
        I64  ch;

        buf = MAlloc(STR_LEN);
        _buf = &buf;
        dst = buf;
        _dst = &dst;
        if (ptr)
                while (ch = *ptr++)
                {
                        switch (ch)
                        {
                                case '$':
                                        if (flags & PRINTF_DOLLAR)
                                        {
                                                SPutChar(_dst, '\\', _buf);
                                                SPutChar(_dst, 'd',  _buf);
                                        }
                                        else
                                        {
                                                SPutChar(_dst, ch, _buf);
                                                SPutChar(_dst, ch, _buf);
                                        }
                                        break;

                                case '%':
                                        SPutChar(_dst, ch, _buf);
                                        if (flags & PRINTF_SLASH)
                                                SPutChar(_dst, ch, _buf);
                                        break;

                                case '\n':
                                        SPutChar(_dst, '\\', _buf);
                                        SPutChar(_dst, 'n',  _buf);
                                        break;

                                case '\r':
                                        SPutChar(_dst, '\\', _buf);
                                        SPutChar(_dst, 'r',  _buf);
                                        break;

                                case '\t':
                                        SPutChar(_dst, '\\', _buf);
                                        SPutChar(_dst, 't',  _buf);
                                        break;

                                case '"':
                                case '\\':
                                        SPutChar(_dst, '\\', _buf);
                                        SPutChar(_dst, ch,   _buf);
                                        break;

                                default:
                                        if (ch >= CH_SPACE && ch != 0x7F)
                                                SPutChar(_dst, ch, _buf);
                                        else
                                        {
                                                StrPrint(buf2, "\\x%02X", ch);
                                                ptr2 = buf2;
                                                while (*ptr2)
                                                        SPutChar(_dst, *ptr2++, _buf);
                                        }
                        }
                }
        SPutChar(_dst, 0, _buf);
        return buf;
}

U8 *MPrintq(U8 *ptr, I64 flags)
{
        U8 **_buf, *buf, **_dst, *dst;
        I64  i, j, ch, ch1;

        buf = MAlloc(STR_LEN);
        _buf = &buf;
        dst = buf;
        _dst = &dst;
        if (ptr)
                while (ch =*ptr++)
                {
                        ch1 = *ptr;
                        switch (ch)
                        {
                                case '\\':
                                        switch (ch1)
                                        {
                                                start:
                                                        case '0':
                                                                SPutChar(_dst, 0,    _buf);
                                                                break;

                                                        case '\'':
                                                                SPutChar(_dst, '\'', _buf);
                                                                break;

                                                        case '\`':
                                                                SPutChar(_dst, '\`', _buf);
                                                                break;

                                                        case '"':
                                                                SPutChar(_dst, '"',  _buf);
                                                                break;

                                                        case '\\':
                                                                SPutChar(_dst, '\\', _buf);
                                                                break;

                                                        case 'd':
                                                                SPutChar(_dst, '$',  _buf);
                                                                break;

                                                        case 'n':
                                                                SPutChar(_dst, '\n', _buf);
                                                                break;

                                                        case 'r':
                                                                SPutChar(_dst, '\r', _buf);
                                                                break;

                                                        case 't':
                                                                SPutChar(_dst, '\t', _buf);
                                                                break;
                                                end:
                                                        ptr++;
                                                        break;

                                                case 'x':
                                                case 'X':
                                                        i = 0;
                                                        ptr++;
                                                        for (j = 0; j < 2; j++)
                                                        {
                                                                ch1 = ToUpper(*ptr++);
                                                                if (Bt(char_bmp_hex_numeric, ch1))
                                                                {
                                                                        if (ch1 <= '9')
                                                                                i = i << 4 + ch1 - '0';
                                                                        else
                                                                                i = i << 4 + ch1 - 'A' + 10;
                                                                }
                                                                else
                                                                {
                                                                        ptr--;
                                                                        break;
                                                                }
                                                        }
                                                        SPutChar(_dst, i, _buf);
                                                        break;

                                                default:
                                                        SPutChar(_dst, ch, _buf);
                                        }
                                        break;

                                case '$':
                                        SPutChar(_dst, ch, _buf);
                                        if (ch1 == '$')
                                                ptr++;
                                        break;

                                case '%':
                                        SPutChar(_dst, ch, _buf);
                                        if (flags & PRINTF_SLASH && ch1 == '%')
                                                ptr++;
                                        break;

                                default:
                                        SPutChar(_dst, ch, _buf);
                        }
                }
        SPutChar(_dst, 0, _buf);
        return buf;
}

U8      *sys_pos_pows_lets = " KMGTPEZY",
        *sys_neg_pows_lets = " munpfazy",
        *sys_pos_pows_list = "kilo\0mega\0giga\0tera\0peta\0exa\0zetta\0yotta\0",
        *sys_neg_pows_list = "milli\0micro\0nano\0pico\0femto\0atto\0zepto\0yocto\0";

#define TMP_BUF_LEN     256
#define SLOP                    8

U8 *StrPrintJoin(U8 *dst, U8 *format, I64 argc, I64 *argv)
{/*Print("") Format Strings
In float formatting, do not exceed 18-digits
before or after the decimal point
because the numbers before and after
the decimal point are stored
in 64-bits.  Use exponentiated forms
to avoid this.
*/
        I64              i, j, l, ch, k, k0, n, n0,
                         len, dec_len, flags, old_flags,
                         aux_format_num, comma_count, comma_format_count, cur_arg=0;
        U64              m;
        F64              d, d1;
        CDoc    *doc;
        U8              *ptr, **_buf, *buf, **_dst, tmp_buf[TMP_BUF_LEN], tmp_buf2[TMP_BUF_LEN*2];

        if (!format)
                throw('StrPrint');
        if (dst)
        {
                _buf = NULL;
                buf  = dst;
        }
        else
        {
                buf  = MAlloc(STR_LEN);
                _buf = &buf;
                dst  = buf;
        }
        _dst = &dst;

        while (ch = *format++)
        {
                if (ch == '%')
                {
                        flags = 0;
                        if (*format == '-')
                        {
                                flags |= PRINTF_LEFT_JUSTIFY;
                                format++;
                        }
                        if (*format == '0')
                        {
                                flags |= PRINTF_PAD_ZERO;
                                format++;
                        }
                        len = 0;
                        while ('0' <= *format <= '9')
                                len = len * 10 + *format++ - '0';
                        if (*format == '*')
                        {
                                format++;
                                if (cur_arg >= argc)
                                        throw('StrPrint');
                                len = argv[cur_arg++];
                        }
                        dec_len = 0;
                        if (*format == '.')
                        {
                                format++;
                                while ('0' <= *format <= '9')
                                        dec_len = dec_len * 10 + *format++ - '0';
                                if (*format == '*')
                                {
                                        format++;
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        dec_len = argv[cur_arg++];
                                }
                                flags |= PRINTF_DECIMAL;
                        }

                        aux_format_num = 0;
                        while (TRUE)
                        {
                                switch (*format)
                                {
                                        start:
                                                case '$':
                                                        flags |= PRINTF_DOLLAR;
                                                        break;

                                                case '/':
                                                        flags |= PRINTF_SLASH;
                                                        break;

                                                case ',':
                                                        flags |= PRINTF_COMMA;
                                                        break;

                                                case 't':
                                                        flags |= PRINTF_TRUNCATE;
                                                        break;

                                                case 'l': //harmless
                                                        break;
                                        end:
                                                format++;
                                                break;

                                        case 'h':
                                                format++;
                                                flags |= PRINTF_AUX_FORMAT_NUM;
                                                if (*format == '?')
                                                {
                                                        format++;
                                                        flags |= PRINTF_QUESTION;
                                                }
                                                else
                                                {
                                                        if (*format == '*')
                                                        {
                                                                format++;
                                                                if (cur_arg >= argc)
                                                                        throw('StrPrint');
                                                                aux_format_num = argv[cur_arg++];
                                                        }
                                                        else
                                                        {
                                                                if (*format == '-')
                                                                {
                                                                        format++;
                                                                        flags |= PRINTF_NEG_AUX_FORMAT_NUM;
                                                                }
                                                                while ('0' <= *format <= '9')
                                                                        aux_format_num = aux_format_num * 10 + *format++ - '0';
                                                                if (flags & PRINTF_NEG_AUX_FORMAT_NUM)
                                                                        aux_format_num = -aux_format_num;
                                                        }
                                                }
                                                break;

                                        default:
                                                goto sp_arg;
                                }
                        }

                        sp_arg:
                        k = 0;
                        switch (*format++)
                        {
                                start:
                                        case 'F':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                if (flags & PRINTF_DOLLAR)
                                                {
                                                        doc = argv[cur_arg++];
                                                        old_flags = doc->flags;
                                                        doc->flags |= DOCF_NO_CURSOR;
                                                        ptr = DocSave(doc);
                                                        doc->flags = old_flags;
                                                }
                                                else
                                                        ptr = FileRead(argv[cur_arg++]);
                                                break;

                                        case 'Q':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                ptr = MPrintQ(argv[cur_arg++], flags);
                                                break;

                                        case 'q':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                ptr = MPrintq(argv[cur_arg++], flags);
                                                break;

                                        case 'D':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                ptr = MPrintDate(argv[cur_arg++]);
                                                break;

                                        case 'T':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                ptr = MPrintTime(argv[cur_arg++]);
                                                break;
                                end:
                                        OutStr(ptr, _buf, _dst, len, flags);
                                        Free(ptr);
                                        break;

                                start:
                                        case 's':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                ptr = argv[cur_arg++];
                                                break;

                                        case 'S':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                ptr = Define(argv[cur_arg++]);
                                                break;

                                        case 'z':
                                                if (cur_arg + 1 >= argc)
                                                        throw('StrPrint');
                                                ptr = ListSub(argv[cur_arg], argv[cur_arg + 1]);
                                                cur_arg = cur_arg + 2;
                                                break;

                                        case 'Z':
                                                if (cur_arg + 1 >= argc)
                                                        throw('StrPrint');
                                                ptr = DefineSub(argv[cur_arg], argv[cur_arg + 1]);
                                                cur_arg = cur_arg + 2;
                                                break;
                                end:
                                        OutStr(ptr, _buf, _dst, len, flags);
                                        break;

                                start:
                                        case 'c':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                tmp_buf[0](I64) = argv[cur_arg++];
                                                tmp_buf[8] = 0;
                                                break;

                                        case 'C':
                                                if (cur_arg >= argc)
                                                        throw('StrPrint');
                                                tmp_buf[0](I64) = argv[cur_arg++];
                                                tmp_buf[8] = 0;
                                                ptr = tmp_buf;
                                                while (*ptr)
                                                {
                                                        *ptr = ToUpper(*ptr);
                                                        ptr++;
                                                }
                                                break;
                                end:
                                        if (!(flags & PRINTF_AUX_FORMAT_NUM))
                                                aux_format_num = 1;
                                        while (aux_format_num-- > 0)
                                                OutStr(tmp_buf, _buf, _dst, len, flags);
                                        break;

                                case 'p':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        StrPrintFunSeg(tmp_buf, argv[cur_arg++], len, flags);
                                        OutStr(tmp_buf, _buf, _dst, len, flags);
                                        break;

                                case 'P':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        StrPrintFunSeg(tmp_buf, argv[cur_arg], len, flags);
                                        if (!IsRaw || !_buf)
                                        {
                                                StrPrint(tmp_buf2, "$LK,\"%s\",A=\"AD:0x%X\"$", tmp_buf, argv[cur_arg]);
                                                OutStr(tmp_buf2, _buf, _dst, len, flags);
                                        }
                                        else
                                                OutStr(tmp_buf, _buf, _dst, len, flags);
                                        cur_arg++;
                                        break;

                                case 'd':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        m = argv[cur_arg++];
                                        if (m(I64) < 0)
                                        {
                                                flags |= PRINTF_NEG;
                                                m = -m;
                                        }
sp_out_dec:
                                        if (flags & PRINTF_AUX_FORMAT_NUM)
                                        {
                                                if (!len)
                                                        len = 12;
                                                d = m;
                                                goto sp_out_eng;
                                        }
                                        if (flags & PRINTF_COMMA)
                                        {
                                                comma_format_count = comma_count = 3;
                                                do
                                                {
                                                        tmp_buf[k++] = ModU64(&m, 10) + '0';
                                                        if (!m)
                                                                break;
                                                        if (!--comma_count)
                                                        {
                                                                tmp_buf[k++] = ',';
                                                                comma_count = 3;
                                                        }
                                                }
                                                while (k < TMP_BUF_LEN - SLOP);
sp_out_comma_num:
                                                if (flags & PRINTF_NEG)
                                                        i = 1;
                                                else
                                                        i = 0;
                                                if (len < 0)
                                                        len = 0;
                                                if (flags & PRINTF_TRUNCATE && k + i > len)
                                                        k = len - i;
                                                if (k < 0)
                                                        k = 0;
                                                if (flags & PRINTF_PAD_ZERO)
                                                {
                                                        if (flags & PRINTF_NEG)
                                                                SPutChar(_dst, '-', _buf);
                                                        comma_count = (len - k - i + comma_format_count - comma_count + 1) % (comma_format_count + 1) + 1;
                                                        for (; i < len - k; i++)
                                                        {
                                                                if (!--comma_count)
                                                                {
                                                                        SPutChar(_dst, ',', _buf);
                                                                        comma_count = comma_format_count;
                                                                        if (++i >= len - k)
                                                                                break;
                                                                }
                                                                SPutChar(_dst, '0', _buf);
                                                        }
                                                }
                                                else
                                                {
                                                        for (; i < len - k; i++)
                                                                SPutChar(_dst, CH_SPACE, _buf);
                                                        if (flags & PRINTF_NEG)
                                                                SPutChar(_dst, '-', _buf);
                                                }
                                        }
                                        else
                                        {
                                                do
                                                {
                                                        tmp_buf[k++] = ModU64(&m, 10) + '0';
                                                        if (!m)
                                                                break;
                                                }
                                                while (k < TMP_BUF_LEN - SLOP);
sp_out_num:
                                                if (flags & PRINTF_NEG)
                                                        i = 1;
                                                else
                                                        i = 0;
                                                if (len < 0)
                                                        len = 0;
                                                if (flags & PRINTF_TRUNCATE && k + i > len)
                                                        k = len - i;
                                                if (k < 0)
                                                        k = 0;
                                                if (flags & PRINTF_PAD_ZERO)
                                                {
                                                        if (flags & PRINTF_NEG)
                                                                SPutChar(_dst, '-', _buf);
                                                        for (; i < len - k; i++)
                                                                SPutChar(_dst, '0', _buf);
                                                }
                                                else
                                                {
                                                        for (; i < len - k; i++)
                                                                SPutChar(_dst, CH_SPACE, _buf);
                                                        if (flags & PRINTF_NEG)
                                                                SPutChar(_dst, '-', _buf);
                                                }
                                        }
                                        for (i = k - 1; i >= 0; i--)
                                                SPutChar(_dst, tmp_buf[i], _buf);
                                        break;

                                case 'u':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        m = argv[cur_arg++];
                                        goto sp_out_dec;

                                case 'f':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        d = argv[cur_arg++](F64);
                                        if (d < 0)
                                        {
                                                flags |= PRINTF_NEG;
                                                d = -d;
                                        }

                                        if (d == inf)
                                        {
sp_out_inf:
                                                if (flags & PRINTF_NEG)
                                                        i = 1;
                                                else
                                                        i = 0;
                                                k = 1;
                                                if (len < 0)
                                                        len = 0;
                                                if (flags & PRINTF_TRUNCATE && k + i > len)
                                                        k = len - i;
                                                if (k < 0)
                                                        k = 0;
                                                for (; i < len - k; i++)
                                                        SPutChar(_dst, CH_SPACE, _buf);
                                                if (flags & PRINTF_NEG)
                                                        SPutChar(_dst, '-', _buf);
                                                for (i = 0; i < k; i++)
                                                        SPutChar(_dst, 'inf', _buf);
                                                break;
                                        }

                                        sp_out_f:
                                        if (dec_len < 0)
                                                dec_len = 0;
                                        n = Log10(d);
                                        if (i = dec_len)
                                        {
                                                if (flags & PRINTF_COMMA)
                                                        i = i - i / 4;
                                                if (n + i > 17)
                                                {
                                                        n += i - 17;
                                                        d *= Pow10I64(i - n);
                                                }
                                                else
                                                {
                                                        n = 0;
                                                        d *= Pow10I64(i);
                                                }
                                                i = dec_len;
                                        }
                                        else if (n > 17)
                                        {
                                                n -= 17;
                                                d *= Pow10I64(-n);
                                        }
                                        else
                                                n = 0;

                                        m = Round(d);
                                        if (flags & PRINTF_COMMA)
                                        {
                                                comma_count = i & 3;
                                                while (i-- && k < TMP_BUF_LEN - SLOP)
                                                {
                                                        if (i > 2 && !comma_count--)
                                                        {
                                                                tmp_buf[k++] = ',';
                                                                comma_count = 2;
                                                                if (!--i)
                                                                        break;
                                                        }
                                                        if (n)
                                                        {
                                                                n--;
                                                                tmp_buf[k++] = '0';
                                                        }
                                                        else
                                                                tmp_buf[k++] = ModU64(&m, 10) + '0';
                                                        if (!i)
                                                                break;
                                                }
                                        }
                                        else
                                        {
                                                while (i-- && k < TMP_BUF_LEN - SLOP)
                                                {
                                                        if (n)
                                                        {
                                                                n--;
                                                                tmp_buf[k++] = '0';
                                                        }
                                                        else
                                                                tmp_buf[k++] = ModU64(&m, 10) + '0';
                                                }
                                        }
                                        if (dec_len)
                                                tmp_buf[k++] = '.';
                                        if (flags & PRINTF_COMMA)
                                        {
                                                comma_count = 3;
                                                do
                                                {
                                                        if (n)
                                                        {
                                                                n--;
                                                                tmp_buf[k++] = '0';
                                                        }
                                                        else
                                                                tmp_buf[k++] = ModU64(&m, 10) + '0';
                                                        if (!m)
                                                                break;
                                                        if (!--comma_count)
                                                        {
                                                                tmp_buf[k++] = ',';
                                                                comma_count = 3;
                                                        }
                                                }
                                                while (k < TMP_BUF_LEN - SLOP);

                                        }
                                        else
                                        {
                                                do
                                                {
                                                        if (n)
                                                        {
                                                                n--;
                                                                tmp_buf[k++] = '0';
                                                        }
                                                        else
                                                                tmp_buf[k++] = ModU64(&m, 10) + '0';
                                                        if (!m)
                                                                break;
                                                }
                                                while (k < TMP_BUF_LEN - SLOP);

                                        }
                                        goto sp_out_num;

                                case 'e':
                                        if (!len)
                                                len = 12;
                                        flags |= PRINTF_TRUNCATE;

                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        d = argv[cur_arg++](F64);
                                        if (d < 0)
                                        {
                                                flags |= PRINTF_NEG;
                                                d = -d;
                                        }
                                        if (d == inf)
                                                goto sp_out_inf;

                                        if (d)
                                                n = Floor(Log10(d));
                                        else
                                                n = 0;
sp_out_e:
                                        d /= Pow10I64(n);

                                        k0 = k;
                                        for (l = 0; l < 2; l++)
                                        {
                                                n0 = n;
                                                if (n < 0)
                                                {
                                                        n = -n;
                                                        flags |= PRINTF_NEG_E;
                                                }
                                                else
                                                        flags &= ~PRINTF_NEG_E;

                                                i = 3;

                                                do tmp_buf[k++] = ModU64(&n, 10) + '0';
                                                while (n && i--);

                                                if (flags & PRINTF_NEG_E)
                                                        tmp_buf[k++] = '-';
                                                tmp_buf[k++] = 'e';
                                                dec_len = len - k - 2;
                                                if (flags & PRINTF_NEG)
                                                        dec_len--;

                                                if (d)
                                                {
                                                        d1 = d + Pow10I64(-dec_len) / 2;
                                                        if (d1 < 1.0)
                                                        {
                                                                d *= 10;
                                                                n = n0 - 1;
                                                                k = k0;
                                                        }
                                                        else if (d1 >= 10)
                                                        {
                                                                d /= 10;
                                                                n = n0 + 1;
                                                                k = k0;
                                                        }
                                                        else
                                                                break;
                                                }
                                                else
                                                        break;
                                        }

                                        goto sp_out_f;

                                case 'g':
                                        if (!len)
                                                len = 12;
                                        flags |= PRINTF_TRUNCATE;
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        d = argv[cur_arg++](F64);
                                        if (d < 0)
                                        {
                                                flags |= PRINTF_NEG;
                                                d = -d;
                                        }
                                        if (d == inf)
                                                goto sp_out_inf;
                                        if (d)
                                                n = Floor(Log10(d));
                                        else
                                                n = 0;
                                        if (n >= len - 1 - dec_len || n < -(dec_len - 1))
                                                goto sp_out_e;
                                        else
                                                goto sp_out_f;

                                case 'n':
                                        if (!len)
                                                len = 12;
                                        flags |= PRINTF_TRUNCATE;
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        d = argv[cur_arg++](F64);
                                        if (d < 0)
                                        {
                                                flags |= PRINTF_NEG;
                                                d = -d;
                                        }
sp_out_eng: //Engineering notation
                                        if (d == inf)
                                                goto sp_out_inf;
                                        if (d)
                                                n = FloorI64(Floor(Log10(d)), 3);
                                        else
                                                n = 0;
                                        d /= Pow10I64(n);

                                        if (n < 0)
                                        {
                                                n = -n;
                                                flags |= PRINTF_NEG_E;
                                        }
                                        if (flags & PRINTF_AUX_FORMAT_NUM && -24 <= n <= 24)
                                        {
                                                if (flags & PRINTF_QUESTION)
                                                {
                                                        if (flags & PRINTF_NEG_E)
                                                                i = -n / 3;
                                                        else
                                                                i = n / 3;
                                                        j = 0;
                                                }
                                                else
                                                {
                                                        if (flags & PRINTF_NEG_E)
                                                                j = -n - aux_format_num;
                                                        else
                                                                j = n - aux_format_num;
                                                        d *= Pow10I64(j);
                                                        i = aux_format_num / 3;
                                                }
                                                if (i < 0)
                                                        tmp_buf[k++] = sys_neg_pows_lets[-i];
                                                else if (i > 0)
                                                        tmp_buf[k++] = sys_pos_pows_lets[i];
                                                else if (len != 0)
                                                        tmp_buf[k++] = CH_SPACE;
                                                if (!(flags & PRINTF_DECIMAL))
                                                {
                                                        dec_len = len - k - 2;
                                                        if (flags & PRINTF_NEG)
                                                                dec_len--;
                                                        if (j > 0)
                                                        {
                                                                if (flags & PRINTF_COMMA)
                                                                        dec_len -= 4 * j / 3;
                                                                else
                                                                        dec_len -= j;
                                                        }
                                                        d1 = d + Pow10I64(-dec_len + 1) / 2;
                                                        if (d1 >= 10)
                                                        {
                                                                dec_len--;
                                                                if (d1 >= 100)
                                                                        dec_len--;
                                                        }
                                                }
                                        }
                                        else
                                        {
                                                i = 3;
                                                do tmp_buf[k++] = ModU64(&n, 10) + '0';
                                                while (n && i--);
                                                if (flags & PRINTF_NEG_E)
                                                        tmp_buf[k++] = '-';
                                                tmp_buf[k++] = 'e';
                                                if (!dec_len)
                                                {
                                                        dec_len = len - k - 2;
                                                        if (flags & PRINTF_NEG)
                                                                dec_len--;
                                                        d1 = d + Pow10I64(-dec_len + 1) / 2;
                                                        if (d1 >= 10)
                                                        {
                                                                dec_len--;
                                                                if (d1 >= 100)
                                                                        dec_len--;
                                                        }
                                                }
                                        }
                                        if (flags & PRINTF_COMMA)
                                        {
                                                if (len && dec_len > 0 && !(dec_len & 3))
                                                        tmp_buf[k++] = ',';
                                                dec_len -= dec_len / 4;
                                        }
                                        goto sp_out_f;

                                case 'X':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        m = argv[cur_arg++];
                                        if (flags & PRINTF_COMMA)
                                        {
                                                comma_format_count = comma_count = 4;
                                                do
                                                {
                                                        tmp_buf[k] = m & 15 + '0';
                                                        if (tmp_buf[k] > '9')
                                                                tmp_buf[k] += 'A' - 0x3A;
                                                        k++;
                                                        m >>= 4;
                                                        if (!m)
                                                                break;
                                                        if (!--comma_count)
                                                        {
                                                                tmp_buf[k++] = ',';
                                                                comma_count = 4;
                                                        }
                                                }
                                                while (k < TMP_BUF_LEN - SLOP);

                                                goto sp_out_comma_num;
                                        }
                                        else
                                        {
                                                do
                                                {
                                                        tmp_buf[k] = m & 15 + '0';
                                                        if (tmp_buf[k] > '9')
                                                                tmp_buf[k] += 'A' - 0x3A;
                                                        k++;
                                                        m >>= 4;
                                                }
                                                while (m && k < TMP_BUF_LEN - SLOP);

                                                goto sp_out_num;
                                        }

                                case 'x':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        m = argv[cur_arg++];
                                        if (flags & PRINTF_COMMA)
                                        {
                                                comma_format_count = comma_count = 4;
                                                do
                                                {
                                                        tmp_buf[k] = m & 15 + '0';
                                                        if (tmp_buf[k] > '9')
                                                                tmp_buf[k] += 'a' - 0x3A;
                                                        k++;
                                                        m >>= 4;
                                                        if (!m)
                                                                break;
                                                        if (!--comma_count)
                                                        {
                                                                tmp_buf[k++] = ',';
                                                                comma_count = 4;
                                                        }
                                                }
                                                while (k < TMP_BUF_LEN - SLOP);

                                                goto sp_out_comma_num;
                                        }
                                        else
                                        {
                                                do
                                                {
                                                        tmp_buf[k] = m & 15 + '0';
                                                        if (tmp_buf[k] > '9')
                                                                tmp_buf[k] += 'a' - 0x3A;
                                                        k++;
                                                        m >>= 4;
                                                }
                                                while (m && k < TMP_BUF_LEN - SLOP);

                                                goto sp_out_num;
                                        }

                                case 'b':
                                case 'B':
                                        if (cur_arg >= argc)
                                                throw('StrPrint');
                                        m = argv[cur_arg++];
                                        if (flags & PRINTF_COMMA)
                                        {
                                                comma_format_count = comma_count = 4;
                                                do
                                                {
                                                        tmp_buf[k++] = m & 1 + '0';
                                                        m >>= 1;
                                                        if (!m)
                                                                break;
                                                        if (!--comma_count)
                                                        {
                                                                tmp_buf[k++] = ',';
                                                                comma_count = 4;
                                                        }
                                                }
                                                while (k < TMP_BUF_LEN - SLOP);

                                                goto sp_out_comma_num;
                                        }
                                        else
                                        {
                                                do
                                                {
                                                        tmp_buf[k++] = m & 1 + '0';
                                                        m >>= 1;
                                                }
                                                while (m && k < TMP_BUF_LEN - SLOP);

                                                goto sp_out_num;
                                        }

                                case '%':
                                        SPutChar(_dst, '%', _buf);
                                        break;
                        }
                }
                else
                        SPutChar(_dst, ch, _buf);
        }
        SPutChar(_dst, 0, _buf);
        return buf;
}

U8 *StrPrint(U8 *dst, U8 *format, ...)
{//See StrPrintJoin().
        return StrPrintJoin(dst, format, argc, argv);
}

U8 *CatPrint(U8 *_dst, U8 *format, ...)
{//StrCat().  See StrPrintJoin().
        U8 *dst = _dst;

        while (*dst)
                dst++;
        StrPrintJoin(dst, format, argc, argv);

        return _dst;
}

U0 Print(U8 *format, ...)
{//Print("") Format Strings.  See StrPrintJoin().
//Don't use this.  See Print() shortcut.
        U8 *buf = StrPrintJoin(NULL, format, argc, argv);

        PutS(buf);//Don't use PutS().  See Print() shortcut.
        Free(buf);
}

U8 *MStrPrint(U8 *format, ...)
{//MAlloc StrPrint.  See StrPrintJoin().
        U8 *res, *buf = StrPrintJoin(NULL, format, argc, argv);

        res = StrNew(buf);
        Free(buf);

        return res;
}

U0 PrintErr(U8 *format, ...)
{//Print "Err:" and message in blinking red.
        U8 *buf = StrPrintJoin(NULL, format, argc, argv);

        GetOutOfDollar;
        "%,p %,p %,p %,p " ST_ERR_ST "%s", Caller, Caller(2), Caller(3), Caller(4), buf;
        Free(buf);
}

U0 PrintWarn(U8 *format, ...)
{//Print "Warn:" and message in blinking red.
        U8 *buf = StrPrintJoin(NULL, format, argc, argv);

        GetOutOfDollar;
        "%,p %,p %,p %,p " ST_WARN_ST "%s", Caller, Caller(2), Caller(3), Caller(4), buf;
        Free(buf);
}