internal static int FormatNumber(Interp interp, char type, TclObject src, byte[] resultBytes, int cursor)
        {
            if (type == 'd')
            {
                double dvalue                 = TclDouble.get(interp, src);
                System.IO.MemoryStream ms     = new System.IO.MemoryStream(resultBytes, cursor, 8);
                System.IO.BinaryWriter writer = new System.IO.BinaryWriter(ms);
                writer.Write(dvalue);
                cursor += 8;
                writer.Close();
                ms.Close();
            }
            else if (type == 'f')
            {
                float fvalue = (float)TclDouble.get(interp, src);
                System.IO.MemoryStream ms     = new System.IO.MemoryStream(resultBytes, cursor, 4);
                System.IO.BinaryWriter writer = new System.IO.BinaryWriter(ms);
                writer.Write(fvalue);
                cursor += 4;
                writer.Close();
                ms.Close();
            }
            else
            {
                int value = TclInteger.get(interp, src);

                if (type == 'c')
                {
                    resultBytes[cursor++] = (byte)value;
                }
                else if (type == 's')
                {
                    resultBytes[cursor++] = (byte)value;
                    resultBytes[cursor++] = (byte)(value >> 8);
                }
                else if (type == 'S')
                {
                    resultBytes[cursor++] = (byte)(value >> 8);
                    resultBytes[cursor++] = (byte)value;
                }
                else if (type == 'i')
                {
                    resultBytes[cursor++] = (byte)value;
                    resultBytes[cursor++] = (byte)(value >> 8);
                    resultBytes[cursor++] = (byte)(value >> 16);
                    resultBytes[cursor++] = (byte)(value >> 24);
                }
                else if (type == 'I')
                {
                    resultBytes[cursor++] = (byte)(value >> 24);
                    resultBytes[cursor++] = (byte)(value >> 16);
                    resultBytes[cursor++] = (byte)(value >> 8);
                    resultBytes[cursor++] = (byte)value;
                }
            }
            return(cursor);
        }
        private static TclObject ScanNumber(byte[] src, int pos, int type)
        // Format character from "binary scan"
        {
            switch (type)
            {
            case 'c':
            {
                return(TclInteger.newInstance((sbyte)src[pos]));
            }

            case 's':
            {
                short value = (short)((src[pos] & 0xff) + ((src[pos + 1] & 0xff) << 8));
                return(TclInteger.newInstance((int)value));
            }

            case 'S':
            {
                short value = (short)((src[pos + 1] & 0xff) + ((src[pos] & 0xff) << 8));
                return(TclInteger.newInstance((int)value));
            }

            case 'i':
            {
                int value = (src[pos] & 0xff) + ((src[pos + 1] & 0xff) << 8) + ((src[pos + 2] & 0xff) << 16) + ((src[pos + 3] & 0xff) << 24);
                return(TclInteger.newInstance(value));
            }

            case 'I':
            {
                int value = (src[pos + 3] & 0xff) + ((src[pos + 2] & 0xff) << 8) + ((src[pos + 1] & 0xff) << 16) + ((src[pos] & 0xff) << 24);
                return(TclInteger.newInstance(value));
            }

            case 'f':
            {
                System.IO.MemoryStream ms     = new System.IO.MemoryStream(src, pos, 4, false);
                System.IO.BinaryReader reader = new System.IO.BinaryReader(ms);
                double fvalue = reader.ReadSingle();
                reader.Close();
                ms.Close();
                return(TclDouble.newInstance(fvalue));
            }

            case 'd':
            {
                System.IO.MemoryStream ms     = new System.IO.MemoryStream(src, pos, 8, false);
                System.IO.BinaryReader reader = new System.IO.BinaryReader(ms);
                double dvalue = reader.ReadDouble();
                reader.Close();
                ms.Close();
                return(TclDouble.newInstance(dvalue));
            }
            }
            return(null);
        }
 public static bool Tcl_GetDouble(Interp interp, TclObject to, out double value)
 {
     try
     {
         value = TclDouble.get(interp, to);
         return(false);
     }
     catch
     {
         value = 0;
         return(true);
     }
 }
        public static void  set(TclObject tobj, double d)
        // The new value for the object.
        {
            tobj.invalidateStringRep();
            InternalRep rep = tobj.InternalRep;

            if (rep is TclDouble)
            {
                TclDouble tdouble = (TclDouble)rep;
                tdouble.value = d;
            }
            else
            {
                tobj.InternalRep = new TclDouble(d);
            }
        }
 public static bool Tcl_GetDoubleFromObj(Interp interp, TclObject to, ref double value)
 {
     try
     {
         if (to.ToString() == "NaN")
         {
             value = Double.NaN;
         }
         else
         {
             value = TclDouble.get(interp, to);
         }
         return(false);
     }
     catch { return(true); }
 }
