ZealOS/src/Kernel/StrPrint.ZC

1145 lines
22 KiB
HolyC
Executable file
Raw Blame History

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 = " m<>npfazy",
*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)
{/*$LK,"Print(\"\") Format Strings",A="FI:::/Doc/Print.DD"$
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 == <EFBFBD>)
{
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, '<EFBFBD>', _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 == <EFBFBD>)
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 == <EFBFBD>)
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 == <EFBFBD>)
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 $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
return StrPrintJoin(dst, format, argc, argv);
}
U8 *CatPrint(U8 *_dst, U8 *format, ...)
{//StrCat(). See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
U8 *dst = _dst;
while (*dst)
dst++;
StrPrintJoin(dst, format, argc, argv);
return _dst;
}
U0 Print(U8 *format, ...)
{//$LK,"Print(\"\") Format Strings",A="FI:::/Doc/Print.DD"$. See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
//Don't use this. $LK,"See Print() shortcut.",A="FF:::/Doc/ZealC.DD,DemoZealC"$
U8 *buf = StrPrintJoin(NULL, format, argc, argv);
PutS(buf);//Don't use PutS(). $LK,"See Print() shortcut.",A="FF:::/Doc/ZealC.DD,DemoZealC"$
Free(buf);
}
U8 *MStrPrint(U8 *format, ...)
{//MAlloc StrPrint. See $LK,"StrPrintJoin",A="MN: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 <20> %,p <20> %,p <20> %,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 <20> %,p <20> %,p <20> %,p " ST_WARN_ST "%s", Caller, Caller(2), Caller(3), Caller(4), buf;
Free(buf);
}