#include "Core.h" //#BLITZ_APPROVE #include NAMESPACE_UPP // Old format --------------------------- String VFormat(const char *fmt, va_list ptr) { int limit = 2 * (int)strlen(fmt) + 1024; Buffer buffer(limit); vsprintf(buffer, fmt, ptr); va_end(ptr); int len = (int)strlen(buffer); ASSERT(len <= limit); return String(buffer, len); } // Formatting routines --------------------------- String FormatIntBase(int i, int base, int width, char lpad, int sign, bool upper) { enum { BUFFER = sizeof(int) * 8 + 1 }; ASSERT(base >= 2 && base <= 36); char buffer[BUFFER]; char *const e = buffer + (int)BUFFER; char *p = e; const char *itoc = upper ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz"; if(sign < 0 || !IsNull(i)) { unsigned x = i; if(sign >= 0 && i < 0) x = -i; do *--p = itoc[x % base]; while(x /= base); } bool minus = (sign >= 0 && i < 0 && !IsNull(i)); bool do_sign = (sign > 0 || sign >= 0 && minus); if(do_sign && lpad != '0') *--p = (minus ? '-' : '+'); if(width > e - p) { char *b = e - min(width, BUFFER); while(p > b) *--p = lpad; } if(do_sign && lpad == '0') *--p = (minus ? '-' : '+'); int dwd = (int)(e - p); int pad = (width = max(width, dwd)) - dwd; StringBuffer out(width); char *o = out; if(dwd < width) memset(o, lpad, pad); memcpy(o + pad, p, dwd); return out; } String FormatInt(int i) { return FormatIntBase(i, 10, 0, ' ', 0); } String FormatIntDec(int i, int width, char lpad, bool always_sign) { return FormatIntBase(i, 10, width, lpad, always_sign ? 1 : 0); } String FormatIntHex(int i, int width, char lpad) { return FormatIntBase(i, 16, width, lpad, -1); } String FormatIntHexUpper(int i, int width, char lpad) { return FormatIntBase(i, 16, width, lpad, -1, true); } String FormatIntOct(int i, int width, char lpad) { return FormatIntBase(i, 8, width, lpad, -1); } String FormatIntAlpha(int i, bool upper) { if(IsNull(i) || i == 0) return Null; String out; if(i < 0) { out << '-'; i = -i; } char temp[10], *p = temp; i--; char start = (upper ? 'A' : 'a'); do *p++ = start + (i % 26); while(i /= 26); while(p > temp) out << *--p; return out; } String FormatIntRoman(int i, bool upper) { if(IsNull(i) || i == 0) return Null; String out; if(i < 0) { out << '-'; i = -i; } int m = i / 1000; if(m) { out.Cat('M', m); i -= 1000 * m; } char shift = upper ? 0 : 'a' - 'A'; static const int value[] = { 1000, 500, 100, 50, 10, 5, 1 }; static const char letter[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' }; for(int n = 0; i && n < __countof(value); n++) { int v = value[n]; while(i >= v) { out << (char)(letter[n] + shift); i -= v; } if(n < __countof(value) - 1) for(int j = n + (value[n + 1] * 2 >= v ? 2 : 1); j < __countof(value); j++) if(i >= v - value[j]) { // subtraction scheme out << (char)(letter[j] + shift) << (char)(letter[n] + shift); i -= v - value[j]; break; } } return out; } String Format64(uint64 a) { char b[50]; char *p = b + 50; do { *--p = char(a % 10 + '0'); a /= 10; } while(a); return String(p, b + 50); } String Format64Hex(uint64 a) { char b[50]; char *p = b + 50; do { *--p = "0123456789abcdef"[a & 15]; a >>= 4; } while(a); return String(p, b + 50); } String FormatInteger(int a) { return IsNull(a) ? String() : FormatInt(a); } String FormatUnsigned(unsigned long a) { return Sprintf("%u", a); } String FormatDouble(double a) { return IsNull(a) ? String() : IsNaN(a) ? "?" : FormatDouble(a, 10, FD_REL); } String FormatBool(bool a) { return a ? "true" : "false"; } String FormatPtr(const void *p) { return "0x" + FormatHex(p); } String FormatInt64(int64 a) { return IsNull(a) ? String() : a < 0 ? "-" + Format64(-a) : Format64(a); } static char *PutDigits(char *out, unsigned number, int count) { char temp[10]; char *t = temp; do *t++ = number % 10 + '0'; while(number /= 10); ASSERT(t - temp <= __countof(temp)); if((count -= (int)(t - temp)) > 0) { char *e = out + count; while(out < e) *out++ = '0'; } while(t > temp) *out++ = *--t; return out; } enum { DBL_DIGITS = (int)(DBL_MANT_DIG * M_LN2 / M_LN10) + 2 }; String FormatDoubleDigits(double d, int raw_digits, int flags, int& exponent) { if(IsNull(d)) { exponent = Null; return Null; } d = fabs(normalize(d, exponent)); if(IsNull(exponent)) return "0"; int digits = raw_digits + (flags & FD_REL ? 0 : exponent + 1); int count = minmax(digits, 1, DBL_DIGITS - 2); Buffer buffer(max(digits, 0) + 10); char *p = buffer; if(count == 0) d /= 10; else { static double powtbl[] = { 1e0, 1e1, 1e2, 1e3, 1e4 }; int part1 = min(count, 5); unsigned i = (unsigned)(d * powtbl[part1 - 1]); p = PutDigits(p, i, 0); d = double((long double)d * (long double)powtbl[part1 - 1] - i); count -= part1; while(count >= 4) { i = minmax(0, (unsigned)(d * 10000), 9999); p = PutDigits(p, i, 4); d = double((long double)d * (long double)10000 - i); count -= 4; } if(count > 0) { i = (unsigned)(d * powtbl[count]); p = PutDigits(p, i, count); d = d * powtbl[count] - i; } } if(p - ~buffer < DBL_DIGITS && d >= 0.5) { // round while(p > ~buffer && p[-1] == '9') p--; if(p == ~buffer) { *p++ = '1'; exponent++; if(!(flags & FD_REL)) digits++; } else p[-1]++; } if(flags & FD_ZERO) { char *e = p; while(e > ~buffer && e[-1] == '0') e--; if(e == buffer) exponent = Null; e = ~buffer + digits; while(p < e) *p++ = '0'; } else { while(p > ~buffer && p[-1] == '0') p--; if(p == ~buffer) { exponent = Null; *p++ = '0'; } } return String(~buffer, (int)(p - ~buffer)); } String FormatDouble(double d, int digits, int flags, int pad_exp) { if(IsNull(d)) return Null; double ad = fabs(d); bool is_exp = (flags & FD_EXP); if(!(flags & FD_FIX)) { is_exp = ad && (ad <= 1e-15 || ad >= 1e15); if(flags & FD_REL) { double bd = ipow10(2 * digits); if(ad && (ad * bd <= 1 || ad >= bd)) is_exp = true; } } if(is_exp) return FormatDoubleExp(d, digits, flags, pad_exp); else return FormatDoubleFix(d, digits, flags); } String FormatDoubleFix(double d, int digits, int flags) { if(IsNull(d)) return Null; int exp; String dig = FormatDoubleDigits(d, digits, flags, exp); if(flags & FD_REL) digits = max(0, digits - Nvl(exp, 0) - 1); String out; if(flags & FD_SIGN || d < 0 && !IsNull(exp)) out.Cat(d >= 0 ? '+' : '-'); if(IsNull(exp) || exp < -digits) { out.Cat('0'); if((flags & FD_ZERO) && digits) { out.Cat('.'); out.Cat('0', digits); } } else if(exp < 0) { out.Cat("0."); out.Cat('0', -1 - exp); int fill = digits + exp + 1; if(!(flags & FD_ZERO) || dig.GetLength() >= fill) out.Cat(dig, min(fill, dig.GetLength())); else { out.Cat(dig); out.Cat('0', fill - dig.GetLength()); } } else if(exp < dig.GetLength()) { out.Cat(dig, ++exp); if(digits > 0 && ((flags & FD_ZERO) || dig.GetLength() > exp)) { out.Cat('.'); if(!(flags & FD_ZERO) || dig.GetLength() - exp >= digits) out.Cat(dig.Begin() + exp, min(dig.GetLength() - exp, digits)); else { out.Cat(dig.Begin() + exp, dig.GetLength() - exp); out.Cat('0', digits - (dig.GetLength() - exp)); } } } else { out.Cat(dig); out.Cat('0', exp - dig.GetLength() + 1); if(digits > 0 && (flags & FD_ZERO)) { out.Cat('.'); out.Cat('0', digits); } } return out; } String FormatDoubleExp(double d, int digits, int flags, int fill_exp) { if(IsNull(d)) return Null; int exp; String dig = FormatDoubleDigits(d, digits, flags | FD_REL, exp); exp = Nvl(exp, 0); String out; if(flags & FD_SIGN || d < 0 && !IsNull(exp)) out.Cat(d >= 0 ? '+' : '-'); out.Cat(dig[0]); if(dig.GetLength() > 1) { out.Cat('.'); out.Cat(dig.Begin() + 1, dig.GetLength() - 1); } out.Cat(flags & FD_CAP_E ? 'E' : 'e'); out.Cat(FormatIntDec(exp, fill_exp, '0', flags & FD_SIGN_EXP)); return out; } String FormatDate(Date date, const char *format, int language) { if(IsNull(date)) return Null; if(!format || !*format) return Format(date); return FormatTime(ToTime(date), format, language); } String FormatTime(Time t, const char *s, int language) { if(IsNull(t)) return Null; String result; if(!s || !*s) return Format(t); while(*s) { int q = 0; if(*s == 'M') { while(*s == 'M') { s++; q++; } if(q == 1) result.Cat(Format("%d", t.month)); else result.Cat(Format("%02d", t.month)); } else if(*s == 'D') { while(*s == 'D') { s++; q++; } if(q == 1) result.Cat(Format("%d", t.day)); else result.Cat(Format("%02d", t.day)); } else if(*s == 'Y') { while(*s == 'Y') { s++; q++; } if(q == 1) result.Cat(Format("%d", t.year % 100)); else if(q == 2) result.Cat(Format("%02d", t.year % 100)); else result.Cat(Format("%d", t.year)); } else if(*s == 'h') { while(*s == 'h') { s++; q++; } if(q == 1) result.Cat(Format("%d", t.hour)); else result.Cat(Format("%02d", t.hour)); } else if(*s == 'H') { while(*s == 'H') { s++; q++; } int h = ((t.hour + 11) % 12 + 1); if(q == 1) result.Cat(Format("%d", h)); else result.Cat(Format("%02d", h)); } else if(*s == '<') { s++; while(*s && *s != '/') { if(t.hour <= 12) result.Cat(*s); s++; } if(!*s) break; s++; while(*s && *s != '>') { if(t.hour > 12) result.Cat(*s); s++; } if(!*s) break; s++; } else if(*s == 'm') { while(*s == 'm') { s++; q++; } if(q == 1) result.Cat(Format("%d", t.minute)); else result.Cat(Format("%02d", t.minute)); } else if(*s == 's') { while(*s == 's') { s++; q++; } if(q == 1) result.Cat(Format("%d", t.second)); else result.Cat(Format("%02d", t.second)); } else if(*s == '`' && s[1]) { s++; result.Cat(*s++); } else result.Cat(*s++); } return result; } // New format ---------------------------- struct FormId : Moveable { FormId(String id, int type) : id(id), type(type) {} String id; int type; }; unsigned GetHashValue(const FormId& fid) { return CombineHash(fid.type, GetHashValue(fid.id)); } bool operator==(const FormId& a, const FormId& b) { return a.type == b.type && a.id == b.id; } VectorMap& formatmap() { return Single< VectorMap > (); } void RegisterFormatter(int type, const char *id, Formatter f) { AssertST(); INTERLOCKED { FormId fid(id, type); formatmap().FindAdd(fid, f); formatmap().Find(fid); } } void RegisterValueFormatter(const char *id, Formatter f) { RegisterFormatter(VALUE_V, id, f); } void RegisterNullFormatter(const char *id, Formatter f) { RegisterFormatter(VOID_V, id, f); RegisterFormatter(ERROR_V, id, f); } void RegisterNumberFormatter(const char *id, Formatter f) { RegisterFormatter(DOUBLE_V, id, f); RegisterFormatter(INT64_V, id, f); RegisterFormatter(INT_V, id, f); RegisterFormatter(BOOL_V, id, f); RegisterNullFormatter(id, f); } void RegisterStringFormatter(const char *id, Formatter f) { RegisterFormatter(WSTRING_V, id, f); RegisterFormatter(STRING_V, id, f); RegisterNullFormatter(id, f); } void RegisterDateTimeFormatter(const char *id, Formatter f) { RegisterFormatter(TIME_V, id, f); RegisterFormatter(DATE_V, id, f); RegisterNullFormatter(id, f); } String IntFormatter(const Formatting& f) { StringBuffer q; q.SetLength(1000); q.SetLength(sprintf(q, '%' + f.format + f.id, (int)f.arg)); return q; } String Int64Formatter(const Formatting& f) { StringBuffer q; q.SetLength(1000); q.SetLength(sprintf(q, '%' + f.format + f.id, (int64)f.arg)); return q; } String IntLowerAlphaFormatter(const Formatting& f) { return FormatIntAlpha(f.arg, false); } String IntUpperAlphaFormatter(const Formatting& f) { return FormatIntAlpha(f.arg, true); } String IntLowerRomanFormatter(const Formatting& f) { return FormatIntRoman(f.arg, false); } String IntUpperRomanFormatter(const Formatting& f) { return FormatIntRoman(f.arg, true); } String RealFormatter(const Formatting& f) { if(IsNull(f.arg)) return Null; double value = f.arg; const char *s = f.format; int digits = 6, fill_exp = 0; const char *id = f.id; int flags = (*id++ == 'v' ? FD_REL : 0); if(*s == '+') { flags |= FD_SIGN; s++; } if(IsDigit(*s) || *s == '-' && IsDigit(s[1])) { digits = (int)strtol(s, NULL, 10); while(IsDigit(*++s)) ; } if(*s == '!') { s++; flags |= FD_ZERO; } if(*s == '^') { if(*++s == '+') { flags |= FD_SIGN_EXP; s++; } if(IsDigit(*s)) { fill_exp = (int)strtol(s, NULL, 10); while(IsDigit(*++s)) ; } } bool lng = false; if(*id == 'l') { lng = true; id++; } if(*id == 'e') flags |= FD_EXP; else if(*id == 'f') flags |= FD_FIX; if(lng) return GetLanguageInfo(f.language).FormatDouble(value, digits, flags, fill_exp); else return FormatDouble(value, digits, flags, fill_exp); } String StringFormatter(const Formatting& f) { const String& s = f.arg; String fmt = '%' + f.format + f.id; char h[256]; #ifdef COMPILER_MSC int n = _snprintf(h, 256, fmt, ~s); if(n < 0) #else int n = snprintf(h, 255, fmt, ~s); if(n >= 254) #endif { #ifdef COMPILER_MSC n = _scprintf(fmt, ~s); #endif Buffer ah(n + 1); sprintf(ah, fmt, ~s); return String(ah, n); } return String(h, n); } String FloatFormatter(const Formatting& f) { double d = f.arg; String fmt = '%' + f.format + f.id; char h[256]; #ifdef COMPILER_MSC int n = _snprintf(h, 256, fmt, d); if(n < 0) #else int n = snprintf(h, 255, fmt, d); if(n >= 254) #endif { #ifdef COMPILER_MSC n = _scprintf(fmt, d); #endif Buffer ah(n + 1); sprintf(ah, fmt, d); return String(ah, n); } return String(h, n); } String DateFormatter(const Formatting& f) { return GetLanguageInfo(f.language).FormatDate(f.arg); } String TimeFormatter(const Formatting& f) { return GetLanguageInfo(f.language).FormatTime(f.arg); } String SwitchFormatter(const Formatting& f) { const char *s = f.format; int i = f.arg; int o = i; for(;;) { int n = 0; while(IsDigit(*s)) n = 10 * n + *s++ - '0'; if(!*s) return Null; if(*s == '%') { o = i % max(n, 1); s++; } else if(*s == ',' || *s == ':') { if(o == n) { while(*s && *s != ':') s++; if(!*s) return Null; ++s; const char *b = s; while(*s && *s != ';') s++; return String(b, s); } if(*s == ':') while(*s && *s != ';') s++; if(!*s) return Null; s++; } else return s; } return String(); } String StdFormatFormatter(const Formatting& f) { String out = StdFormat(f.arg); if(!IsNull(out)) return out; return f.format; } String MonthFormatter(const Formatting& f) { return MonthName((int)f.arg - 1, f.language); } String MONTHFormatter(const Formatting& f) { return ToUpper(MonthFormatter(f), GetLNGCharset(f.language)); } String monthFormatter(const Formatting& f) { return ToLower(MonthFormatter(f), GetLNGCharset(f.language)); } String MonFormatter(const Formatting& f) { return MonName((int)f.arg - 1, f.language); } String MONFormatter(const Formatting& f) { return ToUpper(MonFormatter(f), GetLNGCharset(f.language)); } String monFormatter(const Formatting& f) { return ToLower(MonFormatter(f), GetLNGCharset(f.language)); } String DayFormatter(const Formatting& f) { return DayName((int)f.arg, f.language); } String DAYFormatter(const Formatting& f) { return ToUpper(DayFormatter(f), GetLNGCharset(f.language)); } String dayFormatter(const Formatting& f) { return ToLower(DayFormatter(f), GetLNGCharset(f.language)); } String DyFormatter(const Formatting& f) { return DyName((int)f.arg, f.language); } String DYFormatter(const Formatting& f) { return ToUpper(DyFormatter(f), GetLNGCharset(f.language)); } String dyFormatter(const Formatting& f) { return ToLower(DyFormatter(f), GetLNGCharset(f.language)); } String twFormatter(const Formatting& f) { int q = f.arg; return Sprintf(*f.format == '0' ? "%02d" : "%d", q ? q % 12 : 12); } String NumberFormatter(const Formatting& f) { int q = f.arg; return AsString(q); } void IntDoubleRegister(int type) { RegisterFormatter(type, "", &NumberFormatter); RegisterFormatter(type, "c", &IntFormatter); RegisterFormatter(type, "d", &IntFormatter); RegisterFormatter(type, "i", &IntFormatter); RegisterFormatter(type, "o", &IntFormatter); RegisterFormatter(type, "x", &IntFormatter); RegisterFormatter(type, "X", &IntFormatter); RegisterFormatter(type, "ld", &IntFormatter); RegisterFormatter(type, "li", &IntFormatter); RegisterFormatter(type, "lo", &IntFormatter); RegisterFormatter(type, "lx", &IntFormatter); RegisterFormatter(type, "lX", &IntFormatter); RegisterFormatter(type, "lld", &Int64Formatter); RegisterFormatter(type, "lli", &Int64Formatter); RegisterFormatter(type, "llo", &Int64Formatter); RegisterFormatter(type, "llx", &Int64Formatter); RegisterFormatter(type, "llX", &Int64Formatter); RegisterFormatter(type, "e", &FloatFormatter); RegisterFormatter(type, "E", &FloatFormatter); RegisterFormatter(type, "f", &FloatFormatter); RegisterFormatter(type, "g", &FloatFormatter); RegisterFormatter(type, "G", &FloatFormatter); RegisterFormatter(type, "s", &SwitchFormatter); RegisterFormatter(type, "month", &monthFormatter); RegisterFormatter(type, "Month", &MonthFormatter); RegisterFormatter(type, "MONTH", &MONTHFormatter); RegisterFormatter(type, "mon", &monFormatter); RegisterFormatter(type, "Mon", &MonFormatter); RegisterFormatter(type, "MON", &MONFormatter); RegisterFormatter(type, "Day", &DayFormatter); RegisterFormatter(type, "DAY", &DAYFormatter); RegisterFormatter(type, "day", &dayFormatter); RegisterFormatter(type, "Dy", &DyFormatter); RegisterFormatter(type, "DY", &DYFormatter); RegisterFormatter(type, "dy", &dyFormatter); RegisterFormatter(type, "tw", &twFormatter); } static void sRegisterFormatters() { ONCELOCK { IntDoubleRegister(BOOL_V); IntDoubleRegister(INT_V); IntDoubleRegister(INT64_V); IntDoubleRegister(DOUBLE_V); RegisterStringFormatter("s", &StringFormatter); RegisterNullFormatter("", &DateFormatter); RegisterFormatter(DATE_V, "", &DateFormatter); RegisterFormatter(TIME_V, "", &TimeFormatter); RegisterNumberFormatter("n", &RealFormatter); RegisterNumberFormatter("ne", &RealFormatter); RegisterNumberFormatter("nf", &RealFormatter); RegisterNumberFormatter("nl", &RealFormatter); RegisterNumberFormatter("nle", &RealFormatter); RegisterNumberFormatter("nlf", &RealFormatter); RegisterNumberFormatter("v", &RealFormatter); RegisterNumberFormatter("ve", &RealFormatter); RegisterNumberFormatter("vf", &RealFormatter); RegisterNumberFormatter("vl", &RealFormatter); RegisterNumberFormatter("vle", &RealFormatter); RegisterNumberFormatter("vlf", &RealFormatter); // real number formats (n = fixed decimals, v = valid decimals) // ne, ve - force exponential notation; nf, vf - force fixed notation; nl, vl - language-based formatting // Options: [+][[-]][!][^[+]] // + .. always prepend sign // [-] .. number of decimals to print (negative = left of decimal point, default = 6) // ! .. keep insignificant zeros // ^ .. exponent options: // + .. always prepend sign to exponent // exponent padding width RegisterNumberFormatter("a", &IntLowerAlphaFormatter); RegisterNumberFormatter("A", &IntUpperAlphaFormatter); RegisterNumberFormatter("r", &IntLowerRomanFormatter); RegisterNumberFormatter("R", &IntUpperRomanFormatter); RegisterValueFormatter("vt", &StdFormatFormatter); RegisterValueFormatter("", &StdFormatFormatter); } } INITBLOCK { sRegisterFormatters(); } String NFormat0(int language, const char *s, const Value **v, int count) { sRegisterFormatters(); Formatting f; f.language = language; String result; int pos = 0; const char *b; for(;;) { int n = 0; b = s; for(;;) { while(*s && *s != '%') ++s; result.Cat(b, (int)(s - b)); if(*s == '\0') return result; ++s; if(*s == '%') { result.Cat('%'); ++s; } else break; b = s; } f.format.Clear(); f.id.Clear(); b = s; int pad = -1; int padn; String nvl_value = String::GetVoid(); for(;;) { if(*s == '$') { pos = n - 1; b = ++s; n = 0; } else if(*s == ':') { pos = n - 1; b = ++s; n = 0; } else if(*s == '*') { f.format.Cat(b, (int)(s - b)); b = ++s; int i = *v[pos++]; if(*s == ':' || *s == '$' || *s == '<' || *s == '>' || *s == '=') n = i; else f.format.Cat(FormatInt(i)); } else if(*s == '<') { padn = n; pad = ALIGN_LEFT; b = ++s; n = 0; } else if(*s == '>') { padn = n; pad = ALIGN_RIGHT; b = ++s; n = 0; } else if(*s == '=') { padn = n; pad = ALIGN_CENTER; b = ++s; n = 0; } else if(*s == '[') { f.format.Cat(b, (int)(s - b)); s++; b = s; while(*s && *s != ']') s++; f.format.Cat(b, (int)(s - b)); if(*s) s++; b = s; if(!IsAlpha(*s) && *s != '~') break; } else if(*s == '~') { nvl_value = f.format; f.format = Null; b = ++s; } else if(!*s || *s == '`' || IsAlpha(*s)) break; else { ASSERT(*s); if(IsDigit(*s)) n = 10 * n + *s - '0'; else n = 0; s++; } } f.format.Cat(b, (int)(s - b)); b = s; while(IsAlpha(*s)) s++; f.id = String(b, s); #ifndef _DEBUG if(pos < 0 || pos >= count) { result << "!!ARGPOS=" << pos; if(*s == '`') s++; continue; } #endif f.arg = *v[pos++]; String r; if(!nvl_value.IsVoid() && IsNull(f.arg)) r = nvl_value; else { Formatter ft = NULL; #ifdef _DEBUG int fi = formatmap().Find(FormId(f.id, f.arg.GetType())); if(fi < 0) fi = formatmap().Find(FormId(f.id, VALUE_V)); if(fi < 0) { LOG("Missing formatter '" << f.id << "' for type " << f.arg.GetType()); String fmt_types; for(int fm = 0; fm < formatmap().GetCount(); fm++) if(formatmap().GetKey(fm).id == f.id) fmt_types << ' ' << formatmap().GetKey(fm).type; LOG("Formatter available for type(s): " << fmt_types); NEVER(); } ft = formatmap()[fi]; #else for(;;) { int fi = formatmap().Find(FormId(f.id, f.arg.GetType())); if(fi < 0) fi = formatmap().Find(FormId(f.id, VALUE_V)); if(fi >= 0) { ft = formatmap()[fi]; break; } if(f.id.GetLength() == 0) break; f.id.Trim(f.id.GetLength() - 1); s--; } #endif if(ft) r = (*ft)(f); else r << ""; } switch(pad) { case ALIGN_LEFT: ASSERT(padn >= 0); if(r.GetLength() < padn) r.Cat(' ', padn - r.GetLength()); else r.Trim(padn); break; case ALIGN_RIGHT: ASSERT(padn >= 0); if(r.GetLength() < padn) { String fill(' ', padn - r.GetLength()); r = fill + r; } else r.Trim(padn); break; case ALIGN_CENTER: ASSERT(padn >= 0); if(r.GetLength() < padn) { String fill(' ', (padn - r.GetLength()) / 2); r = fill + r; r.Cat(' ', padn - r.GetLength()); } else r.Trim(padn); break; } result.Cat(r); if(*s == '`') s++; } } String NFormat0(const char *s, const Value **v, int count) { return NFormat0(GetCurrentLanguage(), s, v, count); } String NFormat(int language, const char *s, const Vector& v) { Buffer bv(v.GetCount()); for(int i = 0; i < v.GetCount(); i++) bv[i] = &v[i]; return NFormat0(language, s, bv, v.GetCount()); } String NFormat(const char *s, const Vector& v) { return NFormat(GetCurrentLanguage(), s, v); } //$- #define E__NFSetArg(I) arg[I - 1] = &COMBINE(p, I) #define E__NFValue(I) const Value& COMBINE(p, I) #define E__NFBody(I) \ String NFormat(const char *fmt, __List##I(E__NFValue)) \ { \ const Value *arg[I]; \ __List##I(E__NFSetArg); \ return NFormat0(fmt, arg, I); \ } \ String NFormat(int language, const char *fmt, __List##I(E__NFValue)) \ { \ const Value *arg[I]; \ __List##I(E__NFSetArg); \ return NFormat0(language, fmt, arg, I); \ } __Expand10(E__NFBody) #if 1 #define E__FBody(I) \ String Format(const char *fmt, __List##I(E__NFValue)) \ {\ const Value *arg[I]; \ __List##I(E__NFSetArg); \ return NFormat0(fmt, arg, I); \ } \ String Format(int language, const char *fmt, __List##I(E__NFValue)) \ { \ const Value *arg[I]; \ __List##I(E__NFSetArg); \ return NFormat0(language, fmt, arg, I); \ } __Expand20(E__FBody) //$+ String Format(const char *s, const Vector& v) { return NFormat(s, v); } String Format(int language, const char *s, const Vector& v) { return NFormat(language, s, v); } #else String Format(const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); return VFormat(fmt, argptr); } #endif String Sprintf(const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); return VFormat(fmt, argptr); } String DeFormat(const char *text) { StringBuffer x; while(*text) { if(*text == '%') x.Cat('%'); x.Cat(*text++); } return x; } END_UPP_NAMESPACE