Example #6
0
        /// <summary> This procedure is invoked to process the "scan" Tcl command.
        /// See the user documentation for details on what it does.
        ///
        /// Each iteration of the cmdProc compares the scanArr's current index to
        /// the frmtArr's index.  If the chars are equal then the indicies are
        /// incremented.  If a '%' is found in the frmtArr, the formatSpecifier
        /// is parced from the frmtArr, the corresponding value is extracted from
        /// the scanArr, and that value is set in the Tcl Interp.
        ///
        /// If the chars are not equal, or the conversion fails, the boolean
        /// scanArrDone is set to true, indicating the scanArr is not to be
        /// parced and no new values are to be set.  However the frmtArr is still
        /// parced because of the priority of error messages.  In the C version
        /// of Tcl, bad format specifiers throw errors before incorrect argument
        /// input or other scan errors.  Thus we need to parce the entire frmtArr
        /// to verify correct formating.  This is dumb and inefficient but it is
        /// consistent w/ the current C-version of Tcl.
        /// </summary>

        public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv)
        {
            if (argv.Length < 3)
            {
                throw new TclNumArgsException(interp, 1, argv, "string format ?varName varName ...?");
            }
            ;

            StrtoulResult strul;             // Return value for parcing the scanArr when
            // extracting integers/longs
            StrtodResult strd;;              // Return value for parcing the scanArr when

            // extracting doubles
            char[] scanArr;    // Array containing parce info
            char[] frmtArr;    // Array containing info on how to
            // parse the scanArr
            int  scanIndex;    // Index into the scan array
            int  frmtIndex;    // Index into the frmt array
            int  tempIndex;    // Temporary index holder
            int  argIndex;     // Index into the current arg
            int  width;        // Stores the user specified result width
            int  base_;        // Base of the integer being converted
            int  numUnMatched; // Number of fields actually set.
            int  numMatched;   // Number of fields actually matched.
            int  negateScan;   // Mult by result, set to -1 if true
            int  i;            // Generic variable
            char ch;           // Generic variable
            bool cont;         // Used in loops to indicate when to stop
            bool scanOK;       // Set to false if strtoul/strtod fails
            bool scanArrDone;  // Set to false if strtoul/strtod fails
            bool widthFlag;    // True is width is specified
            bool discardFlag;  // If a "%*" is in the formatString dont

            // write output to arg


            scanArr = argv[1].ToString().ToCharArray();

            frmtArr     = argv[2].ToString().ToCharArray();
            width       = base_ = numMatched = numUnMatched = 0;
            scanIndex   = frmtIndex = 0;
            scanOK      = true;
            scanArrDone = false;
            argIndex    = 3;

            // Skip all (if any) of the white space before getting to a char

            frmtIndex = skipWhiteSpace(frmtArr, frmtIndex);

            // Search through the frmtArr.  If the next char is a '%' parse the
            // next chars and determine the type (if any) of the format specifier.
            // If the scanArr has been fully searched, do nothing but incerment
            // "numUnMatched".  The reason to continue the frmtArr search is for
            // consistency in output.  Previously scan format errors were reported
            // before arg input mismatch, so this maintains the same level of error
            // checking.

            while (frmtIndex < frmtArr.Length)
            {
                discardFlag = widthFlag = false;
                negateScan  = 1;
                cont        = true;

                // Parce the format array and read in the correct value from the
                // scan array.  When the correct value is retrieved, set the
                // variable (from argv) in the interp.

                if (frmtArr[frmtIndex] == '%')
                {
                    frmtIndex++;
                    checkOverFlow(interp, frmtArr, frmtIndex);

                    // Two '%'s in a row, do nothing...

                    if (frmtArr[frmtIndex] == '%')
                    {
                        frmtIndex++;
                        scanIndex++;
                        continue;
                    }

                    // Check for a discard field flag

                    if (frmtArr[frmtIndex] == '*')
                    {
                        discardFlag = true;
                        frmtIndex++;
                        checkOverFlow(interp, frmtArr, frmtIndex);
                    }

                    // Check for a width field and accept the 'h', 'l', 'L'
                    // characters, but do nothing with them.
                    //
                    // Note: The order of the width specifier and the other
                    // chars is unordered, so we need to iterate until all
                    // of the specifiers are identified.

                    while (cont)
                    {
                        cont = false;

                        switch (frmtArr[frmtIndex])
                        {
                        case 'h':
                        case 'l':
                        case 'L':  {
                            // Just ignore these values

                            frmtIndex++;
                            cont = true;
                            break;
                        }

                        default:  {
                            if (System.Char.IsDigit(frmtArr[frmtIndex]))
                            {
                                strul     = Util.strtoul(new string(frmtArr), frmtIndex, base_);
                                frmtIndex = strul.index;
                                width     = (int)strul.value;
                                widthFlag = true;
                                cont      = true;
                            }
                        }
                        break;
                        }
                        checkOverFlow(interp, frmtArr, frmtIndex);
                    }

                    // On all conversion specifiers except 'c', move the
                    // scanIndex to the next non-whitespace.

                    ch = frmtArr[frmtIndex];
                    if ((ch != 'c') && (ch != '[') && !scanArrDone)
                    {
                        scanIndex = skipWhiteSpace(scanArr, scanIndex);
                    }
                    if (scanIndex >= scanArr.Length)
                    {
                        scanArrDone = true;
                    }

                    if ((scanIndex < scanArr.Length) && (ch != 'c') && (ch != '['))
                    {
                        // Since strtoul dosent take signed numbers, make the
                        // value positive and store the sign.

                        if (scanArr[scanIndex] == '-')
                        {
                            negateScan = -1;
                            scanIndex++;
                            width--;
                        }
                        else if (scanArr[scanIndex] == '+')
                        {
                            scanIndex++;
                            width--;
                        }

                        // The width+scanIndex might be greater than
                        // the scanArr so we need to re-adjust when this
                        // happens.

                        if (widthFlag && (width + scanIndex > scanArr.Length))
                        {
                            width = scanArr.Length - scanIndex;
                        }
                    }

                    if (scanIndex >= scanArr.Length)
                    {
                        scanArrDone = true;
                    }

                    // Foreach iteration we want strul and strd to be
                    // null since we error check on this case.

                    strul = null;
                    strd  = null;

                    switch (ch)
                    {
                    case 'd':
                    case 'o':
                    case 'x':  {
                        if (!scanArrDone)
                        {
                            if (ch == 'd')
                            {
                                base_ = 10;
                            }
                            else if (ch == 'o')
                            {
                                base_ = 8;
                            }
                            else
                            {
                                base_ = 16;
                            }

                            // If the widthFlag is set then convert only
                            // "width" characters to an ascii representation,
                            // else read in until the end of the integer.  The
                            // scanIndex is moved to the point where we stop
                            // reading in.

                            if (widthFlag)
                            {
                                strul = Util.strtoul(new string(scanArr, 0, width + scanIndex), scanIndex, base_);
                            }
                            else
                            {
                                strul = Util.strtoul(new string(scanArr), scanIndex, base_);
                            }
                            if (strul.errno != 0)
                            {
                                scanOK = false;
                                break;
                            }
                            scanIndex = strul.index;

                            if (!discardFlag)
                            {
                                i = (int)strul.value * negateScan;
                                if (argIndex == argv.Length)
                                {
                                    numMatched--;
                                }
                                else
                                {
                                    testAndSetVar(interp, argv, argIndex++, TclInteger.newInstance(i));
                                }
                            }
                        }
                        break;
                    }

                    case 'c':  {
                        if (widthFlag)
                        {
                            errorCharFieldWidth(interp);
                        }
                        if (!discardFlag && !scanArrDone)
                        {
                            testAndSetVar(interp, argv, argIndex++, TclInteger.newInstance(scanArr[scanIndex++]));
                        }
                        break;
                    }

                    case 's':  {
                        if (!scanArrDone)
                        {
                            // If the widthFlag is set then read only "width"
                            // characters into the string, else read in until
                            // the first whitespace or endArr is found.  The
                            // scanIndex is moved to the point where we stop
                            // reading in.

                            tempIndex = scanIndex;
                            if (!widthFlag)
                            {
                                width = scanArr.Length;
                            }
                            for (i = 0; (scanIndex < scanArr.Length) && (i < width); i++)
                            {
                                ch = scanArr[scanIndex];
                                if ((ch == ' ') || (ch == '\n') || (ch == '\r') || (ch == '\t') || (ch == '\f'))
                                {
                                    break;
                                }
                                scanIndex++;
                            }

                            if (!discardFlag)
                            {
                                string str = new string(scanArr, tempIndex, scanIndex - tempIndex);
                                testAndSetVar(interp, argv, argIndex++, TclString.newInstance(str));
                            }
                        }
                        break;
                    }

                    case 'e':
                    case 'f':
                    case 'g':  {
                        if (!scanArrDone)
                        {
                            // If the wisthFlag is set then read only "width"
                            // characters into the string, else read in until
                            // the first whitespace or endArr is found.  The
                            // scanIndex is moved to the point where we stop
                            // reading in.

                            if (widthFlag)
                            {
                                strd = Util.strtod(new string(scanArr, 0, width + scanIndex), scanIndex);
                            }
                            else
                            {
                                strd = Util.strtod(new string(scanArr), scanIndex);
                            }
                            if (strd.errno != 0)
                            {
                                scanOK = false;
                                break;
                            }
                            scanIndex = strd.index;

                            if (!discardFlag)
                            {
                                double d = strd.value * negateScan;
                                testAndSetVar(interp, argv, argIndex++, TclDouble.newInstance(d));
                            }
                        }
                        break;
                    }

                    case '[':  {
                        bool   charMatchFound = false;
                        bool   charNotMatch   = false;
                        char[] tempArr;
                        int    startIndex;
                        int    endIndex;
                        string unmatched = "unmatched [ in format string";

                        if ((++frmtIndex) >= frmtArr.Length)
                        {
                            throw new TclException(interp, unmatched);
                        }

                        if (frmtArr[frmtIndex] == '^')
                        {
                            charNotMatch = true;
                            frmtIndex   += 2;
                        }
                        else
                        {
                            frmtIndex++;
                        }
                        tempIndex = frmtIndex - 1;

                        if (frmtIndex >= frmtArr.Length)
                        {
                            throw new TclException(interp, unmatched);
                        }

                        // Extract the list of chars for matching.

                        while (frmtArr[frmtIndex] != ']')
                        {
                            if ((++frmtIndex) >= frmtArr.Length)
                            {
                                throw new TclException(interp, unmatched);
                            }
                        }
                        tempArr = new string(frmtArr, tempIndex, frmtIndex - tempIndex).ToCharArray();

                        startIndex = scanIndex;
                        if (charNotMatch)
                        {
                            // Format specifier contained a '^' so interate
                            // until one of the chars in tempArr is found.

                            while (scanOK && !charMatchFound)
                            {
                                if (scanIndex >= scanArr.Length)
                                {
                                    scanOK = false;
                                    break;
                                }
                                for (i = 0; i < tempArr.Length; i++)
                                {
                                    if (tempArr[i] == scanArr[scanIndex])
                                    {
                                        charMatchFound = true;
                                        break;
                                    }
                                }
                                if (widthFlag && ((scanIndex - startIndex) >= width))
                                {
                                    break;
                                }
                                if (!charMatchFound)
                                {
                                    scanIndex++;
                                }
                            }
                        }
                        else
                        {
                            // Iterate until the char in the scanArr is not
                            // in the tempArr.

                            charMatchFound = true;
                            while (scanOK && charMatchFound)
                            {
                                if (scanIndex >= scanArr.Length)
                                {
                                    scanOK = false;
                                    break;
                                }
                                charMatchFound = false;
                                for (i = 0; i < tempArr.Length; i++)
                                {
                                    if (tempArr[i] == scanArr[scanIndex])
                                    {
                                        charMatchFound = true;
                                        break;
                                    }
                                }
                                if (widthFlag && (scanIndex - startIndex) >= width)
                                {
                                    break;
                                }
                                if (charMatchFound)
                                {
                                    scanIndex++;
                                }
                            }
                        }

                        // Indicates nothing was found.

                        endIndex = scanIndex - startIndex;
                        if (endIndex <= 0)
                        {
                            scanOK = false;
                            break;
                        }

                        if (!discardFlag)
                        {
                            string str = new string(scanArr, startIndex, endIndex);
                            testAndSetVar(interp, argv, argIndex++, TclString.newInstance(str));
                        }
                        break;
                    }

                    default:  {
                        errorBadField(interp, ch);
                    }
                    break;
                    }

                    // As long as the scan was successful (scanOK), the format
                    // specifier did not contain a '*' (discardFlag), and
                    // we are not at the end of the scanArr (scanArrDone);
                    // increment the num of vars set in the interp.  Otherwise
                    // increment the number of valid format specifiers.

                    if (scanOK && !discardFlag && !scanArrDone)
                    {
                        numMatched++;
                    }
                    else if ((scanArrDone || !scanOK) && !discardFlag)
                    {
                        numUnMatched++;
                    }
                    frmtIndex++;
                }
                else if (scanIndex < scanArr.Length && scanArr[scanIndex] == frmtArr[frmtIndex])
                {
                    // No '%' was found, but the characters matched

                    scanIndex++;
                    frmtIndex++;
                }
                else
                {
                    // No '%' found and the characters int frmtArr & scanArr
                    // did not match.

                    frmtIndex++;
                }
            }

            // The numMatched is the return value: a count of the num of vars set.
            // While the numUnMatched is the number of formatSpecifiers that
            // passed the parsing stage, but did not match anything in the scanArr.

            if ((numMatched + numUnMatched) != (argv.Length - 3))
            {
                errorDiffVars(interp);
            }
            interp.setResult(TclInteger.newInstance(numMatched));
            return(TCL.CompletionCode.RETURN);
        }
 public static TclObject Tcl_NewDoubleObj(double value)
 {
     return(TclDouble.newInstance(value));
 }
