Example #1
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 #2
0
        /// <summary>----------------------------------------------------------------------
        ///
        /// Tcl_StringObjCmd -> StringCmd.cmdProc
        ///
        /// This procedure is invoked to process the "string" Tcl command.
        /// See the user documentation for details on what it does.
        ///
        /// Results:
        /// None.
        ///
        /// Side effects:
        /// See the user documentation.
        ///
        /// ----------------------------------------------------------------------
        /// </summary>

        public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv)
        {
            if (objv.Length < 2)
            {
                throw new TclNumArgsException(interp, 1, objv, "option arg ?arg ...?");
            }
            int index = TclIndex.get(interp, objv[1], options, "option", 0);

            switch (index)
            {
            case STR_EQUAL:
            case STR_COMPARE:
            {
                if (objv.Length < 4 || objv.Length > 7)
                {
                    throw new TclNumArgsException(interp, 2, objv, "?-nocase? ?-length int? string1 string2");
                }

                bool nocase    = false;
                int  reqlength = -1;
                for (int i = 2; i < objv.Length - 2; i++)
                {
                    string string2 = objv[i].ToString();
                    int    length2 = string2.Length;
                    if ((length2 > 1) && "-nocase".StartsWith(string2))
                    {
                        nocase = true;
                    }
                    else if ((length2 > 1) && "-length".StartsWith(string2))
                    {
                        if (i + 1 >= objv.Length - 2)
                        {
                            throw new TclNumArgsException(interp, 2, objv, "?-nocase? ?-length int? string1 string2");
                        }
                        reqlength = TclInteger.get(interp, objv[++i]);
                    }
                    else
                    {
                        throw new TclException(interp, "bad option \"" + string2 + "\": must be -nocase or -length");
                    }
                }


                string string1 = objv[objv.Length - 2].ToString();

                string string3 = objv[objv.Length - 1].ToString();
                int    length1 = string1.Length;
                int    length3 = string3.Length;

                // This is the min length IN BYTES of the two strings

                int length = (length1 < length3) ? length1 : length3;

                int match;

                if (reqlength == 0)
                {
                    // Anything matches at 0 chars, right?

                    match = 0;
                }
                else if (nocase || ((reqlength > 0) && (reqlength <= length)))
                {
                    // In Java, strings are always encoded in unicode, so we do
                    // not need to worry about individual char lengths

                    // Do the reqlength check again, against 0 as well for
                    // the benfit of nocase

                    if ((reqlength > 0) && (reqlength < length))
                    {
                        length = reqlength;
                    }
                    else if (reqlength < 0)
                    {
                        // The requested length is negative, so we ignore it by
                        // setting it to the longer of the two lengths.

                        reqlength = (length1 > length3) ? length1 : length3;
                    }
                    if (nocase)
                    {
                        string1 = string1.ToLower();
                        string3 = string3.ToLower();
                    }
                    match = System.Globalization.CultureInfo.InvariantCulture.CompareInfo.Compare(string1, 0, length, string3, 0, length, System.Globalization.CompareOptions.Ordinal);
                    // match = string1.Substring(0, (length) - (0)).CompareTo(string3.Substring(0, (length) - (0)));

                    if ((match == 0) && (reqlength > length))
                    {
                        match = length1 - length3;
                    }
                }
                else
                {
                    match = System.Globalization.CultureInfo.InvariantCulture.CompareInfo.Compare(string1, 0, length, string3, 0, length, System.Globalization.CompareOptions.Ordinal);
                    // ATK match = string1.Substring(0, (length) - (0)).CompareTo(string3.Substring(0, (length) - (0)));
                    if (match == 0)
                    {
                        match = length1 - length3;
                    }
                }

                if (index == STR_EQUAL)
                {
                    interp.setResult((match != 0) ? false : true);
                }
                else
                {
                    interp.setResult(((match > 0) ? 1 : (match < 0) ? -1 : 0));
                }
                break;
            }


            case STR_FIRST:
            {
                if (objv.Length < 4 || objv.Length > 5)
                {
                    throw new TclNumArgsException(interp, 2, objv, "subString string ?startIndex?");
                }

                string string1 = objv[2].ToString();

                string string2 = objv[3].ToString();
                int    length2 = string2.Length;

                int start = 0;

                if (objv.Length == 5)
                {
                    // If a startIndex is specified, we will need to fast
                    // forward to that point in the string before we think
                    // about a match.

                    start = Util.getIntForIndex(interp, objv[4], length2 - 1);
                    if (start >= length2)
                    {
                        interp.setResult(-1);
                        return(TCL.CompletionCode.RETURN);
                    }
                }

                if (string1.Length == 0)
                {
                    interp.setResult(-1);
                }
                else
                {
                    interp.setResult(string2.IndexOf(string1, start));
                }
                break;
            }


            case STR_INDEX:
            {
                if (objv.Length != 4)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string charIndex");
                }


                string string1 = objv[2].ToString();
                int    length1 = string1.Length;

                int i = Util.getIntForIndex(interp, objv[3], length1 - 1);

                if ((i >= 0) && (i < length1))
                {
                    interp.setResult(string1.Substring(i, (i + 1) - (i)));
                }
                break;
            }


            case STR_IS:
            {
                if (objv.Length < 4 || objv.Length > 7)
                {
                    throw new TclNumArgsException(interp, 2, objv, "class ?-strict? ?-failindex var? str");
                }
                index = TclIndex.get(interp, objv[2], isOptions, "class", 0);

                bool      strict     = false;
                TclObject failVarObj = null;

                if (objv.Length != 4)
                {
                    for (int i = 3; i < objv.Length - 1; i++)
                    {
                        string string2 = objv[i].ToString();
                        int    length2 = string2.Length;
                        if ((length2 > 1) && "-strict".StartsWith(string2))
                        {
                            strict = true;
                        }
                        else if ((length2 > 1) && "-failindex".StartsWith(string2))
                        {
                            if (i + 1 >= objv.Length - 1)
                            {
                                throw new TclNumArgsException(interp, 3, objv, "?-strict? ?-failindex var? str");
                            }
                            failVarObj = objv[++i];
                        }
                        else
                        {
                            throw new TclException(interp, "bad option \"" + string2 + "\": must be -strict or -failindex");
                        }
                    }
                }

                bool result = true;
                int  failat = 0;

                // We get the objPtr so that we can short-cut for some classes
                // by checking the object type (int and double), but we need
                // the string otherwise, because we don't want any conversion
                // of type occuring (as, for example, Tcl_Get*FromObj would do

                TclObject obj = objv[objv.Length - 1];

                string string1 = obj.ToString();
                int    length1 = string1.Length;
                if (length1 == 0)
                {
                    if (strict)
                    {
                        result = false;
                    }
                }

                switch (index)
                {
                case STR_IS_BOOL:
                case STR_IS_TRUE:
                case STR_IS_FALSE:
                {
                    if (obj.InternalRep is TclBoolean)
                    {
                        if (((index == STR_IS_TRUE) && !TclBoolean.get(interp, obj)) || ((index == STR_IS_FALSE) && TclBoolean.get(interp, obj)))
                        {
                            result = false;
                        }
                    }
                    else
                    {
                        try
                        {
                            bool i = TclBoolean.get(null, obj);
                            if (((index == STR_IS_TRUE) && !i) || ((index == STR_IS_FALSE) && i))
                            {
                                result = false;
                            }
                        }
                        catch (TclException e)
                        {
                            result = false;
                        }
                    }
                    break;
                }

                case STR_IS_DOUBLE:
                {
                    if ((obj.InternalRep is TclDouble) || (obj.InternalRep is TclInteger))
                    {
                        break;
                    }

                    // This is adapted from Tcl_GetDouble
                    //
                    // The danger in this function is that
                    // "12345678901234567890" is an acceptable 'double',
                    // but will later be interp'd as an int by something
                    // like [expr].  Therefore, we check to see if it looks
                    // like an int, and if so we do a range check on it.
                    // If strtoul gets to the end, we know we either
                    // received an acceptable int, or over/underflow

                    if (Expression.looksLikeInt(string1, length1, 0))
                    {
                        char          c      = string1[0];
                        int           signIx = (c == '-' || c == '+') ? 1 : 0;
                        StrtoulResult res    = Util.strtoul(string1, signIx, 0);
                        if (res.index == length1)
                        {
                            if (res.errno == TCL.INTEGER_RANGE)
                            {
                                result = false;
                                failat = -1;
                            }
                            break;
                        }
                    }

                    char         c2      = string1[0];
                    int          signIx2 = (c2 == '-' || c2 == '+') ? 1 : 0;
                    StrtodResult res2    = Util.strtod(string1, signIx2);
                    if (res2.errno == TCL.DOUBLE_RANGE)
                    {
                        // if (errno == ERANGE), then it was an over/underflow
                        // problem, but in this method, we only want to know
                        // yes or no, so bad flow returns 0 (false) and sets
                        // the failVarObj to the string length.

                        result = false;
                        failat = -1;
                    }
                    else if (res2.index == 0)
                    {
                        // In this case, nothing like a number was found

                        result = false;
                        failat = 0;
                    }
                    else
                    {
                        // Go onto SPACE, since we are
                        // allowed trailing whitespace

                        failat = res2.index;
                        for (int i = res2.index; i < length1; i++)
                        {
                            if (!System.Char.IsWhiteSpace(string1[i]))
                            {
                                result = false;
                                break;
                            }
                        }
                    }
                    break;
                }

                case STR_IS_INT:
                {
                    if (obj.InternalRep is TclInteger)
                    {
                        break;
                    }
                    bool isInteger = true;
                    try
                    {
                        TclInteger.get(null, obj);
                    }
                    catch (TclException e)
                    {
                        isInteger = false;
                    }
                    if (isInteger)
                    {
                        break;
                    }

                    char          c      = string1[0];
                    int           signIx = (c == '-' || c == '+') ? 1 : 0;
                    StrtoulResult res    = Util.strtoul(string1, signIx, 0);
                    if (res.errno == TCL.INTEGER_RANGE)
                    {
                        // if (errno == ERANGE), then it was an over/underflow
                        // problem, but in this method, we only want to know
                        // yes or no, so bad flow returns false and sets
                        // the failVarObj to the string length.

                        result = false;
                        failat = -1;
                    }
                    else if (res.index == 0)
                    {
                        // In this case, nothing like a number was found

                        result = false;
                        failat = 0;
                    }
                    else
                    {
                        // Go onto SPACE, since we are
                        // allowed trailing whitespace

                        failat = res.index;
                        for (int i = res.index; i < length1; i++)
                        {
                            if (!System.Char.IsWhiteSpace(string1[i]))
                            {
                                result = false;
                                break;
                            }
                        }
                    }
                    break;
                }

                case STR_IS_WIDE:
                {
                    if (obj.InternalRep is TclLong)
                    {
                        break;
                    }
                    bool isInteger = true;
                    try
                    {
                        TclLong.get(null, obj);
                    }
                    catch (TclException e)
                    {
                        isInteger = false;
                    }
                    if (isInteger)
                    {
                        break;
                    }

                    char          c      = string1[0];
                    int           signIx = (c == '-' || c == '+') ? 1 : 0;
                    StrtoulResult res    = Util.strtoul(string1, signIx, 0);
                    if (res.errno == TCL.INTEGER_RANGE)
                    {
                        // if (errno == ERANGE), then it was an over/underflow
                        // problem, but in this method, we only want to know
                        // yes or no, so bad flow returns false and sets
                        // the failVarObj to the string length.

                        result = false;
                        failat = -1;
                    }
                    else if (res.index == 0)
                    {
                        // In this case, nothing like a number was found

                        result = false;
                        failat = 0;
                    }
                    else
                    {
                        // Go onto SPACE, since we are
                        // allowed trailing whitespace

                        failat = res.index;
                        for (int i = res.index; i < length1; i++)
                        {
                            if (!System.Char.IsWhiteSpace(string1[i]))
                            {
                                result = false;
                                break;
                            }
                        }
                    }
                    break;
                }

                default:
                {
                    for (failat = 0; failat < length1; failat++)
                    {
                        char c = string1[failat];
                        switch (index)
                        {
                        case STR_IS_ASCII:

                            result = c < 0x80;
                            break;

                        case STR_IS_ALNUM:
                            result = System.Char.IsLetterOrDigit(c);
                            break;

                        case STR_IS_ALPHA:
                            result = System.Char.IsLetter(c);
                            break;

                        case STR_IS_DIGIT:
                            result = System.Char.IsDigit(c);
                            break;

                        case STR_IS_GRAPH:
                            result = ((1 << (int)System.Char.GetUnicodeCategory(c)) & PRINT_BITS) != 0 && c != ' ';
                            break;

                        case STR_IS_PRINT:
                            result = ((1 << (int)System.Char.GetUnicodeCategory(c)) & PRINT_BITS) != 0;
                            break;

                        case STR_IS_PUNCT:
                            result = ((1 << (int)System.Char.GetUnicodeCategory(c)) & PUNCT_BITS) != 0;
                            break;

                        case STR_IS_UPPER:
                            result = System.Char.IsUpper(c);
                            break;

                        case STR_IS_SPACE:
                            result = System.Char.IsWhiteSpace(c);
                            break;

                        case STR_IS_CONTROL:
                            result = (System.Char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.Control);
                            break;

                        case STR_IS_LOWER:
                            result = System.Char.IsLower(c);
                            break;

                        case STR_IS_WORD:
                            result = ((1 << (int)System.Char.GetUnicodeCategory(c)) & WORD_BITS) != 0;
                            break;

                        case STR_IS_XDIGIT:
                            result = "0123456789ABCDEFabcdef".IndexOf(c) >= 0;
                            break;

                        default:
                            throw new TclRuntimeError("unimplemented");
                        }
                        if (!result)
                        {
                            break;
                        }
                    }
                }
                break;
                }

                // Only set the failVarObj when we will return 0
                // and we have indicated a valid fail index (>= 0)

                if ((!result) && (failVarObj != null))
                {
                    interp.setVar(failVarObj, TclInteger.newInstance(failat), 0);
                }
                interp.setResult(result);
                break;
            }


            case STR_LAST:
            {
                if (objv.Length < 4 || objv.Length > 5)
                {
                    throw new TclNumArgsException(interp, 2, objv, "subString string ?startIndex?");
                }

                string string1 = objv[2].ToString();

                string string2 = objv[3].ToString();
                int    length2 = string2.Length;

                int start = 0;
                if (objv.Length == 5)
                {
                    // If a startIndex is specified, we will need to fast
                    // forward to that point in the string before we think
                    // about a match.

                    start = Util.getIntForIndex(interp, objv[4], length2 - 1);
                    if (start < 0)
                    {
                        interp.setResult(-1);
                        break;
                    }
                    else if (start < length2)
                    {
                        string2 = string2.Substring(0, (start + 1) - (0));
                    }
                }

                if (string1.Length == 0)
                {
                    interp.setResult(-1);
                }
                else
                {
                    interp.setResult(string2.LastIndexOf(string1));
                }
                break;
            }


            case STR_BYTELENGTH:
                if (objv.Length != 3)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string");
                }

                interp.setResult(Utf8Count(objv[2].ToString()));
                break;


            case STR_LENGTH:
            {
                if (objv.Length != 3)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string");
                }

                interp.setResult(objv[2].ToString().Length);
                break;
            }


            case STR_MAP:
            {
                if (objv.Length < 4 || objv.Length > 5)
                {
                    throw new TclNumArgsException(interp, 2, objv, "?-nocase? charMap string");
                }

                bool nocase = false;
                if (objv.Length == 5)
                {
                    string string2 = objv[2].ToString();
                    int    length2 = string2.Length;
                    if ((length2 > 1) && "-nocase".StartsWith(string2))
                    {
                        nocase = true;
                    }
                    else
                    {
                        throw new TclException(interp, "bad option \"" + string2 + "\": must be -nocase");
                    }
                }

                TclObject[] mapElemv = TclList.getElements(interp, objv[objv.Length - 2]);
                if (mapElemv.Length == 0)
                {
                    // empty charMap, just return whatever string was given

                    interp.setResult(objv[objv.Length - 1]);
                }
                else if ((mapElemv.Length % 2) != 0)
                {
                    // The charMap must be an even number of key/value items

                    throw new TclException(interp, "char map list unbalanced");
                }

                string string1 = objv[objv.Length - 1].ToString();
                string cmpString1;
                if (nocase)
                {
                    cmpString1 = string1.ToLower();
                }
                else
                {
                    cmpString1 = string1;
                }
                int length1 = string1.Length;
                if (length1 == 0)
                {
                    // Empty input string, just stop now

                    break;
                }

                // Precompute pointers to the unicode string and length.
                // This saves us repeated function calls later,
                // significantly speeding up the algorithm.

                string[] mapStrings = new string[mapElemv.Length];
                int[]    mapLens    = new int[mapElemv.Length];
                for (int ix = 0; ix < mapElemv.Length; ix++)
                {
                    mapStrings[ix] = mapElemv[ix].ToString();
                    mapLens[ix]    = mapStrings[ix].Length;
                }
                string[] cmpStrings;
                if (nocase)
                {
                    cmpStrings = new string[mapStrings.Length];
                    for (int ix = 0; ix < mapStrings.Length; ix++)
                    {
                        cmpStrings[ix] = mapStrings[ix].ToLower();
                    }
                }
                else
                {
                    cmpStrings = mapStrings;
                }

                TclObject result = TclString.newInstance("");
                int       p, str1;
                for (p = 0, str1 = 0; str1 < length1; str1++)
                {
                    for (index = 0; index < mapStrings.Length; index += 2)
                    {
                        // Get the key string to match on

                        string string2 = mapStrings[index];
                        int    length2 = mapLens[index];
                        if ((length2 > 0) && (cmpString1.Substring(str1).StartsWith(cmpStrings[index])))
                        {
                            if (p != str1)
                            {
                                // Put the skipped chars onto the result first

                                TclString.append(result, string1.Substring(p, (str1) - (p)));
                                p = str1 + length2;
                            }
                            else
                            {
                                p += length2;
                            }

                            // Adjust len to be full length of matched string

                            str1 = p - 1;

                            // Append the map value to the unicode string

                            TclString.append(result, mapStrings[index + 1]);
                            break;
                        }
                    }
                }

                if (p != str1)
                {
                    // Put the rest of the unmapped chars onto result

                    TclString.append(result, string1.Substring(p, (str1) - (p)));
                }
                interp.setResult(result);
                break;
            }


            case STR_MATCH:
            {
                if (objv.Length < 4 || objv.Length > 5)
                {
                    throw new TclNumArgsException(interp, 2, objv, "?-nocase? pattern string");
                }

                string string1, string2;
                if (objv.Length == 5)
                {
                    string inString = objv[2].ToString();
                    if (!((inString.Length > 1) && "-nocase".StartsWith(inString)))
                    {
                        throw new TclException(interp, "bad option \"" + inString + "\": must be -nocase");
                    }

                    string1 = objv[4].ToString().ToLower();

                    string2 = objv[3].ToString().ToLower();
                }
                else
                {
                    string1 = objv[3].ToString();

                    string2 = objv[2].ToString();
                }

                interp.setResult(Util.stringMatch(string1, string2));
                break;
            }


            case STR_RANGE:
            {
                if (objv.Length != 5)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string first last");
                }


                string string1 = objv[2].ToString();
                int    length1 = string1.Length;

                int first = Util.getIntForIndex(interp, objv[3], length1 - 1);
                if (first < 0)
                {
                    first = 0;
                }
                int last = Util.getIntForIndex(interp, objv[4], length1 - 1);
                if (last >= length1)
                {
                    last = length1 - 1;
                }

                if (first > last)
                {
                    interp.resetResult();
                }
                else
                {
                    interp.setResult(string1.Substring(first, (last + 1) - (first)));
                }
                break;
            }


            case STR_REPEAT:
            {
                if (objv.Length != 4)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string count");
                }

                int count = TclInteger.get(interp, objv[3]);


                string string1 = objv[2].ToString();
                if (string1.Length > 0)
                {
                    TclObject tstr = TclString.newInstance("");
                    for (index = 0; index < count; index++)
                    {
                        TclString.append(tstr, string1);
                    }
                    interp.setResult(tstr);
                }
                break;
            }


            case STR_REPLACE:
            {
                if (objv.Length < 5 || objv.Length > 6)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string first last ?string?");
                }


                string string1 = objv[2].ToString();
                int    length1 = string1.Length - 1;

                int first = Util.getIntForIndex(interp, objv[3], length1);
                int last  = Util.getIntForIndex(interp, objv[4], length1);

                if ((last < first) || (first > length1) || (last < 0))
                {
                    interp.setResult(objv[2]);
                }
                else
                {
                    if (first < 0)
                    {
                        first = 0;
                    }
                    string start = string1.Substring(first);
                    int    ind   = ((last > length1) ? length1 : last) - first + 1;
                    string end;
                    if (ind <= 0)
                    {
                        end = start;
                    }
                    else if (ind >= start.Length)
                    {
                        end = "";
                    }
                    else
                    {
                        end = start.Substring(ind);
                    }

                    TclObject tstr = TclString.newInstance(string1.Substring(0, (first) - (0)));

                    if (objv.Length == 6)
                    {
                        TclString.append(tstr, objv[5]);
                    }
                    if (last < length1)
                    {
                        TclString.append(tstr, end);
                    }

                    interp.setResult(tstr);
                }
                break;
            }


            case STR_TOLOWER:
            case STR_TOUPPER:
            case STR_TOTITLE:
            {
                if (objv.Length < 3 || objv.Length > 5)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string ?first? ?last?");
                }

                string string1 = objv[2].ToString();

                if (objv.Length == 3)
                {
                    if (index == STR_TOLOWER)
                    {
                        interp.setResult(string1.ToLower());
                    }
                    else if (index == STR_TOUPPER)
                    {
                        interp.setResult(string1.ToUpper());
                    }
                    else
                    {
                        interp.setResult(Util.toTitle(string1));
                    }
                }
                else
                {
                    int length1 = string1.Length - 1;
                    int first   = Util.getIntForIndex(interp, objv[3], length1);
                    if (first < 0)
                    {
                        first = 0;
                    }
                    int last = first;
                    if (objv.Length == 5)
                    {
                        last = Util.getIntForIndex(interp, objv[4], length1);
                    }
                    if (last >= length1)
                    {
                        last = length1;
                    }
                    if (last < first)
                    {
                        interp.setResult(objv[2]);
                        break;
                    }

                    string        string2;
                    StringBuilder buf = new StringBuilder();
                    buf.Append(string1.Substring(0, (first) - (0)));
                    if (last + 1 > length1)
                    {
                        string2 = string1.Substring(first);
                    }
                    else
                    {
                        string2 = string1.Substring(first, (last + 1) - (first));
                    }
                    if (index == STR_TOLOWER)
                    {
                        buf.Append(string2.ToLower());
                    }
                    else if (index == STR_TOUPPER)
                    {
                        buf.Append(string2.ToUpper());
                    }
                    else
                    {
                        buf.Append(Util.toTitle(string2));
                    }
                    if (last + 1 <= length1)
                    {
                        buf.Append(string1.Substring(last + 1));
                    }

                    interp.setResult(buf.ToString());
                }
                break;
            }


            case STR_TRIM:
            {
                if (objv.Length == 3)
                {
                    // Case 1: "string trim str" --
                    // Remove leading and trailing white space


                    interp.setResult(objv[2].ToString().Trim());
                }
                else if (objv.Length == 4)
                {
                    // Case 2: "string trim str chars" --
                    // Remove leading and trailing chars in the chars set


                    string tmp = Util.TrimLeft(objv[2].ToString(), objv[3].ToString());

                    interp.setResult(Util.TrimRight(tmp, objv[3].ToString()));
                }
                else
                {
                    // Case 3: Wrong # of args

                    throw new TclNumArgsException(interp, 2, objv, "string ?chars?");
                }
                break;
            }


            case STR_TRIMLEFT:
            {
                if (objv.Length == 3)
                {
                    // Case 1: "string trimleft str" --
                    // Remove leading and trailing white space


                    interp.setResult(Util.TrimLeft(objv[2].ToString()));
                }
                else if (objv.Length == 4)
                {
                    // Case 2: "string trimleft str chars" --
                    // Remove leading and trailing chars in the chars set


                    interp.setResult(Util.TrimLeft(objv[2].ToString(), objv[3].ToString()));
                }
                else
                {
                    // Case 3: Wrong # of args

                    throw new TclNumArgsException(interp, 2, objv, "string ?chars?");
                }
                break;
            }


            case STR_TRIMRIGHT:
            {
                if (objv.Length == 3)
                {
                    // Case 1: "string trimright str" --
                    // Remove leading and trailing white space


                    interp.setResult(Util.TrimRight(objv[2].ToString()));
                }
                else if (objv.Length == 4)
                {
                    // Case 2: "string trimright str chars" --
                    // Remove leading and trailing chars in the chars set


                    interp.setResult(Util.TrimRight(objv[2].ToString(), objv[3].ToString()));
                }
                else
                {
                    // Case 3: Wrong # of args

                    throw new TclNumArgsException(interp, 2, objv, "string ?chars?");
                }
                break;
            }


            case STR_WORDEND:
            {
                if (objv.Length != 4)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string index");
                }


                string string1  = objv[2].ToString();
                char[] strArray = string1.ToCharArray();
                int    cur;
                int    length1 = string1.Length;
                index = Util.getIntForIndex(interp, objv[3], length1 - 1);

                if (index < 0)
                {
                    index = 0;
                }
                if (index >= length1)
                {
                    interp.setResult(length1);
                    return(TCL.CompletionCode.RETURN);
                }
                for (cur = index; cur < length1; cur++)
                {
                    char c = strArray[cur];
                    if (((1 << (int)System.Char.GetUnicodeCategory(c)) & WORD_BITS) == 0)
                    {
                        break;
                    }
                }
                if (cur == index)
                {
                    cur = index + 1;
                }
                interp.setResult(cur);
                break;
            }


            case STR_WORDSTART:
            {
                if (objv.Length != 4)
                {
                    throw new TclNumArgsException(interp, 2, objv, "string index");
                }


                string string1  = objv[2].ToString();
                char[] strArray = string1.ToCharArray();
                int    cur;
                int    length1 = string1.Length;
                index = Util.getIntForIndex(interp, objv[3], length1 - 1);

                if (index > length1)
                {
                    index = length1 - 1;
                }
                if (index < 0)
                {
                    interp.setResult(0);
                    return(TCL.CompletionCode.RETURN);
                }
                for (cur = index; cur >= 0; cur--)
                {
                    char c = strArray[cur];
                    if (((1 << (int)System.Char.GetUnicodeCategory(c)) & WORD_BITS) == 0)
                    {
                        break;
                    }
                }
                if (cur != index)
                {
                    cur += 1;
                }
                interp.setResult(cur);
                break;
            }
            }
            return(TCL.CompletionCode.RETURN);
        }
