String         FormatIntBase(int i, int base, int width = 0, char lpad = ' ', int sign = 0, bool upper = false);
String         FormatInt(int i);
String         FormatIntDec(int i, int width, char lpad = ' ', bool always_sign = false);
String         FormatIntHex(int i, int width = 8, char lpad = '0');
String         FormatIntHexUpper(int i, int width = 8, char lpad = '0');
String         FormatIntOct(int i, int width = 12, char lpad = '0');
String         FormatIntRoman(int i, bool upper = false);
String         FormatIntAlpha(int i, bool upper = true);
String         Format64(uint64 a);
String         Format64Hex(uint64 a);

#ifdef CPU_64
inline String  FormatIntHex(const void *ptr) { return Format64Hex((int64)(uintptr_t)ptr); }
inline String  FormatHex(const void *ptr)    { return Format64Hex((int64)(uintptr_t)ptr); }
#else
inline String  FormatIntHex(const void *ptr) { return FormatIntHex((int)(uintptr_t)ptr); }
inline String  FormatHex(const void *ptr)    { return FormatIntHex((int)(uintptr_t)ptr); }
#endif

String         FormatInteger(int a);
String         FormatUnsigned(unsigned long a);
String         FormatDouble(double a);
String         FormatBool(bool a);
String         FormatInt64(int64 a);

template<> inline String AsString(const short& a)           { return FormatInteger(a); }
template<> inline String AsString(const unsigned short& a)  { return FormatUnsigned(a); }
template<> inline String AsString(const int& a)             { return FormatInteger(a); }
template<> inline String AsString(const unsigned int& a)    { return FormatUnsigned(a); }
template<> inline String AsString(const long& a)            { return FormatInt64(a); }
template<> inline String AsString(const unsigned long& a)   { return Format64(a); }
template<> inline String AsString(const double& a)          { return FormatDouble(a); }
template<> inline String AsString(const float& a)           { return FormatDouble(a); }
template<> inline String AsString(const int64& a)           { return FormatInt64(a); }
template<> inline String AsString(const uint64& a)          { return Format64(a); }

enum
{
	FD_SIGN     = 0x01,  // always prepend sign (+10)
	FD_REL      = 0x02,  // relative decimal places (valid digits)
	FD_SIGN_EXP = 0x04,  // always prepend sign to exponent (1e+2)
	FD_CAP_E    = 0x08,  // capital E for exponent (1E10)
	FD_ZERO     = 0x10,  // keep trailing zeros (1.25000)
	FD_FIX      = 0x20,  // always use fixed notation (FormatDouble)
	FD_EXP      = 0x40,  // always use exponential notation (FormatDouble)
	FD_COMMA    = 0x80,  // use ',' instead of '.'
	FD_NOTHSEPS = 0x100, // In i18n, do not use thousands separators
};

String         FormatDoubleDigits(double d, int digits, int flags, int& exponent);
String         FormatDouble(double d, int digits, int flags = 0, int fill_exp = 0);
String         FormatDoubleFix(double d, int digits, int flags = 0);
String         FormatDoubleExp(double d, int digits, int flags = 0, int fill_exp = 0);

String         FormatDate(Date date, const char *format, int language = 0);
String         FormatTime(Time time, const char *format, int language = 0);

inline String  IntStr(int i)         { return FormatInt(i); }
inline String  IntStr64(int64 i)     { return FormatInt64(i); }
inline String  DblStr(double d)      { return FormatDouble(d, 10); }

/*
Date        ScanDate(const char *text, const char **endptr, const char *format, int language, Date base_date);
Time        ScanTime(const char *text, const char **endptr, const char *format, int language, Time base_time);
*/

struct Formatting
{
	int    language;
	Value  arg;
	String format;
	String id;
};

typedef String (*Formatter)(const Formatting& fmt);

void RegisterFormatter(int type, const char *id, Formatter f) init_;
void RegisterNullFormatter(const char *id, Formatter f) init_;
void RegisterNumberFormatter(const char *id, Formatter f) init_;
void RegisterStringFormatter(const char *id, Formatter f) init_;
void RegisterDateTimeFormatter(const char *id, Formatter f) init_;
void RegisterValueFormatter(const char *id, Formatter f) init_;

#define E__NFValue(I)  const Value& COMBINE(p, I)
#define E__NFBody(I) \
String NFormat(const char *fmt, __List##I(E__NFValue)); \
String NFormat(int language, const char *fmt, __List##I(E__NFValue));

//$-String NFormat(const char *fmt, Value p1, ...);
//$ String NFormat(int language, const char *fmt, Value p1, ...);
__Expand20(E__NFBody)
//$+

#undef E__NFBody
#undef E__NFValue

String NFormat(const char *s, const Vector<Value>& v);
String NFormat(int language, const char *s, const Vector<Value>& v);

String VFormat(const char *fmt, va_list args);
String Sprintf(const char *fmt, ...);

//$-

#define E__NFValue(I)  const Value& COMBINE(p, I)
#define E__NFBody(I) \
String Format(const char *fmt, __List##I(E__NFValue)); \
String Format(int language, const char *fmt, __List##I(E__NFValue));

__Expand20(E__NFBody)

#undef E__NFBody
#undef E__NFValue

String Format(const char *s, const Vector<Value>& v);
String Format(int language, const char *s, const Vector<Value>& v);

String DeFormat(const char *text);