Example #8
0
        private const int GENERIC       = 4; // Floating or exponential,
        // depending on exponent. %g

        /// <summary> This procedure is invoked to process the "format" Tcl command.
        /// See the user documentation for details on what it does.
        ///
        /// The first argument to the cmdProc is the formatString.  The cmdProc
        /// simply copies all the chars into the sbuf until a '%' is found.  At
        /// this point the cmdProc parces the formatString and determines the
        /// format parameters.  The parcing of the formatString can be broken into
        /// six possible phases:
        ///
        /// Phase 0 - Simply Print:            If the next char is %
        /// Phase 1 - XPG3 Position Specifier: If the format [1-n]$ is used
        /// Phase 2 - A Set of Flags:          One or more of the following + -
        /// [space] 0 #
        /// Phase 3 - A Minimun Field Width    Either [integer] or *
        /// Phase 4 - A Precision              If the format .[integer] or .*
        /// Phase 5 - A Length Modifier        If h is present
        /// Phase 6 - A Conversion Character   If one of the following is used
        /// d u i o x X c s f E g G
        ///
        /// Any phase can skip ahead one or more phases, but are not allowed
        /// to move back to previous phases.  Once the parameters are determined
        /// the cmdProc calls one of three private methods that returns a fully
        /// formatted string.  This loop occurs for ever '%' in the formatString.
        /// </summary>

        public TCL.CompletionCode cmdProc(Interp interp, TclObject[] argv)
        {
            System.Text.StringBuilder sbuf; // Stores the return value of the parsed
            // format string
            StrtoulResult stoul;            // A return object to the strtoul call

            char[] format;                  // The format argument is converted to a char
            // array and manipulated as such
            int    phase;                   // Stores the current phase of the parsing
            int    width;                   // Minimum field width
            int    precision;               // Field precision from field specifier
            int    fmtFlags;                // Used to store the format flags ( #,+,etc)
            int    argIndex;                // Index of argument to substitute next.
            int    fmtIndex;                // Used to locate end of the format fields.
            int    endIndex;                // Used to locate end of numerical fields.
            int    intValue;                // Generic storage variable
            long   lngValue;                // Store the TclInteger.get() result
            double dblValue;                // Store the TclDouble.get() result
            bool   noPercent;               // Special case for speed:  indicates there's
            // no field specifier, just a string to copy.
            bool xpgSet;                    // Indicates that xpg has been used for the
            // particular format of the main while loop
            bool gotXpg;                    // True means that an XPG3 %n$-style
            // specifier has been seen.
            bool gotSequential;             // True means that a regular sequential
            // (non-XPG3) conversion specifier has
            // been seen.
            bool useShort;         // Value to be printed is short
            // (half word).
            bool precisionSet;     // Used for f, e, and E conversions
            bool cont;             // Used for phase 3

            if (argv.Length < 2)
            {
                throw new TclNumArgsException(interp, 1, argv, "formatString ?arg arg ...?");
            }

            argIndex = 2;
            fmtIndex = 0;
            gotXpg   = gotSequential = false;

            format = argv[1].ToString().ToCharArray();
            sbuf   = new System.Text.StringBuilder();

            // So, what happens here is to scan the format string one % group
            // at a time, making many individual appends to the StringBuffer.

            while (fmtIndex < format.Length)
            {
                fmtFlags  = phase = width = 0;
                noPercent = true;
                xpgSet    = precisionSet = useShort = false;
                precision = -1;

                // Append all characters to sbuf that are not used for the
                // format specifier.


                if (format[fmtIndex] != '%')
                {
                    int i;
                    for (i = fmtIndex; (i < format.Length); i++)
                    {
                        if (format[i] == '%')
                        {
                            noPercent = false;
                            break;
                        }
                    }
                    sbuf.Append(new string(format, fmtIndex, i - fmtIndex));
                    fmtIndex = i;
                    if (noPercent)
                    {
                        break;
                    }
                }

                // If true, then a % has been indicated but we are at the end
                // of the format string.  Call function to throw exception.

                if (fmtIndex + 1 >= format.Length)
                {
                    errorEndMiddle(interp);
                }

                // Phase 0:
                // Check for %%.  If true then simply write a single '%'
                // to the list.

                checkOverFlow(interp, format, fmtIndex + 1);
                if (format[fmtIndex + 1] == '%')
                {
                    sbuf.Append("%");
                    fmtIndex += 2;
                    // Re-enter the loop

                    continue;
                }

                fmtIndex++;
                checkOverFlow(interp, format, fmtIndex);
                if (System.Char.IsDigit(format[fmtIndex]))
                {
                    // Parce the format array looking for the end of
                    // the number.

                    stoul    = strtoul(format, fmtIndex);
                    intValue = (int)stoul.value;
                    endIndex = stoul.index;

                    if (format[endIndex] == '$')
                    {
                        if (intValue == 0)
                        {
                            errorBadIndex(interp, true);
                        }

                        // Phase 1:
                        // Check for an XPG3-style %n$ specification.
                        // Note: there must not be a mixture of XPG3
                        // specs and non-XPG3 specs in the same format string.

                        if (gotSequential)
                        {
                            errorMixedXPG(interp);
                        }
                        gotXpg   = true;
                        xpgSet   = true;
                        phase    = 2;
                        fmtIndex = endIndex + 1;
                        argIndex = intValue + 1;
                        if ((argIndex < 2) || (argIndex >= argv.Length))
                        {
                            errorBadIndex(interp, gotXpg);
                        }
                    }
                    else
                    {
                        // Phase 3:
                        // Format jumped straight to phase 3; Setting
                        // width field.  Again, verify that all format
                        // specifiers are sequential.

                        if (gotXpg)
                        {
                            errorMixedXPG(interp);
                        }
                        gotSequential = true;
                        if (format[fmtIndex] != '0')
                        {
                            fmtIndex = endIndex;
                            width    = intValue;
                            phase    = 4;
                        }
                    }
                }
                else
                {
                    if (gotXpg)
                    {
                        errorMixedXPG(interp);
                    }
                    gotSequential = true;
                }

                // Phase 2:
                // Setting the Format Flags.  At this point the phase value
                // can be either zero or three.  Anything greater is an
                // incorrect format.

                if (phase < 3)
                {
                    checkOverFlow(interp, format, fmtIndex);
                    char ch = format[fmtIndex];
                    cont = true;
                    while (cont)
                    {
                        switch (ch)
                        {
                        case '-':  {
                            fmtFlags |= LEFT_JUSTIFY;
                            break;
                        }

                        case '#':  {
                            fmtFlags |= ALT_OUTPUT;
                            break;
                        }

                        case '0':  {
                            fmtFlags |= PAD_W_ZERO;
                            break;
                        }

                        case ' ':  {
                            fmtFlags |= SPACE_OR_SIGN;
                            break;
                        }

                        case '+':  {
                            fmtFlags |= SHOW_SIGN;
                            break;
                        }

                        default:  {
                            cont = false;
                        }
                        break;
                        }
                        if (cont)
                        {
                            fmtIndex++;
                            checkOverFlow(interp, format, fmtIndex);
                            ch = format[fmtIndex];
                        }
                    }
                    phase = 3;
                }

                // Phase 3:
                // Setting width field.  Partially redundant code from the
                // Phase 1 if/else statement, but this is made to run fast.

                checkOverFlow(interp, format, fmtIndex);
                if (System.Char.IsDigit(format[fmtIndex]))
                {
                    stoul    = strtoul(format, fmtIndex);
                    width    = (int)stoul.value;
                    fmtIndex = stoul.index;
                }
                else if (format[fmtIndex] == '*')
                {
                    if (argv.Length > argIndex)
                    {
                        width = TclInteger.get(interp, argv[argIndex]);
                        if (width < 0)
                        {
                            width     = -width;
                            fmtFlags |= LEFT_JUSTIFY;
                        }
                        argIndex++;
                        fmtIndex++;
                    }
                }

                // Phase 4:
                // Setting the precision field.

                checkOverFlow(interp, format, fmtIndex);
                if (format[fmtIndex] == '.')
                {
                    fmtIndex++;
                    checkOverFlow(interp, format, fmtIndex);
                    if (System.Char.IsDigit(format[fmtIndex]))
                    {
                        precisionSet = true;

                        stoul     = strtoul(format, fmtIndex);
                        precision = (int)stoul.value;
                        fmtIndex  = stoul.index;
                    }
                    else if (format[fmtIndex] == '*')
                    {
                        if (argv.Length > argIndex)
                        {
                            precisionSet = true;
                            precision    = TclInteger.get(interp, argv[argIndex]);
                            argIndex++;
                            fmtIndex++;
                            checkOverFlow(interp, format, fmtIndex);
                        }
                    }
                    else
                    {
                        // Format field had a '.' without an integer or '*'
                        // preceeding it  (eg  %2.d  or %2.-5d)

                        errorBadField(interp, format[fmtIndex]);
                    }
                }

                // Phase 5:
                // Setting the length modifier.

                if (format[fmtIndex] == 'h')
                {
                    fmtIndex++;
                    checkOverFlow(interp, format, fmtIndex);
                    useShort = true;
                }
                else if (format[fmtIndex] == 'l')
                {
                    fmtIndex++;
                    checkOverFlow(interp, format, fmtIndex);

                    // 'l' is ignored, but should still be processed.
                }

                if ((argIndex < 2) || (argIndex >= argv.Length))
                {
                    errorBadIndex(interp, gotXpg);
                }

                // Phase 6:
                // Setting conversion field.
                // At this point, variables are initialized as follows:
                //
                // width               The specified field width.  This is always
                //                         non-negative.  Zero is the default.
                // precision           The specified precision.  The default
                //                         is -1.
                // argIndex            The argument index from the argv array
                //                         for the appropriate arg.
                // fmtFlags            The format flags are set via bitwise
                //                         operations.  Below are the bits
                //                         and their meanings.

                //     ALT_OUTPUT          set if a '#' is present.
                //     SHOW_SIGN           set if a '+' is present.
                //     SPACE_OR_SIGN       set if a ' ' is present.
                //     LEFT_JUSTIFY        set if a '-' is present or if the
                //                           field width was negative.
                //     PAD_W_ZERO          set if a '0' is present

                string strValue = "";
                char   index    = format[fmtIndex];

                switch (index)
                {
                case 'u':
                case 'd':
                case 'o':
                case 'x':
                case 'X':
                case 'i':  {
                    if (index == 'u')
                    {
                        // Since Java does not provide unsigned ints we need to
                        // make our own.  If the value is negative we need to
                        // clear out all of the leading bits from the 33rd bit
                        // and on.  The result is a long value equal to that
                        // of an unsigned int.

                        lngValue = (long)TclInteger.get(interp, argv[argIndex]);
                        if (lngValue < 0)
                        {
                            lngValue = (lngValue << 32);
                            lngValue = (SupportClass.URShift(lngValue, 32));
                        }
                    }
                    else
                    {
                        fmtFlags |= SIGNED_VALUE;
                        lngValue  = (long)TclInteger.get(interp, argv[argIndex]);
                    }

                    // If the useShort option has been selected, we need
                    // to clear all but the first 16 bits.

                    if (useShort)
                    {
                        lngValue = (lngValue << 48);
                        lngValue = (lngValue >> 48);
                    }

                    if (index == 'o')
                    {
                        sbuf.Append(cvtLngToStr(lngValue, width, precision, fmtFlags, 8, "01234567".ToCharArray(), "0"));
                    }
                    else if (index == 'x')
                    {
                        sbuf.Append(cvtLngToStr(lngValue, width, precision, fmtFlags, 16, "0123456789abcdef".ToCharArray(), "0x"));
                    }
                    else if (index == 'X')
                    {
                        sbuf.Append(cvtLngToStr(lngValue, width, precision, fmtFlags, 16, "0123456789ABCDEF".ToCharArray(), "0X"));
                    }
                    else
                    {
                        sbuf.Append(cvtLngToStr(lngValue, width, precision, fmtFlags, 10, "0123456789".ToCharArray(), ""));
                    }
                    break;
                }

                case 'c':  {
                    intValue = 0;
                    char[] arr = new char[] { (char)TclInteger.get(interp, argv[argIndex]) };
                    strValue = new string(arr);
                    sbuf.Append(cvtStrToStr(strValue, width, precision, fmtFlags));
                    break;
                }

                case 's':  {
                    strValue = argv[argIndex].ToString();
                    sbuf.Append(cvtStrToStr(strValue, width, precision, fmtFlags));
                    break;
                }

                case 'f':  {
                    dblValue = TclDouble.get(interp, argv[argIndex]);
                    sbuf.Append(cvtDblToStr(dblValue, width, precision, fmtFlags, 10, "0123456789".ToCharArray(), "", FLOAT));
                    break;
                }

                case 'e':  {
                    dblValue = TclDouble.get(interp, argv[argIndex]);
                    sbuf.Append(cvtDblToStr(dblValue, width, precision, fmtFlags, 10, "e".ToCharArray(), "", EXP));
                    break;
                }

                case 'E':  {
                    dblValue = TclDouble.get(interp, argv[argIndex]);
                    sbuf.Append(cvtDblToStr(dblValue, width, precision, fmtFlags, 10, "E".ToCharArray(), "", EXP));
                    break;
                }

                case 'g':  {
                    dblValue = TclDouble.get(interp, argv[argIndex]);
                    sbuf.Append(cvtDblToStr(dblValue, width, precision, fmtFlags, 10, "e".ToCharArray(), "", GENERIC));
                    break;
                }

                case 'G':  {
                    dblValue = TclDouble.get(interp, argv[argIndex]);
                    sbuf.Append(cvtDblToStr(dblValue, width, precision, fmtFlags, 10, "E".ToCharArray(), "", GENERIC));
                    break;
                }

                default:  {
                    errorBadField(interp, format[fmtIndex]);
                }
                break;
                }
                fmtIndex++;
                argIndex++;
            }
            interp.setResult(sbuf.ToString());
            return(TCL.CompletionCode.RETURN);
        }
