#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
/// <summary>
/// Determines whether the specified value is of numeric type.
/// </summary>
/// <param name="o">The object to check.</param>
/// <returns>
/// <c>true</c> if o is a numeric type; otherwise, <c>false</c>.
/// </returns>
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
/// <summary>
/// Determines whether the specified value is positive.
/// </summary>
/// <param name="Value">The value.</param>
/// <param name="ZeroIsPositive">if set to <c>true</c> treats 0 as positive.</param>
/// <returns>
/// <c>true</c> if the specified value is positive; otherwise, <c>false</c>.
/// </returns>
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
/// <summary>
/// Converts the specified values boxed type to its correpsonding unsigned
/// type.
/// </summary>
/// <param name="Value">The value.</param>
/// <returns>A boxed numeric object whos type is unsigned.</returns>
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
/// <summary>
/// Converts the specified values boxed type to its correpsonding integer
/// type.
/// </summary>
/// <param name="Value">The value.</param>
/// <returns>A boxed numeric object whos type is an integer type.</returns>
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
/// <summary>
/// Replaces the string representations of meta chars with their corresponding
/// character values.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A string with all string meta chars are replaced</returns>
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
}
}