Hello,

I attached two patches and a Java class (which is not new,
but contains so many differences that a patch is bigger than
the complete code).

It contains the following new features:
- Expressions with &&, || or ?: now accept boolean string values.
- No error for [lreplace {} end end].
- lsearch is 8.4 compliant.

Have fun, Krischan
-- 
Christian Krone, SQL Datenbanksysteme GmbH
Mail mailto:[EMAIL PROTECTED]
--- Expression.java.org Fri Mar 10 19:05:01 2000
+++ Expression.java     Mon Aug 14 20:16:00 2000
@@ -564,15 +575,20 @@
                    value.intValue = (value.doubleValue != 0) ? 1 : 0;
                    value.type = ExprValue.INT;
                } else if (value.type == ExprValue.STRING) {
-                   if (interp.noEval == 0) {
-                       IllegalType(interp, ExprValue.STRING, operator);
-                   }
+                   try {
+                       boolean b = Util.getBoolean(null, value.stringValue);
+                       value = new ExprValue(b ? 1 : 0);
+                   } catch (TclException e) {
+                       if (interp.noEval == 0) {
+                           IllegalType(interp, ExprValue.STRING, operator);
+                       }
 
-                   // Must set value.intValue to avoid referencing
-                   // uninitialized memory in the "if" below;  the actual
-                   // value doesn't matter, since it will be ignored.
+                       // Must set value.intValue to avoid referencing
+                       // uninitialized memory in the "if" below;  the actual
+                       // value doesn't matter, since it will be ignored.
                    
-                   value.intValue = 0;
+                       value.intValue = 0;
+                   }
                }
                if (((operator == AND) && (value.intValue == 0))
                        || ((operator == OR) && (value.intValue != 0))) {
@@ -708,7 +724,12 @@
                    IllegalType(interp, value.type, operator);
                }
                if (value2.type == ExprValue.STRING) {
-                   IllegalType(interp, value.type, operator);
+                   try {
+                       boolean b = Util.getBoolean(null, value2.stringValue);
+                       value2 = new ExprValue(b ? 1 : 0);
+                   } catch (TclException e) {
+                       IllegalType(interp, value2.type, operator);
+                   }
                }
                break;
 
--- LreplaceCmd.java.org        Sat Mar 18 00:31:30 2000
+++ LreplaceCmd.java    Mon Aug 14 21:08:50 2000
@@ -30,30 +30,39 @@
            throw new TclNumArgsException(interp, 1, argv, 
                     "list first last ?element element ...?");
         }
-       int size = TclList.getLength(interp, argv[1]);
-       int first;
-       int last;
-
-       first = Util.getIntForIndex(interp, argv[2], size-1);
-       last  = Util.getIntForIndex(interp, argv[3], size-1);
+       int size  = TclList.getLength(interp, argv[1]);
+       int first = Util.getIntForIndex(interp, argv[2], size-1);
+       int last  = Util.getIntForIndex(interp, argv[3], size-1);
+       int numToDelete;
 
        if (first < 0) {
            first = 0;
        }