Example #3
0
        internal static string joinPath(Interp interp, TclObject[] argv, int startIndex, int endIndex)
        {
            System.Text.StringBuilder result = new System.Text.StringBuilder(10);

            switch (JACL.PLATFORM)
            {
            case JACL.PLATFORM_WINDOWS:

                for (int i = startIndex; i < endIndex; i++)
                {
                    string p          = argv[i].ToString().Replace('\\', '/');
                    int    pIndex     = 0;
                    int    pLastIndex = p.Length - 1;

                    if (p.Length == 0)
                    {
                        continue;
                    }

                    System.Text.StringBuilder absBuf = new System.Text.StringBuilder(0);
                    pIndex = getWinAbsPath(p, absBuf);
                    if (pIndex > 0)
                    {
                        // If the path is absolute or volume relative (except those
                        // beginning with '~'), reset the result buffer to the absolute
                        // substring.

                        result = absBuf;
                    }
                    else if (p[0] == '~')
                    {
                        // If the path begins with '~', reset the result buffer to "".

                        result.Length = 0;
                    }
                    else
                    {
                        // This is a relative path.  Remove the ./ from tilde prefixed
                        // elements unless it is the first component.

                        if ((result.Length != 0) && (String.Compare(p, pIndex, "./~", 0, 3) == 0))
                        {
                            pIndex = 2;
                        }

                        // Check to see if we need to append a separator before adding
                        // this relative component.

                        if (result.Length != 0)
                        {
                            char c = result[result.Length - 1];
                            if ((c != '/') && (c != ':'))
                            {
                                result.EnsureCapacity(result.Length + 1);
                                result.Append('/');
                            }
                        }
                    }

                    // Append the element.

                    appendComponent(p, pIndex, pLastIndex, result);
                    pIndex = p.Length;
                }
                return(result.ToString());


            case JACL.PLATFORM_MAC:


                bool needsSep = true;
                for (int i = startIndex; i < endIndex; i++)
                {
                    TclObject[] splitArrayObj = TclList.getElements(interp, splitPath(interp, argv[i].ToString()));

                    if (splitArrayObj.Length == 0)
                    {
                        continue;
                    }

                    // If 1st path element is absolute, reset the result to "" and
                    // append the 1st path element to it.

                    int start = 0;

                    string p = splitArrayObj[0].ToString();
                    if ((p[0] != ':') && (p.IndexOf((System.Char) ':') != -1))
                    {
                        result.Length = 0;
                        result.Append(p);
                        start++;
                        needsSep = false;
                    }

                    // Now append the rest of the path elements, skipping
                    // : unless it is the first element of the path, and
                    // watching out for :: et al. so we don't end up with
                    // too many colons in the result.

                    for (int j = start; j < splitArrayObj.Length; j++)
                    {
                        p = splitArrayObj[j].ToString();

                        if (p.Equals(":"))
                        {
                            if (result.Length != 0)
                            {
                                continue;
                            }
                            else
                            {
                                needsSep = false;
                            }
                        }
                        else
                        {
                            char c = 'o';
                            if (p.Length > 1)
                            {
                                c = p[1];
                            }
                            if (p[0] == ':')
                            {
                                if (!needsSep)
                                {
                                    p = p.Substring(1);
                                }
                            }
                            else
                            {
                                if (needsSep)
                                {
                                    result.Append(':');
                                }
                            }
                            if (c == ':')
                            {
                                needsSep = false;
                            }
                            else
                            {
                                needsSep = true;
                            }
                        }
                        result.Append(p);
                    }
                }
                return(result.ToString());


            default:

                for (int i = startIndex; i < endIndex; i++)
                {
                    string p          = argv[i].ToString();
                    int    pIndex     = 0;
                    int    pLastIndex = p.Length - 1;

                    if (p.Length == 0)
                    {
                        continue;
                    }

                    if (p[pIndex] == '/')
                    {
                        // If the path is absolute (except those beginning with '~'),
                        // reset the result buffer to the absolute substring.

                        while ((pIndex <= pLastIndex) && (p[pIndex] == '/'))
                        {
                            pIndex++;
                        }
                        result.Length = 0;
                        result.Append('/');
                    }
                    else if (p[pIndex] == '~')
                    {
                        // If the path begins with '~', reset the result buffer to "".

                        result.Length = 0;
                    }
                    else
                    {
                        // This is a relative path.  Remove the ./ from tilde prefixed
                        // elements unless it is the first component.

                        if ((result.Length != 0) && (String.Compare(p, pIndex, "./~", 0, 3) == 0))
                        {
                            pIndex += 2;
                        }

                        // Append a separator if needed.

                        if ((result.Length != 0) && (result[result.Length - 1] != '/'))
                        {
                            result.EnsureCapacity(result.Length + 1);
                            result.Append('/');
                        }
                    }

                    // Append the element.

                    appendComponent(p, pIndex, pLastIndex, result);
                    pIndex = p.Length;
                }
                break;
            }
            return(result.ToString());
        }