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