#region Usings
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
#endregion
namespace AT.MIN
{
public static class Tools
{
#region Public Methods
#region IsNumericType
///
/// Determines whether the specified value is of numeric type.
///
/// The object to check.
///
/// true if o is a numeric type; otherwise, false.
///
public static bool IsNumericType(object o)
{
return (o is byte ||
o is sbyte ||
o is short ||
o is ushort ||
o is int ||
o is uint ||
o is long ||
o is ulong ||
o is float ||
o is double ||
o is decimal);
}
#endregion
#region IsPositive
///
/// Determines whether the specified value is positive.
///
/// The value.
/// if set to true treats 0 as positive.
///
/// true if the specified value is positive; otherwise, false.
///
public static bool IsPositive(object Value, bool ZeroIsPositive)
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.SByte:
return (ZeroIsPositive ? (sbyte)Value >= 0 : (sbyte)Value > 0);
case TypeCode.Int16:
return (ZeroIsPositive ? (short)Value >= 0 : (short)Value > 0);
case TypeCode.Int32:
return (ZeroIsPositive ? (int)Value >= 0 : (int)Value > 0);
case TypeCode.Int64:
return (ZeroIsPositive ? (long)Value >= 0 : (long)Value > 0);
case TypeCode.Single:
return (ZeroIsPositive ? (float)Value >= 0 : (float)Value > 0);
case TypeCode.Double:
return (ZeroIsPositive ? (double)Value >= 0 : (double)Value > 0);
case TypeCode.Decimal:
return (ZeroIsPositive ? (decimal)Value >= 0 : (decimal)Value > 0);
case TypeCode.Byte:
return (ZeroIsPositive ? true : (byte)Value > 0);
case TypeCode.UInt16:
return (ZeroIsPositive ? true : (ushort)Value > 0);
case TypeCode.UInt32:
return (ZeroIsPositive ? true : (uint)Value > 0);
case TypeCode.UInt64:
return (ZeroIsPositive ? true : (ulong)Value > 0);
case TypeCode.Char:
return (ZeroIsPositive ? true : (char)Value != '\0');
default:
return false;
}
}
#endregion
#region ToUnsigned
///
/// Converts the specified values boxed type to its correpsonding unsigned
/// type.
///
/// The value.
/// A boxed numeric object whos type is unsigned.
public static object ToUnsigned(object Value)
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.SByte:
return (byte)((sbyte)Value);
case TypeCode.Int16:
return (ushort)((short)Value);
case TypeCode.Int32:
return (uint)((int)Value);
case TypeCode.Int64:
return (ulong)((long)Value);
case TypeCode.Byte:
return Value;
case TypeCode.UInt16:
return Value;
case TypeCode.UInt32:
return Value;
case TypeCode.UInt64:
return Value;
case TypeCode.Single:
return (UInt32)((float)Value);
case TypeCode.Double:
return (ulong)((double)Value);
case TypeCode.Decimal:
return (ulong)((decimal)Value);
default:
return null;
}
}
#endregion
#region ToInteger
///
/// Converts the specified values boxed type to its correpsonding integer
/// type.
///
/// The value.
/// A boxed numeric object whos type is an integer type.
public static object ToInteger(object Value, bool Round)
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.SByte:
return Value;
case TypeCode.Int16:
return Value;
case TypeCode.Int32:
return Value;
case TypeCode.Int64:
return Value;
case TypeCode.Byte:
return Value;
case TypeCode.UInt16:
return Value;
case TypeCode.UInt32:
return Value;
case TypeCode.UInt64:
return Value;
case TypeCode.Single:
return (Round ? (int)Math.Round((float)Value) : (int)((float)Value));
case TypeCode.Double:
return (Round ? (long)Math.Round((double)Value) : (long)((double)Value));
case TypeCode.Decimal:
return (Round ? Math.Round((decimal)Value) : (decimal)Value);
default:
return null;
}
}
#endregion
#region UnboxToLong
public static long UnboxToLong(object Value, bool Round)
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.SByte:
return (long)((sbyte)Value);
case TypeCode.Int16:
return (long)((short)Value);
case TypeCode.Int32:
return (long)((int)Value);
case TypeCode.Int64:
return (long)Value;
case TypeCode.Byte:
return (long)((byte)Value);
case TypeCode.UInt16:
return (long)((ushort)Value);
case TypeCode.UInt32:
return (long)((uint)Value);
case TypeCode.UInt64:
return (long)((ulong)Value);
case TypeCode.Single:
return (Round ? (long)Math.Round((float)Value) : (long)((float)Value));
case TypeCode.Double:
return (Round ? (long)Math.Round((double)Value) : (long)((double)Value));
case TypeCode.Decimal:
return (Round ? (long)Math.Round((decimal)Value) : (long)((decimal)Value));
default:
return 0;
}
}
#endregion
#region ReplaceMetaChars
///
/// Replaces the string representations of meta chars with their corresponding
/// character values.
///
/// The input.
/// A string with all string meta chars are replaced
public static string ReplaceMetaChars(string input)
{
return Regex.Replace(input, @"(\\)(\d{3}|[^\d])?", new MatchEvaluator(ReplaceMetaCharsMatch));
}
private static string ReplaceMetaCharsMatch(Match m)
{
// convert octal quotes (like \040)
if (m.Groups[2].Length == 3)
return Convert.ToChar(Convert.ToByte(m.Groups[2].Value, 8)).ToString();
else
{
// convert all other special meta characters
//TODO: \xhhh hex and possible dec !!
switch (m.Groups[2].Value)
{
case "0": // null
return "\0";
case "a": // alert (beep)
return "\a";
case "b": // BS
return "\b";
case "f": // FF
return "\f";
case "v": // vertical tab
return "\v";
case "r": // CR
return "\r";
case "n": // LF
return "\n";
case "t": // Tab
return "\t";
default:
// if neither an octal quote nor a special meta character
// so just remove the backslash
return m.Groups[2].Value;
}
}
}
#endregion
#region printf
public static void printf(string Format, params object[] Parameters)
{
Console.Write(Tools.sprintf(Format, Parameters));
}
#endregion
#region fprintf
public static void fprintf(TextWriter Destination, string Format, params object[] Parameters)
{
Destination.Write(Tools.sprintf(Format, Parameters));
}
#endregion
#region sprintf
public static string sprintf(string Format, params object[] Parameters)
{
#region Variables
StringBuilder f = new StringBuilder();
Regex r = new Regex(@"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])");
//"%[parameter][flags][width][.precision][length]type"
Match m = null;
string w = String.Empty;
int defaultParamIx = 0;
int paramIx;
object o = null;
bool flagLeft2Right = false;
bool flagAlternate = false;
bool flagPositiveSign = false;
bool flagPositiveSpace = false;
bool flagZeroPadding = false;
bool flagGroupThousands = false;
int fieldLength = 0;
int fieldPrecision = 0;
char shortLongIndicator = '\0';
char formatSpecifier = '\0';
char paddingCharacter = ' ';
#endregion
// find all format parameters in format string
f.Append(Format);
m = r.Match(f.ToString());
while (m.Success)
{
#region parameter index
paramIx = defaultParamIx;
if (m.Groups[1] != null && m.Groups[1].Value.Length > 0)
{
string val = m.Groups[1].Value.Substring(0, m.Groups[1].Value.Length - 1);
paramIx = Convert.ToInt32(val) - 1;
};
#endregion
#region format flags
// extract format flags
flagAlternate = false;
flagLeft2Right = false;
flagPositiveSign = false;
flagPositiveSpace = false;
flagZeroPadding = false;
flagGroupThousands = false;
if (m.Groups[2] != null && m.Groups[2].Value.Length > 0)
{
string flags = m.Groups[2].Value;
flagAlternate = (flags.IndexOf('#') >= 0);
flagLeft2Right = (flags.IndexOf('-') >= 0);
flagPositiveSign = (flags.IndexOf('+') >= 0);
flagPositiveSpace = (flags.IndexOf(' ') >= 0);
flagGroupThousands = (flags.IndexOf('\'') >= 0);
// positive + indicator overrides a
// positive space character
if (flagPositiveSign && flagPositiveSpace)
flagPositiveSpace = false;
}
#endregion
#region field length
// extract field length and
// pading character
paddingCharacter = ' ';
fieldLength = int.MinValue;
if (m.Groups[3] != null && m.Groups[3].Value.Length > 0)
{
fieldLength = Convert.ToInt32(m.Groups[3].Value);
flagZeroPadding = (m.Groups[3].Value[0] == '0');
}
#endregion
if (flagZeroPadding)
paddingCharacter = '0';
// left2right allignment overrides zero padding
if (flagLeft2Right && flagZeroPadding)
{
flagZeroPadding = false;
paddingCharacter = ' ';
}
#region field precision
// extract field precision
fieldPrecision = int.MinValue;
if (m.Groups[4] != null && m.Groups[4].Value.Length > 0)
fieldPrecision = Convert.ToInt32(m.Groups[4].Value);
#endregion
#region short / long indicator
// extract short / long indicator
shortLongIndicator = Char.MinValue;
if (m.Groups[5] != null && m.Groups[5].Value.Length > 0)
shortLongIndicator = m.Groups[5].Value[0];
#endregion
#region format specifier
// extract format
formatSpecifier = Char.MinValue;
if (m.Groups[6] != null && m.Groups[6].Value.Length > 0)
formatSpecifier = m.Groups[6].Value[0];
#endregion
// default precision is 6 digits if none is specified except
if (fieldPrecision == int.MinValue &&
formatSpecifier != 's' &&
formatSpecifier != 'c' &&
Char.ToUpper(formatSpecifier) != 'X' &&
formatSpecifier != 'o')
fieldPrecision = 6;
#region get next value parameter
// get next value parameter and convert value parameter depending on short / long indicator
if (Parameters == null || paramIx >= Parameters.Length)
o = null;
else
{
o = Parameters[paramIx];
if (shortLongIndicator == 'h')
{
if (o is int)
o = (short)((int)o);
else if (o is long)
o = (short)((long)o);
else if (o is uint)
o = (ushort)((uint)o);
else if (o is ulong)
o = (ushort)((ulong)o);
}
else if (shortLongIndicator == 'l')
{
if (o is short)
o = (long)((short)o);
else if (o is int)
o = (long)((int)o);
else if (o is ushort)
o = (ulong)((ushort)o);
else if (o is uint)
o = (ulong)((uint)o);
}
}
#endregion
// convert value parameters to a string depending on the formatSpecifier
w = String.Empty;
switch (formatSpecifier)
{
#region % - character
case '%': // % character
w = "%";
break;
#endregion
#region d - integer
case 'd': // integer
w = FormatNumber((flagGroupThousands ? "n" : "d"), flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region i - integer
case 'i': // integer
goto case 'd';
#endregion
#region o - octal integer
case 'o': // octal integer - no leading zero
w = FormatOct("o", flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region x - hex integer
case 'x': // hex integer - no leading zero
w = FormatHex("x", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region X - hex integer
case 'X': // same as x but with capital hex characters
w = FormatHex("X", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region u - unsigned integer
case 'u': // unsigned integer
w = FormatNumber((flagGroupThousands ? "n" : "d"), flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
false, false,
paddingCharacter, ToUnsigned(o));
defaultParamIx++;
break;
#endregion
#region c - character
case 'c': // character
if (IsNumericType(o))
w = Convert.ToChar(o).ToString();
else if (o is char)
w = ((char)o).ToString();
else if (o is string && ((string)o).Length > 0)
w = ((string)o)[0].ToString();
defaultParamIx++;
break;
#endregion
#region s - string
case 's': // string
string t = "{0" + (fieldLength != int.MinValue ? "," + (flagLeft2Right ? "-" : String.Empty) + fieldLength.ToString() : String.Empty) + ":s}";
w = o.ToString();
if (fieldPrecision >= 0)
w = w.Substring(0, fieldPrecision);
if (fieldLength != int.MinValue)
if (flagLeft2Right)
w = w.PadRight(fieldLength, paddingCharacter);
else
w = w.PadLeft(fieldLength, paddingCharacter);
defaultParamIx++;
break;
#endregion
#region f - double number
case 'f': // double
w = FormatNumber((flagGroupThousands ? "n" : "f"), flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region e - exponent number
case 'e': // double / exponent
w = FormatNumber("e", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region E - exponent number
case 'E': // double / exponent
w = FormatNumber("E", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region g - general number
case 'g': // double / exponent
w = FormatNumber("g", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region G - general number
case 'G': // double / exponent
w = FormatNumber("G", flagAlternate,
fieldLength, fieldPrecision, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, o);
defaultParamIx++;
break;
#endregion
#region p - pointer
case 'p': // pointer
if (o is IntPtr)
w = "0x" + ((IntPtr)o).ToString("x");
defaultParamIx++;
break;
#endregion
#region n - number of processed chars so far
case 'n': // number of characters so far
w = FormatNumber("d", flagAlternate,
fieldLength, int.MinValue, flagLeft2Right,
flagPositiveSign, flagPositiveSpace,
paddingCharacter, m.Index);
break;
#endregion
default:
w = String.Empty;
defaultParamIx++;
break;
}
// replace format parameter with parameter value
// and start searching for the next format parameter
// AFTER the position of the current inserted value
// to prohibit recursive matches if the value also
// includes a format specifier
f.Remove(m.Index, m.Length);
f.Insert(m.Index, w);
m = r.Match(f.ToString(), m.Index + w.Length);
}
return f.ToString();
}
#endregion
#endregion
#region Private Methods
#region FormatOCT
private static string FormatOct(string NativeFormat, bool Alternate,
int FieldLength, int FieldPrecision,
bool Left2Right,
char Padding, object Value)
{
string w = String.Empty;
string lengthFormat = "{0" + (FieldLength != int.MinValue ?
"," + (Left2Right ?
"-" :
String.Empty) + FieldLength.ToString() :
String.Empty) + "}";
if (IsNumericType(Value))
{
w = Convert.ToString(UnboxToLong(Value, true), 8);
if (Left2Right || Padding == ' ')
{
if (Alternate && w != "0")
w = "0" + w;
w = String.Format(lengthFormat, w);
}
else
{
if (FieldLength != int.MinValue)
w = w.PadLeft(FieldLength - (Alternate && w != "0" ? 1 : 0), Padding);
if (Alternate && w != "0")
w = "0" + w;
}
}
return w;
}
#endregion
#region FormatHEX
private static string FormatHex(string NativeFormat, bool Alternate,
int FieldLength, int FieldPrecision,
bool Left2Right,
char Padding, object Value)
{
string w = String.Empty;
string lengthFormat = "{0" + (FieldLength != int.MinValue ?
"," + (Left2Right ?
"-" :
String.Empty) + FieldLength.ToString() :
String.Empty) + "}";
string numberFormat = "{0:" + NativeFormat + (FieldPrecision != int.MinValue ?
FieldPrecision.ToString() :
String.Empty) + "}";
if (IsNumericType(Value))
{
w = String.Format(numberFormat, Value);
if (Left2Right || Padding == ' ')
{
if (Alternate)
w = (NativeFormat == "x" ? "0x" : "0X") + w;
w = String.Format(lengthFormat, w);
}
else
{
if (FieldLength != int.MinValue)
w = w.PadLeft(FieldLength - (Alternate ? 2 : 0), Padding);
if (Alternate)
w = (NativeFormat == "x" ? "0x" : "0X") + w;
}
}
return w;
}
#endregion
#region FormatNumber
private static string FormatNumber(string NativeFormat, bool Alternate,
int FieldLength, int FieldPrecision,
bool Left2Right,
bool PositiveSign, bool PositiveSpace,
char Padding, object Value)
{
string w = String.Empty;
string lengthFormat = "{0" + (FieldLength != int.MinValue ?
"," + (Left2Right ?
"-" :
String.Empty) + FieldLength.ToString() :
String.Empty) + "}";
string numberFormat = "{0:" + NativeFormat + (FieldPrecision != int.MinValue ?
FieldPrecision.ToString() :
"0") + "}";
if (IsNumericType(Value))
{
w = String.Format(numberFormat, Value);
if (Left2Right || Padding == ' ')
{
if (IsPositive(Value, true))
w = (PositiveSign ?
"+" : (PositiveSpace ? " " : String.Empty)) + w;
w = String.Format(lengthFormat, w);
}
else
{
if (w.StartsWith("-"))
w = w.Substring(1);
if (FieldLength != int.MinValue)
w = w.PadLeft(FieldLength - 1, Padding);
if (IsPositive(Value, true))
w = (PositiveSign ?
"+" : (PositiveSpace ?
" " : (FieldLength != int.MinValue ?
Padding.ToString() : String.Empty))) + w;
else
w = "-" + w;
}
}
return w;
}
#endregion
#endregion
}
}