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); }
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 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); } }
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); }
/* *----------------------------------------------------------------------------- * * 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); }
/// <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); } }