Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed

#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
    }
}