-       if (first >= size) {
+
+       // Complain if the user asked for a start element that is greater
+       // than the list length. This won't ever trigger for the "end*"
+       // case as that will be properly constrained by getIntForIndex
+       // because we use size-1 (to allow for replacing the last elem).
+
+       if ((first >= size) && (size > 0)) {
            throw new TclException(interp, "list doesn't contain element " +
                    argv[2]);
        }
        if (last >= size) {
            last = size - 1;
        }
+       if (first <= last) {
+           numToDelete = (last - first + 1);
+       } else {
+           numToDelete = 0;
+       }
 
        TclObject list = argv[1];
        list.preserve();
        list = list.takeExclusive();
 
        try {
-           TclList.replace(interp, list, first, last-first+1, argv, 4,
+           TclList.replace(interp, list, first, numToDelete, argv, 4,
                    argv.length-1);
            interp.setResult(list);
        } finally {
/*
 * LsearchCmd.java
 *
 * Copyright (c) 1997 Cornell University.
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * Copyright (c) 2000 Christian Krone.
 *
 * See the file "license.terms" for information on usage and
 * redistribution of this file, and for a DISCLAIMER OF ALL
 * WARRANTIES.
 * 
 * RCS: @(#) $Id: LsearchCmd.java,v 1.1.1.1 1998/10/14 21:09:20 cvsadmin Exp $
 *
 */

package tcl.lang;

/*
 * This class implements the built-in "lsearch" command in Tcl.
 */

class LsearchCmd implements Command {
  
static final private String options[] = {
    "-ascii",
    "-decreasing",
    "-dictionary",
    "-exact",
    "-increasing", 
    "-integer",
    "-glob",
    "-real",
    "-regexp",
    "-sorted"
};
static final int LSEARCH_ASCII          = 0;
static final int LSEARCH_DECREASING     = 1;
static final int LSEARCH_DICTIONARY     = 2;
static final int LSEARCH_EXACT          = 3;
static final int LSEARCH_INCREASING     = 4;
static final int LSEARCH_INTEGER        = 5;
static final int LSEARCH_GLOB           = 6;
static final int LSEARCH_REAL           = 7;
static final int LSEARCH_REGEXP         = 8;
static final int LSEARCH_SORTED         = 9;

static final int ASCII          = 0;
static final int DICTIONARY     = 1;
static final int INTEGER        = 2;
static final int REAL           = 3;

static final int EXACT  = 0;
static final int GLOB   = 1;
static final int REGEXP = 2;
static final int SORTED = 3;

/*
 *-----------------------------------------------------------------------------
 *
 * 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 void
cmdProc(
    Interp interp,                      // Current interpreter. 
    TclObject objv[])                   // Arguments to "lsearch" command.
throws TclException
{
    int mode = GLOB;
    int dataType = ASCII;
    boolean isIncreasing = true;
    TclObject pattern = null;
    TclObject list = null;

    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:         /* -ascii */
                dataType = ASCII;
                break;
            case LSEARCH_DECREASING:    /* -decreasing */
                isIncreasing = false;
                break;
            case LSEARCH_DICTIONARY:    /* -dictionary */
                dataType = DICTIONARY;
                break;
            case LSEARCH_EXACT:         /* -increasing */
                mode = EXACT;
                break;
            case LSEARCH_INCREASING:    /* -increasing */
                isIncreasing = true;
                break;
            case LSEARCH_INTEGER:       /* -integer */
                dataType = INTEGER;
                break;
            case LSEARCH_GLOB:          /* -glob */
                mode = GLOB;
                break;
            case LSEARCH_REAL:          /* -real */
                dataType = REAL;
                break;
            case LSEARCH_REGEXP:        /* -regexp */
                mode = REGEXP;
                break;
            case LSEARCH_SORTED:        /* -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++) {
            boolean 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);
}

/**
 *----------------------------------------------------------------------
 *
 * DictionaryCompare -> dictionaryCompare
 *
 *      This function compares two strings as if they were being used in
 *      an index or card catalog.  The case of alphabetic characters is
 *      ignored, except to break ties.  Thus "B" comes before "b" but
 *      after "a".  Also, integers embedded in the strings compare in
 *      numerical order.  In other words, "x10y" comes after "x9y", not
 *      before it as it would when using strcmp().
 *
 * Results:
 *      A negative result means that the first element comes before the
 *      second, and a positive result means that the second element
 *      should come first.  A result of zero means the two elements
 *      are equal and it doesn't matter which comes first.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

private static int
DictionaryCompare(
    String left, String right)          /* The strings to compare */
{
    char leftArr[] = left.toCharArray();
    char rightArr[] = right.toCharArray();
    char leftChar, rightChar, leftLower, rightLower;
    int lInd = 0;
    int rInd = 0;
    int diff;
    int secondaryDiff = 0;

    while (true) {
        if ((rInd < rightArr.length) && (Character.isDigit(rightArr[rInd])) &&
            (lInd < leftArr.length) && (Character.isDigit(leftArr[lInd]))) {
            // There are decimal numbers embedded in the two
            // strings.  Compare them as numbers, rather than
            // strings.  If one number has more leading zeros than
            // the other, the number with more leading zeros sorts
            // later, but only as a secondary choice.

            int zeros = 0;
            while ((rightArr[rInd] == '0') && (rInd+1 < rightArr.length) &&
                   (Character.isDigit(rightArr[rInd+1]))) {
                rInd++;
                zeros--;
            }
            while ((leftArr[lInd] == '0') && (lInd+1 < leftArr.length) &&
                   (Character.isDigit(leftArr[lInd+1]))) {
                lInd++;
                zeros++;
            }
            if (secondaryDiff == 0) {
                secondaryDiff = zeros;
            }

            // The code below compares the numbers in the two
            // strings without ever converting them to integers.  It
            // does this by first comparing the lengths of the
            // numbers and then comparing the digit values.

            diff = 0;
            while (true) {
                if ((diff == 0) &&
                    (lInd < leftArr.length) && (rInd < rightArr.length)) {
                    diff = leftArr[lInd] - rightArr[rInd];
                }
                rInd++;
                lInd++;
                if (rInd >= rightArr.length ||
                    !Character.isDigit(rightArr[rInd])) {
                    if (lInd < leftArr.length &&
                        Character.isDigit(leftArr[lInd])) {
                        return 1;
                    } else {
                        // The two numbers have the same length. See
                        // if their values are different.

                        if (diff != 0) {
                            return diff;
                        }
                        break;
                    }
                } else if (lInd >= leftArr.length ||
                           !Character.isDigit(leftArr[lInd])) {
                    return -1;
                }
            }
            continue;
        }

        // Convert character to Unicode for comparison purposes.  If either
        // string is at the terminating null, do a byte-wise comparison and
        // bail out immediately.

        if ((lInd < leftArr.length) && (rInd < rightArr.length)) {

            // Convert both chars to lower for the comparison, because
            // dictionary sorts are case insensitve.  Covert to lower, not
            // upper, so chars between Z and a will sort before A (where most
            // other interesting punctuations occur)

            leftChar = leftArr[lInd++];
            rightChar = rightArr[rInd++];
            leftLower = Character.toLowerCase(leftChar);
            rightLower = Character.toLowerCase(rightChar);
        } else if (lInd < leftArr.length) {
            diff = -rightArr[rInd];
            break;
        } else if (rInd < rightArr.length) {
            diff = leftArr[lInd];
            break;
        } else {
            diff = 0;
            break;
        }

        diff = leftLower - rightLower;
        if (diff != 0) {
            return diff;
        } else if (secondaryDiff == 0) {
            if (Character.isUpperCase(leftChar) &&
                Character.isLowerCase(rightChar)) {
                secondaryDiff = -1;
            } else if (Character.isUpperCase(rightChar) &&
                       Character.isLowerCase(leftChar)) {
                secondaryDiff = 1;
            }
        }
    }
    if (diff == 0) {
        diff = secondaryDiff;
    }
    return diff;
}

} // end LsearchCmd

Reply via email to