Example #9
0
        /*
         *-----------------------------------------------------------------------------
         *
         * cmdProc --
         *
         *      This procedure is invoked to process the "lsearch" Tcl command.
         *      See the user documentation for details on what it does.
         *
         * Results:
         *      None.
         *
         * Side effects:
         *      See the user documentation.
         *
         *-----------------------------------------------------------------------------
         */

        public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv)
        {
            int       mode         = GLOB;
            int       dataType     = ASCII;
            bool      isIncreasing = true;
            TclObject pattern;
            TclObject list;

            if (objv.Length < 3)
            {
                throw new TclNumArgsException(interp, 1, objv, "?options? list pattern");
            }

            for (int i = 1; i < objv.Length - 2; i++)
            {
                switch (TclIndex.get(interp, objv[i], options, "option", 0))
                {
                case LSEARCH_ASCII:
                    dataType = ASCII;
                    break;

                case LSEARCH_DECREASING:
                    isIncreasing = false;
                    break;

                case LSEARCH_DICTIONARY:
                    dataType = DICTIONARY;
                    break;

                case LSEARCH_EXACT:
                    mode = EXACT;
                    break;

                case LSEARCH_INCREASING:
                    isIncreasing = true;
                    break;

                case LSEARCH_INTEGER:
                    dataType = INTEGER;
                    break;

                case LSEARCH_GLOB:
                    mode = GLOB;
                    break;

                case LSEARCH_REAL:
                    dataType = REAL;
                    break;

                case LSEARCH_REGEXP:
                    mode = REGEXP;
                    break;

                case LSEARCH_SORTED:
                    mode = SORTED;
                    break;
                }
            }

            // Make sure the list argument is a list object and get its length and
            // a pointer to its array of element pointers.

            TclObject[] listv = TclList.getElements(interp, objv[objv.Length - 2]);

            TclObject patObj       = objv[objv.Length - 1];
            string    patternBytes = null;
            int       patInt       = 0;
            double    patDouble    = 0.0;
            int       length       = 0;

            if (mode == EXACT || mode == SORTED)
            {
                switch (dataType)
                {
                case ASCII:
                case DICTIONARY:

                    patternBytes = patObj.ToString();
                    length       = patternBytes.Length;
                    break;

                case INTEGER:
                    patInt = TclInteger.get(interp, patObj);
                    break;

                case REAL:
                    patDouble = TclDouble.get(interp, patObj);
                    break;
                }
            }
            else
            {
                patternBytes = patObj.ToString();
                length       = patternBytes.Length;
            }

            // Set default index value to -1, indicating failure; if we find the
            // item in the course of our search, index will be set to the correct
            // value.

            int index = -1;

            if (mode == SORTED)
            {
                // If the data is sorted, we can do a more intelligent search.
                int match = 0;
                int lower = -1;
                int upper = listv.Length;
                while (lower + 1 != upper)
                {
                    int i = (lower + upper) / 2;
                    switch (dataType)
                    {
                    case ASCII:
                    {
                        string bytes = listv[i].ToString();
                        match = patternBytes.CompareTo(bytes);
                        break;
                    }

                    case DICTIONARY:
                    {
                        string bytes = listv[i].ToString();
                        match = DictionaryCompare(patternBytes, bytes);
                        break;
                    }

                    case INTEGER:
                    {
                        int objInt = TclInteger.get(interp, listv[i]);
                        if (patInt == objInt)
                        {
                            match = 0;
                        }
                        else if (patInt < objInt)
                        {
                            match = -1;
                        }
                        else
                        {
                            match = 1;
                        }
                        break;
                    }

                    case REAL:
                    {
                        double objDouble = TclDouble.get(interp, listv[i]);
                        if (patDouble == objDouble)
                        {
                            match = 0;
                        }
                        else if (patDouble < objDouble)
                        {
                            match = -1;
                        }
                        else
                        {
                            match = 1;
                        }
                        break;
                    }
                    }
                    if (match == 0)
                    {
                        // Normally, binary search is written to stop when it
                        // finds a match.  If there are duplicates of an element in
                        // the list, our first match might not be the first occurance.
                        // Consider:  0 0 0 1 1 1 2 2 2
                        // To maintain consistancy with standard lsearch semantics,
                        // we must find the leftmost occurance of the pattern in the
                        // list.  Thus we don't just stop searching here.  This
                        // variation means that a search always makes log n
                        // comparisons (normal binary search might "get lucky" with
                        // an early comparison).

                        index = i;
                        upper = i;
                    }
                    else if (match > 0)
                    {
                        if (isIncreasing)
                        {
                            lower = i;
                        }
                        else
                        {
                            upper = i;
                        }
                    }
                    else
                    {
                        if (isIncreasing)
                        {
                            upper = i;
                        }
                        else
                        {
                            lower = i;
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < listv.Length; i++)
                {
                    bool match = false;
                    switch (mode)
                    {
                    case SORTED:
                    case EXACT:
                    {
                        switch (dataType)
                        {
                        case ASCII:
                        {
                            string bytes   = listv[i].ToString();
                            int    elemLen = bytes.Length;
                            if (length == elemLen)
                            {
                                match = bytes.Equals(patternBytes);
                            }
                            break;
                        }

                        case DICTIONARY:
                        {
                            string bytes = listv[i].ToString();
                            match = (DictionaryCompare(bytes, patternBytes) == 0);
                            break;
                        }

                        case INTEGER:
                        {
                            int objInt = TclInteger.get(interp, listv[i]);
                            match = (objInt == patInt);
                            break;
                        }

                        case REAL:
                        {
                            double objDouble = TclDouble.get(interp, listv[i]);
                            match = (objDouble == patDouble);
                            break;
                        }
                        }
                        break;
                    }

                    case GLOB:
                    {
                        match = Util.stringMatch(listv[i].ToString(), patternBytes);
                        break;
                    }

                    case REGEXP:
                    {
                        match = Util.regExpMatch(interp, listv[i].ToString(), patObj);
                        break;
                    }
                    }
                    if (match)
                    {
                        index = i;
                        break;
                    }
                }
            }
            interp.setResult(index);
            return(TCL.CompletionCode.RETURN);
        }
Example #10
0
        /// <summary> Compares the order of two items in the array.
        ///
        /// </summary>
        /// <param name="obj1">first item.
        /// </param>
        /// <param name="obj2">second item.
        /// </param>
        /// <returns> 0 if they are equal, 1 if obj1 > obj2, -1 otherwise.
        ///
        /// </returns>
        /// <exception cref=""> TclException if an error occurs during sorting.
        /// </exception>
        private int compare(TclObject obj1, TclObject obj2)
        {
            int index;
            int code = 0;

            if (sortIndex != -1)
            {
                // The "-index" option was specified.  Treat each object as a
                // list, extract the requested element from each list, and
                // compare the elements, not the lists.  The special index "end"
                // is signaled here with a negative index (other than -1).

                TclObject obj;
                if (sortIndex < -1)
                {
                    index = TclList.getLength(sortInterp, obj1) - 1;
                }
                else
                {
                    index = sortIndex;
                }

                obj = TclList.index(sortInterp, obj1, index);
                if (obj == null)
                {
                    throw new TclException(sortInterp, "element " + index + " missing from sublist \"" + obj1 + "\"");
                }
                obj1 = obj;

                if (sortIndex < -1)
                {
                    index = TclList.getLength(sortInterp, obj2) - 1;
                }
                else
                {
                    index = sortIndex;
                }

                obj = TclList.index(sortInterp, obj2, index);
                if (obj == null)
                {
                    throw new TclException(sortInterp, "element " + index + " missing from sublist \"" + obj2 + "\"");
                }
                obj2 = obj;
            }

            switch (sortMode)
            {
            case ASCII:
                // ATK C# CompareTo use option
                // similar to -dictionary but a > A
                code = System.Globalization.CultureInfo.InvariantCulture.CompareInfo.Compare(obj1.ToString(), obj2.ToString(), System.Globalization.CompareOptions.Ordinal);
                // code = obj1.ToString().CompareTo(obj2.ToString());
                break;

            case DICTIONARY:

                code = doDictionary(obj1.ToString(), obj2.ToString());
                break;

            case INTEGER:
                try
                {
                    int int1 = TclInteger.get(sortInterp, obj1);
                    int int2 = TclInteger.get(sortInterp, obj2);

                    if (int1 > int2)
                    {
                        code = 1;
                    }
                    else if (int2 > int1)
                    {
                        code = -1;
                    }
                }
                catch (TclException e1)
                {
                    sortInterp.addErrorInfo("\n    (converting list element from string to integer)");
                    throw e1;
                }
                break;

            case REAL:
                try
                {
                    double f1 = TclDouble.get(sortInterp, obj1);
                    double f2 = TclDouble.get(sortInterp, obj2);

                    if (f1 > f2)
                    {
                        code = 1;
                    }
                    else if (f2 > f1)
                    {
                        code = -1;
                    }
                }
                catch (TclException e2)
                {
                    sortInterp.addErrorInfo("\n    (converting list element from string to real)");
                    throw e2;
                }
                break;

            case COMMAND:
                System.Text.StringBuilder sbuf = new System.Text.StringBuilder(sortCommand);

                Util.appendElement(sortInterp, sbuf, obj1.ToString());

                Util.appendElement(sortInterp, sbuf, obj2.ToString());
                try
                {
                    sortInterp.eval(sbuf.ToString(), 0);
                }
                catch (TclException e3)
                {
                    sortInterp.addErrorInfo("\n    (user-defined comparison command)");
                    throw e3;
                }

                try
                {
                    code = TclInteger.get(sortInterp, sortInterp.getResult());
                }
                catch (TclException e)
                {
                    sortInterp.resetResult();
                    TclException e4 = new TclException(sortInterp, "comparison command returned non-numeric result");
                    throw e4;
                }
                break;


            default:

                throw new TclRuntimeError("Unknown sortMode " + sortMode);
            }

            if (sortIncreasing)
            {
                return(code);
            }
            else
            {
                return(-code);
            }
        }